// entities.jsx — Detail drawers for Release / Publisher / Label / Agreement
// Opens via custom events:
//   window.dispatchEvent(new CustomEvent('astro-open-release',    {detail:{id}}))
//   window.dispatchEvent(new CustomEvent('astro-open-publisher',  {detail:{id}}))
//   window.dispatchEvent(new CustomEvent('astro-open-label',      {detail:{id}}))
//   window.dispatchEvent(new CustomEvent('astro-open-agreement',  {detail:{id}}))

const { useState: useEnS, useEffect: useEnE } = React;

// ── Shared drawer shell ────────────────────────────────────────
function Drawer({ onClose, accentColor, children, width=560 }) {
  return (
    <>
      <div onClick={onClose} style={{position:'fixed',inset:0,background:'rgba(0,0,0,.34)',zIndex:60}}/>
      <aside style={{position:'fixed',top:0,right:0,bottom:0,width:`min(${width}px,92vw)`,background:'var(--bg)',
        borderLeft:'1px solid var(--rule)',zIndex:61,overflowY:'auto',
        boxShadow:'-20px 0 40px rgba(0,0,0,.18)'}}>
        {children}
      </aside>
    </>
  );
}

function CloseBtn({ onClose, dark }) {
  return (
    <button onClick={onClose} aria-label="Close"
      style={{position:'absolute',top:14,right:14,width:30,height:30,display:'inline-flex',
        alignItems:'center',justifyContent:'center',
        background: dark ? 'rgba(0,0,0,.08)' : 'rgba(255,255,255,.14)',
        border:0,cursor:'pointer',color: dark ? '#0b0b0b' : 'rgba(255,255,255,.92)'}}>
      <span style={{fontSize:18,lineHeight:1}}>×</span>
    </button>
  );
}

function KV({ k, v, mono=true }) {
  return (
    <div>
      <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:3}}>{k}</div>
      <div className={mono?'ff-mono':''} style={{fontSize:13}}>{v}</div>
    </div>
  );
}

const toast = (msg, tone='ok') => window.dispatchEvent(new CustomEvent('astro-toast',{detail:{msg, tone}}));

// ── RELEASE DRAWER ─────────────────────────────────────────────
function ReleaseDrawer({ r, onClose, go }) {
  // Resolve the parent release group + all its editions.
  // Even when r is a single-edition release, we treat it as a group of 1
  // so we get a consistent shape; the UI collapses gracefully when count===1.
  const editions = (window.editionsOfGroup ? window.editionsOfGroup(r.groupId || r.id) : null) || [r];
  const group = (window.releaseGroupOf && window.releaseGroupOf(r)) || {
    title:r.title, artist:r.artist, label:r.label, type:r.type,
    art:r.art, originalDate:r.date, genre:r.genre, marketingLabel:r.label,
  };
  const earliestLive = editions.find(e => e.status === 'live') || editions[0];
  const headerDate = earliestLive ? earliestLive.date : (group.originalDate || r.date);

  // Selected edition state — defaults to the one the user clicked through with.
  const [selEdId, setSelEdId] = React.useState(r.id);
  const sel = editions.find(e => e.id === selEdId) || r;

  const isMulti = editions.length > 1;

  // Tracklist for the SELECTED edition — synthesized from the rich graph if present.
  const recs = (typeof RECORDING_GRAPH !== 'undefined')
    ? RECORDING_GRAPH.filter(x => (x.releaseIds||[]).includes(sel.id) || (x.releaseIds||[]).includes(r.id)).slice(0, sel.tracks)
    : [];
  const tracks = Array.from({length: sel.tracks}, (_,i) => recs[i] || {
    id: `${sel.id}_t${i+1}`, title: `Track ${i+1}`, artist: sel.artist, duration: 180+Math.round(Math.random()*120),
  });

  const dsps = ['Spotify','Apple Music','YouTube Music','Amazon','Tidal','Deezer','Pandora','SoundCloud',
    'Anghami','Boomplay','NetEase','QQ Music','Yandex','VK'];
  const delivered = sel.dsps;

  // Format chip — colored bar for each format type, like the mocks
  const fmtTone = (f) => ({
    Digital:  {bg:'#f4d6c8', fg:'#7a3a1c'},
    CD:       {bg:'#dfe7f4', fg:'#2a4d8f'},
    Vinyl:    {bg:'#e0eef6', fg:'#1c5571'},
    Cassette: {bg:'#f1e5cf', fg:'#6b4a1c'},
    DVD:      {bg:'#ecdcec', fg:'#5c2a8a'},
  })[f] || {bg:'var(--bg-2)', fg:'var(--ink-3)'};
  const FormatChip = ({f}) => {
    const t = fmtTone(f);
    return (
      <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',padding:'3px 8px',
        background:t.bg,color:t.fg,fontWeight:600,minWidth:54,display:'inline-block',textAlign:'center'}}>
        {f || '—'}
      </span>
    );
  };
  const StatusPill = ({s}) => {
    const tone = s === 'live' ? 'ok' : s === 'taken-down' ? 'soft' : 'accent';
    return <Pill tone={tone} dot>{(s||'live').toUpperCase()}</Pill>;
  };
  const fmtUpc = (u) => u ? u.replace(/(\d{1})(\d{4})(\d{4})(\d{1})/, '$1 $2 $3 $4') : '—';
  const fmtDate = (d) => {
    if (!d) return '—';
    const dt = new Date(d);
    return dt.toLocaleDateString('en-US',{month:'short',day:'numeric',year:'2-digit'});
  };
  const fmtPrice = (p) => p != null ? `$${p.toFixed(2)}` : '—';

  return (
    <Drawer onClose={onClose} width={isMulti ? 720 : 620}>
      {/* Hero — album cover */}
      <div style={{position:'relative',padding:'28px 28px 24px',background:group.art,color:'#0b0b0b'}}>
        <CloseBtn onClose={onClose} dark/>
        <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.14em',opacity:.7,marginBottom:14,display:'flex',gap:8,alignItems:'center'}}>
          <span>RELEASE</span>
          {isMulti && <span style={{padding:'2px 6px',background:'rgba(0,0,0,.16)',fontWeight:600,whiteSpace:'nowrap'}}>{editions.length} EDITIONS</span>}
          <Pill tone="soft">{group.type}</Pill>
          {group.genre && <span style={{opacity:.65}}>· {group.genre}</span>}
        </div>
        <div style={{display:'flex',gap:18,alignItems:'flex-end'}}>
          <div style={{width:130,height:130,background:'rgba(0,0,0,.12)',display:'flex',
            alignItems:'flex-end',padding:14,flexShrink:0}}>
            <span className="ff-display" style={{fontSize:28,fontWeight:700,letterSpacing:'-0.04em',
              color:'rgba(0,0,0,.78)',lineHeight:.95}}>{group.title}</span>
          </div>
          <div style={{flex:1,minWidth:0}}>
            <div className="ff-display" style={{fontSize:34,fontWeight:700,letterSpacing:'-0.03em',lineHeight:1.0}}>{group.title}</div>
            <div style={{fontSize:14,marginTop:6,fontWeight:500}}>{group.artist} · {group.marketingLabel || group.label} · {fmtDate(headerDate)}</div>
            <div className="ff-mono" style={{fontSize:11,marginTop:4,opacity:.75}}>
              {sel.tracks} tracks{sel.editionLabel?` · ${sel.editionLabel}`:''}
            </div>
          </div>
        </div>
        <div style={{display:'flex',gap:8,marginTop:18}}>
          <button onClick={()=>toast(`Preview opened for ${group.title}`)}
            style={{display:'flex',alignItems:'center',gap:6,padding:'8px 14px',background:'#0b0b0b',color:group.art,
              border:0,fontSize:12,fontWeight:600,cursor:'pointer'}}>
            <Ic.Play width={11} height={11}/> Preview
          </button>
          <button onClick={()=>{
            // Open the New Edition modal pre-bound to this group
            window.dispatchEvent(new CustomEvent('astro-add-edition', {detail:{groupId: group.id || r.groupId || r.id}}));
          }}
            style={{padding:'8px 14px',background:'transparent',color:'#0b0b0b',
              border:'1px solid rgba(0,0,0,.3)',fontSize:12,fontWeight:500,cursor:'pointer'}}>
            + New edition
          </button>
          <button onClick={()=>toast(`DDEX manifest exported`)}
            style={{padding:'8px 14px',background:'transparent',color:'#0b0b0b',
              border:'1px solid rgba(0,0,0,.3)',fontSize:12,fontWeight:500,cursor:'pointer'}}>
            Export DDEX
          </button>
          {window.DetailDelete && (
            <window.DetailDelete kind="release" record={{ id: group.id || r.groupId || r.id, ...group }} title={group.title} subtitle={`${group.artist} · ${editions.length} edition${editions.length===1?'':'s'}`} onDeleted={() => onClose && onClose()} />
          )}
        </div>
      </div>

      {/* EDITIONS LIST — only when there are multiple */}
      {isMulti && (
        <div style={{padding:'18px 28px',borderBottom:'1px solid var(--rule)'}}>
          <div style={{display:'flex',alignItems:'baseline',justifyContent:'space-between',marginBottom:10}}>
            <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em'}}>EDITIONS · {editions.length}</div>
            <button onClick={()=>window.dispatchEvent(new CustomEvent('astro-add-edition', {detail:{groupId: group.id || r.groupId || r.id}}))}
              className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',padding:'5px 9px',
                background:'transparent',color:'var(--ink-2)',border:'1px solid var(--rule)',cursor:'pointer'}}>+ NEW EDITION</button>
          </div>
          <div style={{display:'grid',gridTemplateColumns:'1fr 78px 124px 88px 70px 56px',gap:10,
            padding:'8px 0',borderTop:'1px solid var(--rule-soft)',borderBottom:'1px solid var(--rule-soft)'}}>
            {['EDITION','FORMAT','UPC','TERRITORY','RELEASED','STATUS'].map(h=>(
              <span key={h} className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em'}}>{h}</span>
            ))}
          </div>
          {editions.map(ed => {
            const active = ed.id === selEdId;
            return (
              <React.Fragment key={ed.id}>
                <div onClick={()=>setSelEdId(active ? null : ed.id)}
                  style={{display:'grid',gridTemplateColumns:'1fr 78px 124px 88px 70px 56px',gap:10,
                    padding:'13px 0',borderBottom: active ? 'none' : '1px solid var(--rule-soft)',
                    cursor:'pointer',alignItems:'center',
                    background: active ? 'var(--bg-2)' : 'transparent',
                    marginLeft: active ? -28 : 0, marginRight: active ? -28 : 0,
                    paddingLeft: active ? 28 : 0, paddingRight: active ? 28 : 0,
                    borderLeft: active ? '3px solid var(--accent)' : '3px solid transparent'}}>
                  <div>
                    <div style={{fontSize:13,fontWeight:500}}>{ed.editionLabel || 'Edition'}</div>
                    {ed.bonusTracks > 0 && <div className="ff-mono" style={{fontSize:10,color:'var(--accent)',marginTop:2}}>+{ed.bonusTracks} bonus tracks</div>}
                  </div>
                  <span><FormatChip f={ed.format}/></span>
                  <span className="ff-mono num" style={{fontSize:11}}>{fmtUpc(ed.upc)}</span>
                  <span className="ff-mono" style={{fontSize:11}}>{ed.territory || 'Worldwide'}</span>
                  <span className="ff-mono" style={{fontSize:11,color:'var(--ink-2)'}}>{fmtDate(ed.date)}</span>
                  <span><StatusPill s={ed.status}/></span>
                </div>
                {/* Inline expanded detail */}
                {active && (
                  <div style={{padding:'14px 28px 16px',borderBottom:'1px solid var(--rule-soft)',
                    background:'var(--bg-2)',marginLeft:-28,marginRight:-28,
                    borderLeft:'3px solid var(--accent)'}}>
                    <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(140px,1fr))',gap:'14px 24px',marginBottom:14}}>
                      {[
                        ['UPC',          fmtUpc(ed.upc)],
                        ['FORMAT',       ed.format || '—'],
                        ['TERRITORY',    ed.territory || 'Worldwide'],
                        ['RELEASE DATE', new Date(ed.date).toLocaleDateString('en-US',{month:'long',day:'numeric',year:'numeric'})],
                        ['RETAIL PRICE', fmtPrice(ed.retailPrice)],
                        ['TRACKS',       String(ed.tracks)],
                      ].map(([k,v])=>(
                        <div key={k}>
                          <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:3}}>{k}</div>
                          <div className="ff-mono" style={{fontSize:12}}>{v}</div>
                        </div>
                      ))}
                    </div>
                    <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'8px 24px',marginBottom:(ed.dspList||[]).length>0?14:0}}>
                      <div>
                        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:3}}>℗ LINE</div>
                        <div className="ff-mono" style={{fontSize:11}}>{ed.pLine || '—'}</div>
                      </div>
                      <div>
                        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:3}}>© LINE</div>
                        <div className="ff-mono" style={{fontSize:11}}>{ed.cLine || '—'}</div>
                      </div>
                    </div>
                    {(ed.dspList||[]).length > 0 && (
                      <div>
                        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:6}}>DISTRIBUTED TO · {ed.dsps}/14</div>
                        <div style={{display:'flex',flexWrap:'wrap',gap:5}}>
                          {ed.dspList.map(d=>(
                            <span key={d} className="ff-mono" style={{fontSize:10,padding:'3px 8px',background:'var(--bg)',border:'1px solid var(--rule)'}}>{d}</span>
                          ))}
                        </div>
                      </div>
                    )}
                    <div style={{display:'flex',gap:6,marginTop:14}}>
                      <button onClick={(e)=>{e.stopPropagation();toast(`Editing ${ed.editionLabel}`)}} className="ff-mono upper"
                        style={{padding:'7px 12px',fontSize:10,letterSpacing:'.1em',background:'var(--bg)',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>EDIT EDITION</button>
                      <button onClick={(e)=>{e.stopPropagation();toast(`Re-delivery queued for ${ed.editionLabel}`)}} className="ff-mono upper"
                        style={{padding:'7px 12px',fontSize:10,letterSpacing:'.1em',background:'var(--bg)',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>RE-DELIVER</button>
                      <button onClick={(e)=>{e.stopPropagation();toast(`Takedown queued for ${ed.editionLabel}`)}} className="ff-mono upper"
                        style={{padding:'7px 12px',fontSize:10,letterSpacing:'.1em',background:'var(--bg)',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>TAKEDOWN</button>
                    </div>
                  </div>
                )}
              </React.Fragment>
            );
          })}
        </div>
      )}

      {/* IDs — only when single-edition (otherwise it's covered by the editions panel) */}
      {!isMulti && (
        <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
          <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:12}}>IDENTIFIERS</div>
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'14px 24px'}}>
            <KV k="UPC"        v={sel.upc}/>
            <KV k="LABEL"      v={sel.label}/>
            <KV k="ARTIST"     v={sel.artist} mono={false}/>
            <KV k="TYPE"       v={sel.type}/>
            <KV k="FORMAT"     v={sel.format || 'Digital'}/>
            <KV k="REL. DATE"  v={sel.date}/>
            <KV k="P-LINE"     v={sel.pLine || `℗ ${(sel.date||'').slice(0,4)} ${sel.label}`}/>
            <KV k="C-LINE"     v={sel.cLine || `© ${(sel.date||'').slice(0,4)} ${sel.label}`}/>
          </div>
        </div>
      )}

      {/* Tracklist — for the SELECTED edition */}
      <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
        <div style={{display:'flex',justifyContent:'space-between',alignItems:'baseline',marginBottom:12}}>
          <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em'}}>TRACKLIST · {sel.tracks}{isMulti?` · ${sel.editionLabel}`:''}</div>
          <button onClick={()=>toast('Tracklist exported as CSV')} className="ff-mono upper"
            style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',background:'transparent',border:0,cursor:'pointer'}}>
            EXPORT CSV
          </button>
        </div>
        <div>
          {tracks.map((t,i)=>{
            const isReal = !!t.isrc;
            return (
              <div key={t.id} onClick={isReal ? ()=>{ onClose(); window.dispatchEvent(new CustomEvent('astro-open-recording',{detail:{id:t.id}})); } : undefined}
                style={{display:'grid',gridTemplateColumns:'24px 1fr 60px 14px',gap:12,
                  padding:'10px 0',borderBottom:'1px solid var(--rule-soft)',alignItems:'center',
                  cursor: isReal ? 'pointer' : 'default'}}
                onMouseEnter={e=>{if(isReal) e.currentTarget.style.background='var(--bg-2)'}}
                onMouseLeave={e=>{if(isReal) e.currentTarget.style.background='transparent'}}>
                <span className="ff-mono num" style={{fontSize:11,color:'var(--ink-3)'}}>{String(i+1).padStart(2,'0')}</span>
                <div style={{minWidth:0}}>
                  <div style={{fontSize:13,fontWeight:500,whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{t.title}</div>
                  {isReal && <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:2}}>{(window.isrcDisplay ? window.isrcDisplay(t.isrc) : t.isrc)}</div>}
                </div>
                <span className="ff-mono num" style={{fontSize:11,color:'var(--ink-3)',textAlign:'right'}}>
                  {Math.floor(t.duration/60)}:{String(t.duration%60).padStart(2,'0')}
                </span>
                {isReal ? <Ic.Right width={12} height={12} style={{color:'var(--ink-3)'}}/> : <span/>}
              </div>
            );
          })}
        </div>
      </div>

      {/* Platform popularity */}
      {(() => {
        const pop = (window.RELEASE_PLATFORM_DETAILS || {})[r.id];
        if (!pop) return null;
        const tiles = [
          {l:'SPOTIFY',  c:'#1ed760', v:pop.spotifyPopularity, max:100, sub:pop.spotifyAlbumType},
          {l:'TIDAL',    c:'#000000', v:pop.tidalPopularity,   max:100, sub:pop.tidalQuality},
          {l:'QOBUZ',    c:'#0070d8', v:pop.qobuzPopularity,   max:100, sub:pop.qobuzHires?'Hi-Res':null},
          {l:'AM',       c:'#fa233b', v:pop.appleMusicScore,   max:100, sub:pop.appleHasAtmos?'Atmos':null},
        ].filter(t => t.v != null);
        if (tiles.length === 0) return null;
        return (
          <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
            <div style={{display:'flex',justifyContent:'space-between',alignItems:'baseline',marginBottom:12}}>
              <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em'}}>PLATFORM POPULARITY</div>
              {pop.lastUpdated && <div className="ff-mono" style={{fontSize:9,color:'var(--ink-4)',letterSpacing:'.05em'}}>updated {pop.lastUpdated}</div>}
            </div>
            <div style={{display:'grid',gridTemplateColumns:`repeat(${tiles.length},1fr)`,gap:0,border:'1px solid var(--rule-soft)'}}>
              {tiles.map((t,i)=>(
                <div key={t.l} style={{padding:'12px 14px',borderRight:i<tiles.length-1?'1px solid var(--rule-soft)':'none'}}>
                  <div style={{display:'flex',alignItems:'center',gap:6,marginBottom:6}}>
                    <span style={{width:7,height:7,background:t.c,display:'inline-block',borderRadius:1}}/>
                    <span className="ff-mono upper" style={{fontSize:9,fontWeight:600,letterSpacing:'.08em'}}>{t.l}</span>
                  </div>
                  <div className="ff-display num" style={{fontSize:22,fontWeight:600,letterSpacing:'-0.03em',lineHeight:1}}>
                    {t.v}<span style={{fontSize:11,color:'var(--ink-3)',fontWeight:400}}>/{t.max}</span>
                  </div>
                  <div style={{height:3,background:'var(--bg-2)',marginTop:6,position:'relative',overflow:'hidden'}}>
                    <div style={{height:'100%',width:`${(t.v/t.max)*100}%`,background:t.c}}/>
                  </div>
                  {t.sub && <div className="ff-mono upper" style={{fontSize:8,letterSpacing:'.1em',color:'var(--ink-3)',marginTop:6}}>{t.sub}</div>}
                </div>
              ))}
            </div>
            {(pop.spotifyTotalTracks || pop.tidalNumTracks) && (
              <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:8,display:'flex',gap:18,flexWrap:'wrap'}}>
                {pop.spotifyAlbumType && <span>Spotify type · <span style={{color:'var(--ink)'}}>{pop.spotifyAlbumType}</span></span>}
                {pop.spotifyTotalTracks && <span>{pop.spotifyTotalTracks} tracks on Spotify</span>}
                {pop.tidalNumVolumes && <span>{pop.tidalNumVolumes} volume{pop.tidalNumVolumes>1?'s':''} on Tidal</span>}
                {pop.qobuzMaximumBitDepth && <span>{pop.qobuzMaximumBitDepth}-bit / {pop.qobuzMaximumSamplingRate} kHz on Qobuz</span>}
              </div>
            )}
          </div>
        );
      })()}

      {/* Top territories */}
      {(() => {
        const terr = (window.RELEASE_TERRITORY_POPULARITY || {})[r.id];
        if (!terr || !terr.length) return null;
        const flagFor = (iso) => (window.REF?.territoryByIso2?.get?.(iso))?.flag_emoji || '';
        const max = Math.max(...terr.map(t => t.pop));
        return (
          <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
            <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:12}}>
              TOP TERRITORIES · {terr.length}
            </div>
            <div>
              {terr.map((t,i)=>(
                <div key={t.iso} style={{display:'grid',gridTemplateColumns:'24px 130px 1fr 56px 36px',gap:10,
                  padding:'7px 0',alignItems:'center',borderBottom:i<terr.length-1?'1px solid var(--rule-soft)':'none'}}>
                  <span style={{fontSize:14}}>{flagFor(t.iso) || '•'}</span>
                  <div style={{minWidth:0}}>
                    <div style={{fontSize:12,fontWeight:500,whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{t.name}</div>
                    <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.06em'}}>{t.iso}</div>
                  </div>
                  <div style={{height:6,background:'var(--bg-2)',position:'relative'}}>
                    <div style={{position:'absolute',inset:0,width:`${(t.pop/100)*100}%`,background:'var(--ink)'}}/>
                  </div>
                  <span className="ff-mono num" style={{fontSize:11,textAlign:'right'}}>POP {t.pop}</span>
                  <span className="ff-mono num" style={{fontSize:10,color:'var(--ink-3)',textAlign:'right'}}>{t.share}%</span>
                </div>
              ))}
            </div>
          </div>
        );
      })()}

      {/* DSP delivery — for the SELECTED edition */}
      <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:12}}>DSP DELIVERY · {delivered}/14{isMulti?` · ${sel.editionLabel}`:''}</div>
        <div style={{display:'grid',gridTemplateColumns:'repeat(2,1fr)',gap:'6px 14px'}}>
          {dsps.map((d,i)=>{
            const live = i < delivered;
            return (
              <div key={d} className="ff-mono" style={{display:'flex',alignItems:'center',gap:8,fontSize:11,
                color: live ? 'var(--ink)' : 'var(--ink-3)'}}>
                <span style={{width:8,height:8,background: live ? 'var(--accent)' : 'var(--ink-4)',
                  display:'inline-block'}}/>
                {d}
                {!live && <span style={{marginLeft:'auto',fontSize:9,letterSpacing:'.08em'}}>QUEUED</span>}
              </div>
            );
          })}
        </div>
      </div>

      {/* Footer actions */}
      <div style={{padding:'18px 28px',display:'flex',gap:8,flexWrap:'wrap'}}>
        <button onClick={()=>toast('Royalty report drafted',  'ok')} className="ff-mono upper"
          style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'var(--ink)',color:'var(--bg)',border:0,cursor:'pointer',fontWeight:600}}>
          ROYALTY REPORT →
        </button>
        <button onClick={()=>{ onClose(); go && go('analytics'); }} className="ff-mono upper"
          style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>
          OPEN IN ANALYTICS
        </button>
      </div>
    </Drawer>
  );
}

// ── PUBLISHER DRAWER ───────────────────────────────────────────
function PublisherDrawer({ p, onClose, go, initialEditMode }) {
  const recentRoyalty = '$' + (Math.round(p.works * 124.7)).toLocaleString();
  const sampleWorks = (typeof WORKS !== 'undefined' ? WORKS.slice(0,5) : []);

  // ── Reconcile-statement state ────────────────────────────────
  // Reconciliation matches an inbound publisher statement (CWR/DDEX/CSV) against
  // our expected royalties for a period. Three phases: setup → running → results.
  const [recon, setRecon] = React.useState(null);
  // recon shape:
  //   { phase:'setup',   period, format, file, expected }
  //   { phase:'running', period, format, file, expected, lines:[{title,iswc,expected,reported,status}], idx }
  //   { phase:'results', ...same, finishedAt, totals:{matched,short,over,missing} }

  // Build a deterministic 12-line sample reconciliation set for this publisher
  const buildReconLines = React.useCallback(() => {
    const seed = (p.cae || p.name || 'x').split('').reduce((a,c)=>(a*31+c.charCodeAt(0))>>>0, 7);
    const works = (typeof WORKS !== 'undefined' ? WORKS.slice(0, 12) : Array.from({length:12}).map((_,i)=>({title:`Work ${i+1}`, iswc:`T-000.000.${String(100+i)}-0`})));
    return works.slice(0, 12).map((w, i) => {
      const r = ((seed * (i+3) * 1103515245 + 12345) >>> 0) % 100;
      const expected = 200 + ((seed >> (i%8)) & 0x7ff); // $200–$2247
      let reported, status;
      if (r < 62)      { reported = expected;                      status = 'matched'; }
      else if (r < 78) { reported = Math.round(expected * 0.92);   status = 'short';   }
      else if (r < 90) { reported = Math.round(expected * 1.06);   status = 'over';    }
      else             { reported = 0;                              status = 'missing';}
      return { title: w.title, iswc: w.iswc, expected, reported, status };
    });
  }, [p.cae, p.name]);

  // Run the reconciliation animation: tick through `lines` one at a time.
  React.useEffect(() => {
    if (!recon || recon.phase !== 'running') return;
    if (recon.idx >= recon.lines.length) {
      const totals = recon.lines.reduce((a, l) => { a[l.status]++; return a; },
        { matched:0, short:0, over:0, missing:0 });
      setRecon(c => c ? {...c, phase:'results', finishedAt:new Date().toLocaleTimeString(), totals} : c);
      return;
    }
    const t = setTimeout(() => setRecon(c => c ? {...c, idx: c.idx+1} : c), 180);
    return () => clearTimeout(t);
  }, [recon]);

  const openRecon = () => {
    const lines = buildReconLines();
    const expected = lines.reduce((s,l)=>s+l.expected, 0);
    setRecon({ phase:'setup', period:'Q1 2026', format:'CWR statement', file:null, expected, lines });
  };
  const startRecon = () => setRecon(c => c ? {...c, phase:'running', idx:0} : c);

  // CSV export of reconciliation results
  const exportRecon = () => {
    if (!recon) return;
    const rows = [
      ['publisher','period','format','title','iswc','expected_usd','reported_usd','variance_usd','status'],
      ...recon.lines.map(l => [
        p.name, recon.period, recon.format, l.title, l.iswc,
        l.expected.toFixed(2), l.reported.toFixed(2), (l.reported - l.expected).toFixed(2), l.status,
      ]),
    ];
    const csv = rows.map(r => r.map(c => /[",\n]/.test(String(c)) ? '"'+String(c).replace(/"/g,'""')+'"' : c).join(',')).join('\n');
    const blob = new Blob([csv], { type:'text/csv;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = `reconciliation_${(p.name||'publisher').replace(/\s+/g,'_')}_${recon.period.replace(/\s+/g,'_')}.csv`;
    document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url);
  };

  const [editMode, setEditMode] = React.useState(!!initialEditMode);
  // Working copy of every editable field. Mirrors the publisher record schema
  // plus a small contact block we lazily seed from the name.
  const [draft, setDraft] = React.useState({
    name:           p.name,
    aliases:        p.aliases || '',
    cae:            p.cae || '',
    isni:           p.isni || '',
    dpid:           p.dpid || '',
    submitterCode:  p.submitterCode || '',
    pro:            p.pro || '',
    territory:      p.territory || 'Worldwide',
    parentPub:      p.parentPub || '',
    administrator:  p.administrator || '',
    contactName:    p.contactName    || 'Rights Department',
    contactRole:    p.contactRole    || 'Head of Publishing',
    contactEmail:   p.contactEmail   || ('rights@' + (p.name||'').toLowerCase().replace(/[^a-z0-9]/g,'') + '.com'),
    contactPhone:   p.contactPhone   || '',
    addr1:          p.addr1          || p.address || '',
    addr2:          p.addr2          || '',
    city:           p.city           || '',
    region:         p.region         || '',
    postal:         p.postal         || '',
    addrCountry:    p.addrCountry    || '',
  });
  const setD = (k, v) => setDraft(d => ({...d, [k]: v}));

  const exitEdit = () => {
    // Persist edits back to the source publisher record so the directory grid,
    // tile lists, and other views see the changes immediately.
    Object.assign(p, draft);
    setEditMode(false);
    if (typeof toast === 'function') toast(`${draft.name} · changes saved`, 'ok');
  };

  // Inline publisher picker — searches the live PUBLISHERS list (excluding self),
  // shows IPI / PRO / works in the dropdown, lets the user pick an existing
  // publisher OR keep typing a new name (which is saved as plain text on the
  // record, ready to be promoted to a real publisher later).
  const PubPick = ({value, onChange, placeholder, allowSelf}) => {
    const all = (typeof PUBLISHERS !== 'undefined' ? PUBLISHERS : []);
    const pool = all.filter(x => x.id !== p.id);
    const [open, setOpen] = React.useState(false);
    const [hi, setHi] = React.useState(0);
    const [q, setQ]   = React.useState(value || '');
    const wrapRef = React.useRef(null);
    React.useEffect(()=>{ setQ(value||''); }, [value]);
    React.useEffect(() => {
      if (!open) return;
      const onDoc = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
      document.addEventListener('mousedown', onDoc);
      return () => document.removeEventListener('mousedown', onDoc);
    }, [open]);
    const ql = (q||'').trim().toLowerCase();
    const matches = !ql ? pool.slice(0,10) : pool.filter(x => `${x.name} ${x.aliases||''} ${x.parent||''}`.toLowerCase().includes(ql)).slice(0,10);
    const linked = pool.find(x => x.name.toLowerCase() === ql);
    const isNew  = q && q.trim() && !linked;
    const fld = {width:'100%',height:32,boxSizing:'border-box',fontSize:13,padding:'0 10px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)',lineHeight:'30px'};
    const totalRows = matches.length + (isNew ? 1 : 0);
    return (
      <div ref={wrapRef} style={{position:'relative'}}>
        <input value={q}
          onChange={e=>{ setQ(e.target.value); onChange(e.target.value); setOpen(true); setHi(0); }}
          onFocus={()=>{ setOpen(true); setHi(0); }}
          onKeyDown={(e)=>{
            if (!open && (e.key==='ArrowDown'||e.key==='Enter')) { setOpen(true); e.preventDefault(); return; }
            if (e.key==='ArrowDown') { setHi(h=>Math.min(h+1,totalRows-1)); e.preventDefault(); }
            else if (e.key==='ArrowUp') { setHi(h=>Math.max(h-1,0)); e.preventDefault(); }
            else if (e.key==='Enter') {
              if (matches[hi]) { onChange(matches[hi].name); setQ(matches[hi].name); setOpen(false); }
              else if (isNew && hi === matches.length) { setOpen(false); /* keep typed value */ }
              e.preventDefault();
            }
            else if (e.key==='Escape') { setOpen(false); }
          }}
          placeholder={placeholder || 'Search publishers…'}
          style={fld}/>
        {open && totalRows>0 && (
          <div style={{position:'absolute',top:'calc(100% + 2px)',left:0,right:0,background:'var(--bg)',border:'1px solid var(--ink)',boxShadow:'0 8px 28px rgba(0,0,0,.16)',zIndex:80,maxHeight:280,overflowY:'auto'}}>
            {matches.map((x,i)=>(
              <button type="button" key={x.id}
                onMouseDown={e=>e.preventDefault()}
                onClick={()=>{ onChange(x.name); setQ(x.name); setOpen(false); }}
                onMouseEnter={()=>setHi(i)}
                style={{display:'grid',gridTemplateColumns:'1fr auto',gap:12,width:'100%',padding:'8px 12px',
                  background:i===hi?'var(--bg-2)':'transparent',border:0,borderBottom:'1px solid var(--rule-soft)',cursor:'pointer',textAlign:'left'}}>
                <div style={{minWidth:0}}>
                  <div style={{fontSize:12,fontWeight:500,whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{x.name}</div>
                  <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:2,whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>
                    {x.aliases && x.aliases !== '—' ? `${x.aliases} · ` : ''}{x.parent && x.parent !== '—' ? x.parent : 'Independent'}
                  </div>
                </div>
                <div style={{textAlign:'right'}}>
                  <div className="ff-mono num" style={{fontSize:10,color:'var(--ink-3)'}}>{x.cae || 'no IPI'}</div>
                  <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:2}}>{x.pro || '—'} · {(x.works||0).toLocaleString()} works</div>
                </div>
              </button>
            ))}
            {isNew && (
              <button type="button"
                onMouseDown={e=>e.preventDefault()}
                onClick={()=>setOpen(false)}
                onMouseEnter={()=>setHi(matches.length)}
                style={{display:'flex',width:'100%',alignItems:'center',justifyContent:'space-between',gap:10,padding:'8px 12px',
                  background:hi===matches.length?'var(--bg-2)':'transparent',border:0,borderTop:'1px solid var(--rule)',cursor:'pointer',textAlign:'left'}}>
                <div style={{display:'flex',alignItems:'center',gap:8,minWidth:0}}>
                  <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--bg)',background:'var(--ink)',padding:'2px 6px'}}>+ ADD</span>
                  <span style={{fontSize:12,fontWeight:500,whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>Use "{q.trim()}" as new publisher</span>
                </div>
                <span className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',whiteSpace:'nowrap'}}>plain-text link</span>
              </button>
            )}
          </div>
        )}
      </div>
    );
  };

  // Inline society picker — searches SOCIETIES (PRO/MRO/CMO) and stores the acronym.
  const SocietyPick = ({value, onChange}) => {
    const all = (typeof SOCIETIES !== 'undefined' ? SOCIETIES : []);
    const pool = all.filter(s => s.kind==='PRO'||s.kind==='MRO'||s.kind==='CMO');
    const [open, setOpen] = React.useState(false);
    const [hi, setHi] = React.useState(0);
    const [q, setQ]   = React.useState(value || '');
    const wrapRef = React.useRef(null);
    React.useEffect(()=>{ setQ(value||''); }, [value]);
    React.useEffect(() => {
      if (!open) return;
      const onDoc = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
      document.addEventListener('mousedown', onDoc);
      return () => document.removeEventListener('mousedown', onDoc);
    }, [open]);
    const ql = (q||'').trim().toLowerCase();
    const matches = !ql ? pool.slice(0,12) : pool.filter(s => `${s.acronym} ${s.name} ${s.territory||''}`.toLowerCase().includes(ql)).slice(0,12);
    const tone = (k) => k==='PRO' ? '#0a4a8c' : k==='MRO' ? '#9b6a18' : '#5a3d6e';
    const fld = {width:'100%',height:32,boxSizing:'border-box',fontSize:13,padding:'0 10px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)',lineHeight:'30px'};
    return (
      <div ref={wrapRef} style={{position:'relative'}}>
        <input value={q} onChange={e=>{setQ(e.target.value); onChange(e.target.value); setOpen(true); setHi(0);}}
          onFocus={()=>{ setOpen(true); setHi(0); }}
          onKeyDown={(e)=>{
            if (!open && (e.key==='ArrowDown'||e.key==='Enter')) { setOpen(true); e.preventDefault(); return; }
            if (e.key==='ArrowDown') { setHi(h=>Math.min(h+1,matches.length-1)); e.preventDefault(); }
            else if (e.key==='ArrowUp') { setHi(h=>Math.max(h-1,0)); e.preventDefault(); }
            else if (e.key==='Enter') { if (matches[hi]) { onChange(matches[hi].acronym); setQ(matches[hi].acronym); setOpen(false);} e.preventDefault(); }
            else if (e.key==='Escape') { setOpen(false); }
          }}
          placeholder="Search societies — ASCAP, PRS, SACEM…" className="ff-mono" style={fld}/>
        {open && matches.length>0 && (
          <div style={{position:'absolute',top:'calc(100% + 2px)',left:0,right:0,background:'var(--bg)',border:'1px solid var(--ink)',boxShadow:'0 8px 28px rgba(0,0,0,.16)',zIndex:80,maxHeight:280,overflowY:'auto'}}>
            {matches.map((s,i)=>(
              <button type="button" key={s.acronym}
                onMouseDown={e=>e.preventDefault()}
                onClick={()=>{ onChange(s.acronym); setQ(s.acronym); setOpen(false); }}
                onMouseEnter={()=>setHi(i)}
                style={{display:'grid',gridTemplateColumns:'auto 1fr auto',gap:10,alignItems:'center',width:'100%',padding:'8px 12px',
                  background:i===hi?'var(--bg-2)':'transparent',border:0,borderBottom:'1px solid var(--rule-soft)',cursor:'pointer',textAlign:'left'}}>
                <span style={{display:'inline-flex',alignItems:'center',gap:6}}>
                  <span style={{width:4,height:16,background:tone(s.kind),flexShrink:0}}/>
                  <span className="ff-mono" style={{fontSize:12,fontWeight:600}}>{s.acronym}</span>
                  <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.08em',color:'var(--ink-3)',padding:'1px 5px',border:'1px solid var(--rule)'}}>{s.kind}</span>
                </span>
                <span style={{minWidth:0,fontSize:11,color:'var(--ink-2)',whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{s.name}</span>
                <span className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',whiteSpace:'nowrap'}}>{s.territory}</span>
              </button>
            ))}
          </div>
        )}
      </div>
    );
  };

  // Field shell — label above input. Used in editable rows.
  const fldStyle = {width:'100%',height:32,boxSizing:'border-box',fontSize:13,padding:'0 10px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)',lineHeight:'30px'};
  const FieldLabel = ({children}) => <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>{children}</div>;
  const TextField = ({label, value, onChange, mono=true, placeholder, maxLen, digitsOnly}) => (
    <label style={{display:'block'}}>
      <FieldLabel>{label}</FieldLabel>
      <input
        value={value}
        onChange={(e)=>{
          let v = e.target.value;
          if (digitsOnly) v = v.replace(/[^\d]/g,'');
          if (maxLen) v = v.slice(0, maxLen);
          onChange(v);
        }}
        placeholder={placeholder}
        className={mono ? 'ff-mono' : ''}
        style={fldStyle}
      />
    </label>
  );

  return (
    <Drawer onClose={onClose}>
      {/* Hero */}
      <div style={{position:'relative',padding:'28px 28px 24px',background:'var(--ink)',color:'var(--bg)'}}>
        <CloseBtn onClose={onClose}/>
        {/* Edit toggle — sits to the left of the close button */}
        <button
          onClick={()=> editMode ? exitEdit() : setEditMode(true) }
          aria-label={editMode ? 'Done editing' : 'Edit publisher'}
          title={editMode ? 'Done' : 'Edit'}
          style={{position:'absolute',top:14,right:52,width:30,height:30,zIndex:2,
            display:'inline-flex',alignItems:'center',justifyContent:'center',
            background: editMode ? 'rgba(255,255,255,.95)' : 'rgba(255,255,255,.14)',
            color:    editMode ? 'var(--ink)' : 'rgba(255,255,255,.92)',
            border:0,cursor:'pointer',padding:0,fontWeight:600}}>
          {editMode ? <span style={{fontSize:16,lineHeight:1}}>✓</span> : <span style={{fontSize:13,lineHeight:1}}>✎</span>}
        </button>

        <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.14em',opacity:.6,marginBottom:14}}>
          PUBLISHER · {editMode ? draft.cae || '—' : (p.cae || '—')}
        </div>
        {editMode ? (
          <input value={draft.name} onChange={e=>setD('name', e.target.value)}
            className="ff-display"
            style={{fontSize:38,fontWeight:700,letterSpacing:'-0.04em',lineHeight:.95,
              background:'rgba(255,255,255,.08)',color:'inherit',
              border:'1px solid rgba(255,255,255,.3)',padding:'4px 8px',width:'100%',
              fontFamily:'inherit',outline:'none',boxSizing:'border-box'}}
            placeholder="Publisher name"/>
        ) : (
          <div className="ff-display" style={{fontSize:42,fontWeight:700,letterSpacing:'-0.04em',lineHeight:.95}}>{window.PartyIndicator && <window.PartyIndicator party={p}/>}{p.name}</div>
        )}
        {!editMode && window.PartyIndicator && (
          <div style={{marginTop:10}}><window.PartyIndicator party={p} detail={true}/></div>
        )}
        {editMode ? (
          <input value={draft.aliases} onChange={e=>setD('aliases', e.target.value)}
            className="ff-mono"
            style={{fontSize:11,marginTop:10,opacity:.92,
              background:'rgba(255,255,255,.08)',color:'inherit',
              border:'1px solid rgba(255,255,255,.3)',padding:'3px 8px',width:'100%',
              fontFamily:'inherit',outline:'none',boxSizing:'border-box'}}
            placeholder="a.k.a. — comma-separated aliases"/>
        ) : (
          <div className="ff-mono" style={{fontSize:11,marginTop:8,opacity:.7}}>a.k.a. {p.aliases || '—'}</div>
        )}
        <div style={{display:'flex',gap:6,marginTop:14}}>
          <Pill tone="accent">{editMode ? draft.territory : p.territory}</Pill>
          <Pill tone="soft" style={{background:'rgba(255,255,255,.12)',color:'var(--bg)',borderColor:'rgba(255,255,255,.2)'}}>SINCE {p.since}</Pill>
        </div>
      </div>

      {/* Big stats — read-only (derived) */}
      <div style={{display:'grid',gridTemplateColumns:'repeat(3,1fr)',borderBottom:'1px solid var(--rule)'}}>
        {[
          {l:'WORKS',     v:p.works.toLocaleString()},
          {l:'YTD ROYAL.', v:recentRoyalty},
          {l:'AGREEMENTS', v:Math.max(2, Math.round(p.works/120))},
        ].map((s,i,arr)=>(
          <div key={s.l} style={{padding:'18px 22px',borderRight:i<arr.length-1?'1px solid var(--rule)':'none'}}>
            <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:6}}>{s.l}</div>
            <div className="ff-display num" style={{fontSize:30,fontWeight:600,letterSpacing:'-0.03em',lineHeight:1}}>{s.v}</div>
          </div>
        ))}
      </div>

      {/* Registry */}
      <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:12}}>REGISTRY</div>
        {editMode ? (
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'10px 14px'}}>
            <TextField label="IPI"           value={draft.cae}           onChange={v=>setD('cae', v)}           placeholder="11-digit IPI" digitsOnly maxLen={11}/>
            <TextField label="ISNI"          value={draft.isni}          onChange={v=>setD('isni', v)}          placeholder="0000 0000 0000 0000"/>
            <TextField label="DPID"          value={draft.dpid}          onChange={v=>setD('dpid', v)}          placeholder="PA-DPIDA-..."/>
            <TextField label="CWR Submitter" value={draft.submitterCode} onChange={v=>setD('submitterCode', v.toUpperCase())} placeholder="3-char code" maxLen={3}/>
            <label style={{display:'block'}}>
              <FieldLabel>PRO</FieldLabel>
              <SocietyPick value={draft.pro} onChange={v=>setD('pro', v)}/>
            </label>
            <label style={{display:'block'}}>
              <FieldLabel>TERRITORY</FieldLabel>
              {/* territory_groups (ref): 12 rows incl. Worldwide / European Union /
                  North America / Latin America / Asia-Pacific etc. Free text
                  fallback for legacy values like "US" / "UK". */}
              {(() => {
                const groups = (window.REF && window.REF.ready && window.REF.raw.territory_groups) || [];
                const opts = groups.length
                  ? groups.map(g => g.group_name).filter(Boolean)
                  : ['Worldwide','US','UK','EU','NA','APAC','LATAM'];
                const has = opts.some(o => o.toLowerCase() === (draft.territory||'').toLowerCase());
                return (
                  <select value={draft.territory} onChange={e=>setD('territory', e.target.value)} className="ff-mono" style={fldStyle}>
                    {!has && draft.territory && <option value={draft.territory}>{draft.territory}</option>}
                    {opts.map(o => <option key={o} value={o}>{o}</option>)}
                  </select>
                );
              })()}
            </label>
          </div>
        ) : (
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'14px 24px'}}>
            <KV k="IPI"            v={p.cae || '—'}/>
            <KV k="ISNI"           v={p.isni || '—'}/>
            <KV k="DPID"           v={p.dpid || '—'}/>
            <KV k="CWR SUBMITTER"  v={p.submitterCode || '—'}/>
            <KV k="PRO"            v={p.pro || '—'} mono={false}/>
            <KV k="TERRITORY"      v={p.territory}/>
            <KV k="JOINED"         v={(window.formatDate ? window.formatDate(p.since) : '') || p.since}/>
          </div>
        )}
      </div>

      {/* Chain */}
      <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:12}}>CHAIN</div>
        {editMode ? (
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'10px 14px'}}>
            <label style={{display:'block'}}>
              <FieldLabel>PARENT PUBLISHER</FieldLabel>
              <PubPick value={draft.parentPub} onChange={v=>setD('parentPub', v)}
                placeholder="—  ·  search the publisher directory"/>
              <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:4,lineHeight:1.4}}>
                {(() => {
                  const all = (typeof PUBLISHERS!=='undefined' ? PUBLISHERS : []);
                  const linked = all.find(x => x.id !== p.id && x.name.toLowerCase() === (draft.parentPub||'').trim().toLowerCase());
                  return linked
                    ? <>↳ Linked to <b style={{color:'var(--ink-2)'}}>{linked.name}</b> · {linked.cae ? `IPI ${linked.cae} · ` : ''}{(linked.works||0).toLocaleString()} works</>
                    : draft.parentPub
                      ? <>+ <b style={{color:'var(--ink-2)'}}>{draft.parentPub}</b> isn't in the directory — saved as plain text. Add it later.</>
                      : <>Optional. Leave blank if there is no parent publisher.</>;
                })()}
              </div>
            </label>
            <label style={{display:'block'}}>
              <FieldLabel>ADMINISTRATOR</FieldLabel>
              <PubPick value={draft.administrator} onChange={v=>setD('administrator', v)}
                placeholder="—  ·  blank = self-administered"/>
              <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:4,lineHeight:1.4}}>
                {(() => {
                  const all = (typeof PUBLISHERS!=='undefined' ? PUBLISHERS : []);
                  const linked = all.find(x => x.id !== p.id && x.name.toLowerCase() === (draft.administrator||'').trim().toLowerCase());
                  return linked
                    ? <>↳ Linked to <b style={{color:'var(--ink-2)'}}>{linked.name}</b> · admin handles registrations & collection.</>
                    : draft.administrator
                      ? <>+ <b style={{color:'var(--ink-2)'}}>{draft.administrator}</b> isn't in the directory — saved as plain text.</>
                      : <>Blank means <b style={{color:'var(--ink-2)'}}>self-administered</b>. Only fill if a different publisher administers this catalog.</>;
                })()}
              </div>
            </label>
          </div>
        ) : (
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'14px 24px'}}>
            <KV k="PARENT PUBLISHER" v={p.parentPub || '—'} mono={false}/>
            <KV k="ADMINISTRATOR"    v={p.administrator || 'Self-administered'} mono={false}/>
          </div>
        )}
      </div>

      {/* Contact */}
      <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:12}}>PRIMARY CONTACT</div>
        {editMode ? (
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'10px 14px'}}>
            <TextField label="Name"    mono={false} value={draft.contactName}  onChange={v=>setD('contactName', v)}  placeholder="e.g. Maya Okonkwo"/>
            <TextField label="Role"    mono={false} value={draft.contactRole}  onChange={v=>setD('contactRole', v)}  placeholder="Head of Publishing"/>
            <label style={{display:'block'}}>
              <FieldLabel>EMAIL</FieldLabel>
              <window.EmailField value={draft.contactEmail} onChange={v=>setD('contactEmail', v)} style={fldStyle} className="ff-mono"/>
            </label>
            <label style={{display:'block'}}>
              <FieldLabel>PHONE</FieldLabel>
              <window.PhoneField value={draft.contactPhone} onChange={v=>setD('contactPhone', v)} style={fldStyle}
                defaultCountry={draft.addrCountryIso || 'US'}/>
            </label>

            {/* Address — country first, then street, then city/state/postal.
                Country is stored as ISO-2 in `addrCountryIso`; legacy `addrCountry`
                (common_name) is preserved for back-compat in the read view. */}
            <div style={{gridColumn:'1 / -1',marginTop:6}}>
              <FieldLabel>ADDRESS</FieldLabel>
              <window.AddressBlock
                value={{
                  country_iso: draft.addrCountryIso || '',
                  line1: draft.addr1 || '',
                  line2: draft.addr2 || '',
                  city: draft.city || '',
                  state: draft.region || '',
                  postal_code: draft.postal || '',
                }}
                onChange={(next) => {
                  // mirror ISO into common_name for back-compat reads
                  const ts = (window.REF && window.REF.ready && window.REF.raw.territories) || [];
                  const ctry = next.country_iso ? ts.find(t => t.iso_alpha_2 === next.country_iso) : null;
                  setD('addrCountryIso', next.country_iso || '');
                  setD('addrCountry', ctry ? ctry.common_name : '');
                  setD('addr1',  next.line1 || '');
                  setD('addr2',  next.line2 || '');
                  setD('city',   next.city || '');
                  setD('region', next.state || '');
                  setD('postal', next.postal_code || '');
                }}
                style={fldStyle}/>
            </div>
          </div>
        ) : (() => {
          // Compose a tidy multi-line read-only address from whichever fields are set.
          // Fall back to the legacy `address` string so older records still render.
          const lines = [
            p.addr1,
            p.addr2,
            [p.city, p.region, p.postal].filter(Boolean).join(', '),
            p.addrCountry,
          ].map(s => (s||'').trim()).filter(Boolean);
          const addrDisplay = lines.length ? lines : (p.address ? [p.address] : []);
          return (
            <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'14px 24px'}}>
              <KV k="NAME"    v={p.contactName  || '—'} mono={false}/>
              <KV k="ROLE"    v={p.contactRole  || '—'} mono={false}/>
              <KV k="EMAIL"   v={p.contactEmail || '—'}/>
              <KV k="PHONE"   v={p.contactPhone || '—'}/>
              <div style={{gridColumn:'1 / -1'}}>
                <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:6}}>ADDRESS</div>
                {addrDisplay.length === 0 ? (
                  <div style={{fontSize:13,color:'var(--ink-3)'}}>—</div>
                ) : (
                  <div style={{fontSize:13,lineHeight:1.5}}>
                    {addrDisplay.map((line,i) => <div key={i}>{line}</div>)}
                  </div>
                )}
              </div>
            </div>
          );
        })()}
      </div>

      {/* Recent works */}
      <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:12}}>RECENT WORKS · TOP 5</div>
        <div>
          {sampleWorks.map((w,i)=>(
            <button key={w.id} onClick={()=>{ onClose(); go && go('work', w); }}
              style={{display:'grid',gridTemplateColumns:'24px 1fr auto',gap:12,width:'100%',
                padding:'10px 0',
                alignItems:'center',background:'transparent',border:'none',
                borderBottom:'1px solid var(--rule-soft)',cursor:'pointer',textAlign:'left'}}>
              <span className="ff-mono num" style={{fontSize:11,color:'var(--ink-3)'}}>{String(i+1).padStart(2,'0')}</span>
              <div style={{minWidth:0}}>
                <div style={{fontSize:13,fontWeight:500}}>{w.title}</div>
                <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:2}}>ISWC {window.iswcDisplay ? window.iswcDisplay(w.iswc) : w.iswc} · {w.shares}</div>
              </div>
              <Ic.Right width={12} height={12} style={{color:'var(--ink-3)'}}/>
            </button>
          ))}
        </div>
      </div>

      {/* Footer — adapts to mode */}
      <div style={{padding:'18px 28px',display:'flex',gap:8,flexWrap:'wrap'}}>
        {editMode ? (<>
          <button onClick={exitEdit} className="ff-mono upper"
            style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'var(--ink)',color:'var(--bg)',border:0,cursor:'pointer',fontWeight:600}}>
            SAVE CHANGES
          </button>
          <button onClick={()=>{ setDraft({
              name:p.name, aliases:p.aliases||'', cae:p.cae||'', isni:p.isni||'', dpid:p.dpid||'', submitterCode:p.submitterCode||'',
              pro:p.pro||'', territory:p.territory||'Worldwide', parentPub:p.parentPub||'',
              administrator:p.administrator||'',
              contactName:p.contactName||'Rights Department', contactRole:p.contactRole||'Head of Publishing',
              contactEmail:p.contactEmail||('rights@'+(p.name||'').toLowerCase().replace(/[^a-z0-9]/g,'')+'.com'),
              contactPhone:p.contactPhone||'',
              addr1:p.addr1||p.address||'', addr2:p.addr2||'', city:p.city||'', region:p.region||'', postal:p.postal||'', addrCountry:p.addrCountry||'',
            }); setEditMode(false); }} className="ff-mono upper"
            style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>
            DISCARD
          </button>
        </>) : (<>
          <button onClick={openRecon} className="ff-mono upper"
            style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'var(--ink)',color:'var(--bg)',border:0,cursor:'pointer',fontWeight:600}}>
            RECONCILE STATEMENT
          </button>
          <button onClick={()=>{ onClose && onClose(); go && go('catalog', { tab:'songs', publisher: p.name, publisherIpi: p.cae }); }} className="ff-mono upper"
            style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>
            FILTER CATALOG →
          </button>
          {window.DetailDelete && (
            <window.DetailDelete kind="party" record={{ id: p.id || p.cae || p.name, ...p }} title={p.name} subtitle={`Publisher · ${p.cae || ''}`} onDeleted={() => onClose && onClose()} variant="ghost" label="DELETE" />
          )}
        </>)}
      </div>

      {/* Reconcile-statement modal — match an inbound publisher statement against
          our expected royalties for a period. setup → running → results. */}
      {recon && (
        <div onClick={()=> recon.phase!=='running' && setRecon(null)}
          style={{position:'fixed',inset:0,background:'rgba(0,0,0,.5)',zIndex:120,display:'flex',alignItems:'center',justifyContent:'center',padding:24}}>
          <div onClick={e=>e.stopPropagation()}
            style={{background:'var(--bg)',border:'1px solid var(--ink)',width:'min(820px,100%)',maxHeight:'90vh',overflow:'auto'}}>

            {/* Header */}
            <div style={{padding:'16px 22px',borderBottom:'1px solid var(--rule)',display:'flex',justifyContent:'space-between',alignItems:'baseline',gap:12}}>
              <div>
                <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:4}}>
                  RECONCILE STATEMENT · {p.name}
                </div>
                <div className="ff-display" style={{fontSize:22,fontWeight:600,letterSpacing:'-0.02em'}}>
                  {recon.phase==='setup'   && 'Match an inbound statement'}
                  {recon.phase==='running' && 'Reconciling…'}
                  {recon.phase==='results' && 'Reconciliation complete'}
                </div>
              </div>
              {recon.phase!=='running' && (
                <button onClick={()=>setRecon(null)} aria-label="Close"
                  style={{width:28,height:28,border:'1px solid var(--rule)',background:'var(--bg)',cursor:'pointer'}}>×</button>
              )}
            </div>

            {/* Phase: setup */}
            {recon.phase==='setup' && (
              <div style={{padding:'18px 22px',display:'grid',gap:14}}>
                <div className="ff-mono" style={{fontSize:12,color:'var(--ink-2)',lineHeight:1.55}}>
                  Upload the publisher's statement (CWR/DDEX RD-DSR/CSV/XLSX). We'll match each
                  reported line to the royalties we expected for the period — flagging matches,
                  shorts, overpayments, and missing works.
                </div>

                <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
                  <label>
                    <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>PERIOD</div>
                    <select value={recon.period} onChange={e=>setRecon(c=>({...c,period:e.target.value}))} className="ff-mono"
                      style={{width:'100%',fontSize:13,padding:'0 10px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)'}}>
                      {['Q1 2026','Q4 2025','Q3 2025','Q2 2025','H2 2025','FY 2025'].map(o=> <option key={o}>{o}</option>)}
                    </select>
                  </label>
                  <label>
                    <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>STATEMENT FORMAT</div>
                    <select value={recon.format} onChange={e=>setRecon(c=>({...c,format:e.target.value}))} className="ff-mono"
                      style={{width:'100%',fontSize:13,padding:'0 10px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)'}}>
                      {['CWR statement','DDEX RD-DSR','CSV (mapped)','XLSX (mapped)'].map(o=> <option key={o}>{o}</option>)}
                    </select>
                  </label>
                </div>

                {/* File drop */}
                <div>
                  <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>STATEMENT FILE</div>
                  <label style={{display:'block',border:'1px dashed var(--rule)',padding:'18px',cursor:'pointer',background:'var(--paper)'}}>
                    <input type="file" style={{display:'none'}} accept=".cwr,.xml,.csv,.xlsx,.tsv,.txt"
                      onChange={e=>{ const f=e.target.files && e.target.files[0]; if (f) setRecon(c=>({...c,file:{name:f.name, size:f.size}})); }}/>
                    {recon.file ? (
                      <div className="ff-mono" style={{fontSize:12,color:'var(--ink)'}}>
                        <span style={{fontWeight:600}}>{recon.file.name}</span>
                        <span style={{color:'var(--ink-3)'}}> · {(recon.file.size/1024).toFixed(1)} KB · click to replace</span>
                      </div>
                    ) : (
                      <div className="ff-mono" style={{fontSize:12,color:'var(--ink-3)'}}>
                        Click to choose file, or drop a {recon.format} here.
                        <span style={{color:'var(--ink-4)'}}> · No file selected — we'll use a sample for the demo.</span>
                      </div>
                    )}
                  </label>
                </div>

                {/* Expected summary strip */}
                <div style={{borderTop:'1px solid var(--rule)',borderBottom:'1px solid var(--rule)',padding:'10px 0',display:'grid',gridTemplateColumns:'repeat(3,1fr)',gap:0}}>
                  <div>
                    <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em'}}>EXPECTED LINES</div>
                    <div className="ff-display num" style={{fontSize:22,fontWeight:600}}>{recon.lines.length}</div>
                  </div>
                  <div>
                    <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em'}}>EXPECTED TOTAL</div>
                    <div className="ff-display num" style={{fontSize:22,fontWeight:600}}>${recon.expected.toLocaleString()}</div>
                  </div>
                  <div>
                    <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em'}}>ACTIVE AGREEMENTS</div>
                    <div className="ff-display num" style={{fontSize:22,fontWeight:600}}>{p.agreements || p.works || '—'}</div>
                  </div>
                </div>

                <div style={{display:'flex',justifyContent:'flex-end',gap:8}}>
                  <button onClick={()=>setRecon(null)} className="ff-mono upper"
                    style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>CANCEL</button>
                  <button onClick={startRecon} className="ff-mono upper"
                    style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'var(--ink)',color:'var(--bg)',border:0,cursor:'pointer',fontWeight:600}}>
                    RUN RECONCILIATION →
                  </button>
                </div>
              </div>
            )}

            {/* Phase: running */}
            {recon.phase==='running' && (
              <div style={{padding:'18px 22px',display:'grid',gap:12}}>
                <div className="ff-mono" style={{fontSize:12,color:'var(--ink-2)'}}>
                  Matching {recon.lines.length} lines · {recon.format} · {recon.period}
                </div>
                {/* Progress bar */}
                <div style={{height:6,background:'var(--rule-soft)',position:'relative'}}>
                  <div style={{position:'absolute',inset:0,right:'auto',width:`${(recon.idx/recon.lines.length)*100}%`,background:'var(--ink)',transition:'width 180ms linear'}}/>
                </div>
                {/* Live line readout */}
                <div style={{maxHeight:280,overflow:'auto',border:'1px solid var(--rule)',background:'var(--paper)'}}>
                  {recon.lines.slice(0, recon.idx).map((l,i)=>{
                    const v = l.reported - l.expected;
                    const tag = l.status==='matched' ? 'OK'
                      : l.status==='short'   ? 'SHORT'
                      : l.status==='over'    ? 'OVER'
                      : 'MISSING';
                    const color = l.status==='matched' ? 'var(--ok)'
                      : l.status==='missing' ? 'var(--danger)'
                      : 'var(--ink-2)';
                    return (
                      <div key={i} className="ff-mono" style={{display:'grid',gridTemplateColumns:'60px 1fr 130px 90px',gap:10,padding:'5px 10px',fontSize:11,borderBottom:'1px solid var(--rule-soft)',color}}>
                        <span style={{fontWeight:600}}>{tag}</span>
                        <span style={{whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis',color:'var(--ink-2)'}}>{l.title}</span>
                        <span style={{color:'var(--ink-3)'}}>{window.iswcDisplay ? window.iswcDisplay(l.iswc) : l.iswc}</span>
                        <span style={{textAlign:'right',color:v===0?'var(--ink-3)':color}}>{v>0?'+':''}{v.toLocaleString(undefined,{style:'currency',currency:'USD',maximumFractionDigits:0})}</span>
                      </div>
                    );
                  })}
                  {recon.idx < recon.lines.length && (
                    <div className="ff-mono" style={{padding:'8px 10px',fontSize:11,color:'var(--ink-3)'}}>
                      → Matching line {recon.idx+1} of {recon.lines.length}: <span style={{color:'var(--ink)'}}>{recon.lines[recon.idx].title}</span>…
                    </div>
                  )}
                </div>
              </div>
            )}

            {/* Phase: results */}
            {recon.phase==='results' && (
              <div style={{padding:'18px 22px',display:'grid',gap:14}}>
                {/* Totals strip */}
                <div style={{display:'grid',gridTemplateColumns:'repeat(4,1fr)',borderTop:'1px solid var(--rule)',borderBottom:'1px solid var(--rule)',padding:'10px 0',gap:0}}>
                  {[
                    {k:'matched', label:'MATCHED',  color:'var(--ok)'},
                    {k:'short',   label:'UNDERPAID', color:'var(--ink)'},
                    {k:'over',    label:'OVERPAID',  color:'var(--ink)'},
                    {k:'missing', label:'MISSING',   color:'var(--danger)'},
                  ].map(t => (
                    <div key={t.k}>
                      <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em'}}>{t.label}</div>
                      <div className="ff-display num" style={{fontSize:26,fontWeight:600,color:t.color}}>{recon.totals[t.k]}</div>
                    </div>
                  ))}
                </div>

                {/* Variance summary */}
                {(() => {
                  const expectedTotal = recon.lines.reduce((s,l)=>s+l.expected,0);
                  const reportedTotal = recon.lines.reduce((s,l)=>s+l.reported,0);
                  const variance = reportedTotal - expectedTotal;
                  return (
                    <div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:12,fontSize:13}}>
                      <div>
                        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em'}}>EXPECTED</div>
                        <div className="ff-display num" style={{fontSize:18,fontWeight:600}}>${expectedTotal.toLocaleString()}</div>
                      </div>
                      <div>
                        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em'}}>REPORTED</div>
                        <div className="ff-display num" style={{fontSize:18,fontWeight:600}}>${reportedTotal.toLocaleString()}</div>
                      </div>
                      <div>
                        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em'}}>VARIANCE</div>
                        <div className="ff-display num" style={{fontSize:18,fontWeight:600,color: variance<0 ? 'var(--danger)' : variance>0 ? 'var(--ok)' : 'var(--ink)'}}>
                          {variance>=0?'+':''}${Math.abs(variance).toLocaleString()}
                        </div>
                      </div>
                    </div>
                  );
                })()}

                {/* Detail table */}
                <div style={{border:'1px solid var(--rule)',maxHeight:260,overflow:'auto'}}>
                  <div className="ff-mono upper" style={{display:'grid',gridTemplateColumns:'70px 1fr 130px 90px 90px 90px',gap:10,padding:'8px 10px',fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',borderBottom:'1px solid var(--rule)',background:'var(--paper)'}}>
                    <span>STATUS</span><span>WORK</span><span>ISWC</span>
                    <span style={{textAlign:'right'}}>EXPECTED</span><span style={{textAlign:'right'}}>REPORTED</span><span style={{textAlign:'right'}}>VARIANCE</span>
                  </div>
                  {recon.lines.map((l,i)=>{
                    const v = l.reported - l.expected;
                    const tag = l.status==='matched' ? 'OK'
                      : l.status==='short'   ? 'SHORT'
                      : l.status==='over'    ? 'OVER'
                      : 'MISSING';
                    const color = l.status==='matched' ? 'var(--ok)'
                      : l.status==='missing' ? 'var(--danger)'
                      : 'var(--ink-2)';
                    return (
                      <div key={i} className="ff-mono" style={{display:'grid',gridTemplateColumns:'70px 1fr 130px 90px 90px 90px',gap:10,padding:'6px 10px',fontSize:11,borderBottom:'1px solid var(--rule-soft)'}}>
                        <span style={{fontWeight:600,color}}>{tag}</span>
                        <span style={{whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{l.title}</span>
                        <span style={{color:'var(--ink-3)'}}>{window.iswcDisplay ? window.iswcDisplay(l.iswc) : l.iswc}</span>
                        <span style={{textAlign:'right'}}>${l.expected.toLocaleString()}</span>
                        <span style={{textAlign:'right'}}>${l.reported.toLocaleString()}</span>
                        <span style={{textAlign:'right',color:v===0?'var(--ink-3)':color}}>{v>0?'+':''}{v.toLocaleString(undefined,{style:'currency',currency:'USD',maximumFractionDigits:0})}</span>
                      </div>
                    );
                  })}
                </div>

                <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',gap:8}}>
                  <div className="ff-mono" style={{fontSize:11,color:'var(--ink-3)'}}>
                    Finished {recon.finishedAt} · {recon.format} · {recon.period}
                  </div>
                  <div style={{display:'flex',gap:8}}>
                    <button onClick={exportRecon} className="ff-mono upper"
                      style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>
                      EXPORT CSV
                    </button>
                    <button onClick={()=>setRecon(null)} className="ff-mono upper"
                      style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'var(--ink)',color:'var(--bg)',border:0,cursor:'pointer',fontWeight:600}}>
                      DONE
                    </button>
                  </div>
                </div>
              </div>
            )}

          </div>
        </div>
      )}

    </Drawer>
  );
}

// ── LABEL DRAWER ───────────────────────────────────────────────
// Default Neighboring Rights Organizations by territory.
// NRO = the collective that licenses & collects performance royalties for sound-recording rightsholders.
const DEFAULT_NROS = [
  {territory:'United States',  iso:'US', org:'SoundExchange',    member:'Member',     since:'2014'},
  {territory:'United Kingdom', iso:'GB', org:'PPL',              member:'Member',     since:'2011'},
  {territory:'Germany',        iso:'DE', org:'GVL',              member:'Member',     since:'2013'},
  {territory:'France',         iso:'FR', org:'SCPP',             member:'Member',     since:'2012'},
  {territory:'Japan',          iso:'JP', org:'GeidankyoCPRA',    member:'Reciprocal', since:'2015'},
  {territory:'Netherlands',    iso:'NL', org:'SENA',             member:'Reciprocal', since:'2013'},
  {territory:'Brazil',         iso:'BR', org:'ABRAMUS',          member:'—',          since:'—'},
];

function LabelDrawer({ l, onClose, go, initialEditMode=false }) {
  // Mock recent releases for this label
  const REL = (typeof window.RELEASES !== 'undefined') ? window.RELEASES : (typeof RELEASES !== 'undefined' ? RELEASES : null);
  const labelReleases = REL
    ? REL.filter(r => r.label.toLowerCase().includes(l.name.toLowerCase().split(' ')[0])).slice(0,5)
    : [];

  const [editMode, setEditMode] = React.useState(initialEditMode);
  const [logoFile, setLogoFile] = React.useState(null);
  const [dist, setDist] = React.useState({
    name:   l.name,
    code:   l.code,
    parent: l.parent,
    deals:  l.deals,
    kind:   l.kind || (/sony music|universal music|warner music|umg|wmg/i.test(l.parent||'') ? 'major' : 'indie'),
    status: 'Active partner',
  });
  const [nros, setNros] = React.useState(DEFAULT_NROS);
  const [editingNro, setEditingNro] = React.useState(null);
  const [contact, setContact] = React.useState({
    primary:    'Maya Okonkwo',
    role:       'Head of Rights & Royalties',
    email:      'rights@'+l.name.toLowerCase().replace(/[^a-z]/g,'')+'.com',
    phone:      '+1 (212) 833-8000',
    address:    '550 Madison Ave, New York, NY 10022',
  });
  const [syncRun, setSyncRun] = React.useState(null); // { rows:[{n,status,detail}], idx, done }
  const [reportCfg, setReportCfg] = React.useState(null); // { period, format, recipients:[email], notes, sending, sent, sentAt }
  const fileRef = React.useRef(null);

  // Drive the NRO sync simulation
  React.useEffect(() => {
    if (!syncRun || syncRun.done) return;
    if (syncRun.idx >= syncRun.rows.length) {
      setSyncRun(s => ({...s, done:true}));
      return;
    }
    const t = setTimeout(() => {
      setSyncRun(s => {
        if (!s) return s;
        const rows = s.rows.map((r,i) => {
          if (i !== s.idx) return r;
          // Resolve outcome based on member status
          let status, detail;
          if (r.n.member === 'Member') {
            status = 'ok';
            detail = `Reciprocal feed acked · ${Math.floor(800 + Math.random()*1400)} works`;
          } else if (r.n.member === 'Reciprocal') {
            status = 'ok';
            detail = `Reciprocal claim file received · ${Math.floor(120 + Math.random()*400)} claims`;
          } else if (r.n.member === 'Pending') {
            status = 'warn';
            detail = 'Awaiting bilateral agreement countersign';
          } else {
            status = 'skip';
            detail = 'No reciprocal — territory not represented';
          }
          return {...r, status, detail};
        });
        return {...s, rows, idx: s.idx + 1};
      });
    }, 380);
    return () => clearTimeout(t);
  }, [syncRun]);

  const onPickLogo = (e) => {
    const f = e.target.files && e.target.files[0];
    if (!f) return;
    const url = URL.createObjectURL(f);
    setLogoFile({name:f.name, url});
    if (typeof toast === 'function') toast(`Logo uploaded · ${f.name}`);
  };

  const exitEdit = () => {
    setEditingNro(null);
    // Persist edits back to the source label record so filters, tiles, and other views see the change.
    l.name   = dist.name;
    l.code   = dist.code;
    l.parent = dist.parent;
    l.deals  = dist.deals;
    l.kind   = dist.kind;
    setEditMode(false);
    if (typeof toast === 'function') toast(`${dist.name} · changes saved`, 'ok');
  };

  return (
    <Drawer onClose={onClose}>
      {/* Hero */}
      <div style={{position:'relative',padding:'32px 28px 24px',background:l.color,color:'rgba(255,255,255,.95)',minHeight:200}}>
        <CloseBtn onClose={onClose}/>
        {/* Global edit toggle — matches CloseBtn size, sits to its left with spacing */}
        <button
          onClick={()=> editMode ? exitEdit() : setEditMode(true) }
          aria-label={editMode ? 'Done editing' : 'Edit label'}
          title={editMode ? 'Done' : 'Edit'}
          style={{position:'absolute',top:14,right:52,width:30,height:30,zIndex:2,
            display:'inline-flex',alignItems:'center',justifyContent:'center',
            background: editMode ? 'rgba(255,255,255,.95)' : 'rgba(255,255,255,.14)',
            color:    editMode ? l.color : 'rgba(255,255,255,.92)',
            border:0,cursor:'pointer',padding:0,fontWeight:600}}>
          {editMode
            ? <span style={{fontSize:16,lineHeight:1}}>✓</span>
            : <span style={{fontSize:13,lineHeight:1}}>✎</span>}
        </button>
        <span className="ff-display" style={{position:'absolute',bottom:8,left:24,fontSize:160,fontWeight:800,
          color:'rgba(255,255,255,.12)',letterSpacing:'-0.06em',lineHeight:1,pointerEvents:'none'}}>{l.code}</span>
        <div style={{position:'relative',zIndex:1,display:'flex',gap:18,alignItems:'flex-start'}}>
          {/* Logo slot — read-only unless in edit mode */}
          <button
            onClick={()=> editMode && fileRef.current && fileRef.current.click()}
            disabled={!editMode}
            title={editMode ? (logoFile ? 'Replace logo' : 'Upload logo') : (logoFile ? 'Logo' : 'Enter edit mode to upload a logo')}
            style={{width:72,height:72,flex:'0 0 72px',
              background: logoFile ? '#fff' : (editMode ? 'rgba(255,255,255,.16)' : 'rgba(255,255,255,.06)'),
              border: editMode ? '1px dashed rgba(255,255,255,.7)' : '1px solid rgba(255,255,255,.18)',
              cursor: editMode ? 'pointer' : 'default',padding:0,
              display:'flex',alignItems:'center',justifyContent:'center',overflow:'hidden',color:'rgba(255,255,255,.85)',
              opacity: (!editMode && !logoFile) ? .55 : 1}}>
            {logoFile
              ? <img src={logoFile.url} alt="logo" style={{width:'100%',height:'100%',objectFit:'contain',background:'#fff'}}/>
              : <span className="ff-mono upper" style={{fontSize:8,letterSpacing:'.12em',lineHeight:1.3,textAlign:'center',padding:'0 4px'}}>
                  {editMode ? <>UPLOAD<br/>LOGO</> : <>NO<br/>LOGO</>}
                </span>}
          </button>
          <input ref={fileRef} type="file" accept="image/*" style={{display:'none'}} onChange={onPickLogo}/>
          <div style={{minWidth:0,flex:1}}>
            <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.14em',opacity:.7,marginBottom:14,display:'flex',alignItems:'baseline',gap:8}}>
              <span>LABEL ·</span>
              {editMode ? (
                <input value={dist.code} onChange={e=>setDist({...dist,code:e.target.value.toUpperCase().slice(0,6)})}
                  className="ff-mono upper"
                  style={{fontSize:9,letterSpacing:'.14em',background:'rgba(255,255,255,.1)',color:'inherit',
                    border:'1px solid rgba(255,255,255,.3)',padding:'2px 6px',width:64,fontFamily:'inherit',outline:'none'}}/>
              ) : <span>{l.code}</span>}
            </div>
            {editMode ? (
              <input value={dist.name} onChange={e=>setDist({...dist,name:e.target.value})}
                className="ff-display"
                style={{fontSize:38,fontWeight:700,letterSpacing:'-0.03em',lineHeight:.95,
                  background:'rgba(255,255,255,.08)',color:'inherit',
                  border:'1px solid rgba(255,255,255,.3)',padding:'4px 8px',width:'100%',
                  fontFamily:'inherit',outline:'none',boxSizing:'border-box'}}
                placeholder="Label name"/>
            ) : (
              <div className="ff-display" style={{fontSize:38,fontWeight:700,letterSpacing:'-0.03em',lineHeight:.95}}>{l.name}</div>
            )}
            <div className="ff-mono" style={{fontSize:11,marginTop:8,opacity:.8}}>{editMode ? dist.parent : l.parent}</div>
          </div>
        </div>
      </div>

      {/* Big stats */}
      <div style={{display:'grid',gridTemplateColumns:'repeat(3,1fr)',borderBottom:'1px solid var(--rule)'}}>
        {[
          {l:'RELEASES',  v:l.releases.toLocaleString()},
          {l:'ARTISTS',   v:l.artists.toLocaleString()},
          {l:'CATALOG $', v:'$'+(l.releases*4.2).toFixed(1)+'M'},
        ].map((s,i,arr)=>(
          <div key={s.l} style={{padding:'18px 22px',borderRight:i<arr.length-1?'1px solid var(--rule)':'none'}}>
            <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:6}}>{s.l}</div>
            <div className="ff-display num" style={{fontSize:30,fontWeight:600,letterSpacing:'-0.03em',lineHeight:1}}>{s.v}</div>
          </div>
        ))}
      </div>

      {/* Distribution */}
      <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:12}}>DISTRIBUTION</div>
        {(() => {
          const allLabels = (typeof LABELS !== 'undefined') ? LABELS : [];
          // Distinct parent options come from existing labels' `parent` field, plus all label names (so you can chain a label to another label).
          const parentOptions = Array.from(new Set([
            ...allLabels.map(x=>x.parent).filter(Boolean),
            ...allLabels.filter(x=>x.id!==l.id).map(x=>x.name),
          ])).sort();
          const linkedParent = allLabels.find(x => x.name === dist.parent && x.id !== l.id);

          if (editMode) {
            const fld = {width:'100%',height:32,boxSizing:'border-box',fontSize:13,padding:'0 10px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)',lineHeight:'30px'};
            return (
              <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'10px 14px'}}>
                <label>
                  <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>CODE</div>
                  <input value={dist.code} onChange={e=>setDist({...dist,code:e.target.value.toUpperCase().slice(0,6)})}
                    className="ff-mono" style={fld}/>
                </label>
                <label>
                  <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4,display:'flex',justifyContent:'space-between',alignItems:'baseline'}}>
                    <span>PARENT / DISTRIBUTOR</span>
                    {linkedParent && (
                      <button type="button"
                        onClick={()=>{ onClose(); window.dispatchEvent(new CustomEvent('astro-open-label',{detail:{id:linkedParent.id}})); }}
                        className="ff-mono upper"
                        style={{fontSize:9,letterSpacing:'.1em',padding:0,background:'transparent',border:0,color:'var(--ink)',cursor:'pointer',textDecoration:'underline'}}>
                        OPEN ↗
                      </button>
                    )}
                  </div>
                  <input value={dist.parent} onChange={e=>setDist({...dist,parent:e.target.value})}
                    list="label-parent-options"
                    className="ff-mono" style={fld}/>
                  <datalist id="label-parent-options">
                    {parentOptions.map(o => <option key={o} value={o}/>)}
                  </datalist>
                  {linkedParent
                    ? <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:4}}>↳ Linked to {linkedParent.code} · {linkedParent.releases.toLocaleString()} releases</div>
                    : <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:4}}>Free-text — pick a label name to auto-link</div>}
                </label>
                <label style={{gridColumn:'1 / -1'}}>
                  <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>DEALS</div>
                  <input value={dist.deals} onChange={e=>setDist({...dist,deals:e.target.value})}
                    className="ff-mono" style={fld}/>
                </label>
                <label>
                  <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4,display:'flex',justifyContent:'space-between',alignItems:'baseline'}}>
                    <span>CLASSIFICATION</span>
                    <span className="ff-mono" style={{fontSize:9,letterSpacing:'.04em',color:'var(--ink-3)',textTransform:'none'}}>
                      Major-owned vs Independent
                    </span>
                  </div>
                  <div style={{display:'flex',gap:0,border:'1px solid var(--rule)'}}>
                    {['major','indie'].map(k => (
                      <button key={k} type="button" onClick={()=>setDist({...dist,kind:k})}
                        className="ff-mono upper"
                        style={{flex:1,padding:'8px 10px',fontSize:10,letterSpacing:'.12em',
                          background: dist.kind===k ? 'var(--ink)' : 'transparent',
                          color:      dist.kind===k ? 'var(--bg)'  : 'var(--ink)',
                          border:0,borderRight: k==='major'?'1px solid var(--rule)':'none',
                          cursor:'pointer',fontWeight:600}}>
                        {k==='major' ? 'MAJOR-OWNED' : 'INDEPENDENT'}
                      </button>
                    ))}
                  </div>
                  <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:4}}>
                    {/sony music|universal music|warner music|umg|wmg/i.test(dist.parent||'')
                      ? <>Auto-derived from parent <b style={{color:'var(--ink-2)'}}>{dist.parent}</b> — override here if needed.</>
                      : <>Set manually. ASTRO infers Major when parent is Sony/Universal/Warner.</>}
                  </div>
                </label>
                <label>
                  <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>STATUS</div>
                  <select value={dist.status} onChange={e=>setDist({...dist,status:e.target.value})}
                    className="ff-mono" style={fld}>
                    <option>Active partner</option>
                    <option>Pending onboarding</option>
                    <option>On hold</option>
                    <option>Terminated</option>
                  </select>
                </label>
              </div>
            );
          }
          return (
            <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'14px 24px'}}>
              <KV k="CODE" v={dist.code}/>
              <div>
                <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:3}}>PARENT</div>
                {linkedParent ? (
                  <button onClick={()=>{ onClose(); window.dispatchEvent(new CustomEvent('astro-open-label',{detail:{id:linkedParent.id}})); }}
                    style={{background:'transparent',border:0,padding:0,cursor:'pointer',color:'var(--ink)',fontSize:13,
                      textAlign:'left',textDecoration:'underline',textDecorationColor:'var(--rule)',textUnderlineOffset:3}}>
                    {dist.parent}
                    <span className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginLeft:6,letterSpacing:'.06em'}}>↗ {linkedParent.code}</span>
                  </button>
                ) : (
                  <div style={{fontSize:13}}>{dist.parent}</div>
                )}
              </div>
              <KV k="DEALS"  v={dist.deals} mono={false}/>
              <div>
                <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:3}}>CLASSIFICATION</div>
                <div style={{display:'flex',alignItems:'center',gap:8}}>
                  <span className="ff-mono upper" style={{fontSize:10,letterSpacing:'.12em',padding:'2px 7px',
                    background: dist.kind === 'major' ? 'var(--ink)' : 'transparent',
                    color:      dist.kind === 'major' ? 'var(--bg)'  : 'var(--ink)',
                    border: '1px solid var(--ink)',fontWeight:600}}>
                    {dist.kind === 'major' ? 'MAJOR-OWNED' : 'INDEPENDENT'}
                  </span>
                  <span className="ff-mono" style={{fontSize:10,color:'var(--ink-3)'}}>
                    {/sony music|universal music|warner music|umg|wmg/i.test(dist.parent||'') ? 'auto · from parent' : 'manual'}
                  </span>
                </div>
              </div>
              <KV k="STATUS" v={dist.status}/>
            </div>
          );
        })()}
      </div>

      {/* Neighboring Rights Organizations (per territory) */}
      <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
        <div style={{display:'flex',alignItems:'baseline',justifyContent:'space-between',marginBottom:12}}>
          <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em'}}>
            NEIGHBORING RIGHTS · {nros.length} TERRITORIES
          </div>
          {editMode && (
            <button onClick={()=>{
                setNros([...nros, {territory:'New territory',iso:'—',org:'—',member:'—',since:'—'}]);
                setEditingNro(nros.length);
              }}
              className="ff-mono upper"
              style={{padding:'4px 8px',fontSize:9,letterSpacing:'.1em',background:'transparent',color:'var(--ink-2)',border:'1px solid var(--rule)',cursor:'pointer'}}>
              + ADD TERRITORY
            </button>
          )}
        </div>
        <div style={{border:'1px solid var(--rule)'}}>
          <div className="ff-mono upper" style={{display:'grid',gridTemplateColumns:'30px 1.4fr 1.4fr 0.9fr 0.7fr 24px',
              gap:8,padding:'8px 10px',fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',background:'var(--bg-2)',borderBottom:'1px solid var(--rule)'}}>
            <span>ISO</span><span>TERRITORY</span><span>ORGANIZATION</span><span>STATUS</span><span>SINCE</span><span/>
          </div>
          {nros.map((n,i)=>{
            const isEditing = editMode && editingNro === i;
            return (
              <div key={i} style={{display:'grid',gridTemplateColumns:'30px 1.4fr 1.4fr 0.9fr 0.7fr 24px',
                gap:8,padding:'8px 10px',alignItems:'center',
                borderBottom: i<nros.length-1 ? '1px solid var(--rule-soft)' : 'none',
                fontSize:12, background: isEditing ? 'var(--bg-2)' : 'transparent'}}>
                {isEditing ? (() => {
                  const fieldStyle = {width:'100%',height:28,boxSizing:'border-box',fontSize:12,padding:'0 6px',border:'1px solid var(--rule)',background:'var(--bg)',fontFamily:'inherit',lineHeight:'26px'};
                  const monoFieldStyle = {...fieldStyle, fontVariantNumeric:'tabular-nums'};
                  return (
                  <>
                    <input className="ff-mono" value={n.iso} onChange={e=>setNros(nros.map((x,j)=>j===i?{...x,iso:e.target.value.toUpperCase().slice(0,2)}:x))}
                      style={monoFieldStyle}/>
                    <input value={n.territory} onChange={e=>setNros(nros.map((x,j)=>j===i?{...x,territory:e.target.value}:x))}
                      style={fieldStyle}/>
                    <input value={n.org} onChange={e=>setNros(nros.map((x,j)=>j===i?{...x,org:e.target.value}:x))}
                      list={`nro-suggest-${i}`}
                      style={fieldStyle}/>
                    <datalist id={`nro-suggest-${i}`}>
                      {['SoundExchange','PPL','GVL','SCPP','SPPF','SENA','SAMI','GRAMEX','PPCA','RESOUND','ABRAMUS','GeidankyoCPRA','FILSCAP','AFI','ADAMI','SPEDIDAM'].map(o=>(
                        <option key={o} value={o}/>
                      ))}
                    </datalist>
                    <select value={n.member} onChange={e=>setNros(nros.map((x,j)=>j===i?{...x,member:e.target.value}:x))}
                      style={fieldStyle}>
                      <option>Member</option>
                      <option>Reciprocal</option>
                      <option>Pending</option>
                      <option>—</option>
                    </select>
                    <input className="ff-mono num" value={n.since} onChange={e=>setNros(nros.map((x,j)=>j===i?{...x,since:e.target.value}:x))}
                      style={monoFieldStyle}/>
                    <button onClick={()=>{ setEditingNro(null); if (typeof toast === 'function') toast(`${n.org} saved · ${n.territory}`); }}
                      title="Save"
                      style={{height:28,boxSizing:'border-box',background:'var(--ink)',color:'var(--bg)',border:0,fontSize:12,cursor:'pointer',padding:0,fontWeight:700,lineHeight:'26px'}}>✓</button>
                  </>
                  );
                })() : (
                  <>
                    <span className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',letterSpacing:'.06em'}}>{n.iso}</span>
                    <span style={{fontWeight:500}}>{n.territory}</span>
                    <span className="ff-mono">{n.org}</span>
                    <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',
                      color: n.member==='Member' ? 'var(--ink)' : n.member==='Reciprocal' ? 'var(--ink-2)' : 'var(--ink-3)'}}>
                      {n.member==='Member' && <span style={{display:'inline-block',width:6,height:6,background:'var(--ink)',marginRight:5,verticalAlign:'middle'}}/>}
                      {n.member}
                    </span>
                    <span className="ff-mono num" style={{fontSize:11,color:'var(--ink-2)'}}>{n.since}</span>
                    {editMode
                      ? <button onClick={()=>setEditingNro(i)} title="Edit"
                          style={{background:'transparent',border:0,fontSize:11,color:'var(--ink-3)',cursor:'pointer',padding:0}}>✎</button>
                      : <span/>}
                  </>
                )}
              </div>
            );
          })}
        </div>
      </div>

      {/* Contact info */}
      <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
        <div style={{display:'flex',alignItems:'baseline',justifyContent:'space-between',marginBottom:12}}>
          <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em'}}>CONTACT</div>
        </div>
        {editMode ? (
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'10px 14px'}}>
            {[
              {k:'primary', l:'Name'},
              {k:'role',    l:'Role'},
              {k:'email',   l:'Email',   type:'email'},
              {k:'phone',   l:'Phone',   type:'tel'},
              {k:'address', l:'Address', span:2},
            ].map(f=>(
              <label key={f.k} style={{gridColumn: f.span===2?'1 / -1':'auto'}}>
                <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>{f.l}</div>
                <input type={f.type||'text'} value={contact[f.k]}
                  onChange={e=>setContact({...contact,[f.k]:e.target.value})}
                  style={{width:'100%',fontSize:13,padding:'6px 8px',border:'1px solid var(--rule)',background:'var(--bg)',fontFamily:'inherit'}}/>
              </label>
            ))}
          </div>
        ) : (
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'14px 24px'}}>
            <div>
              <div style={{fontSize:14,fontWeight:600,marginBottom:2}}>{contact.primary}</div>
              <div className="ff-mono" style={{fontSize:11,color:'var(--ink-3)'}}>{contact.role}</div>
            </div>
            <KV k="EMAIL"   v={contact.email}/>
            <KV k="PHONE"   v={contact.phone}/>
            <KV k="ADDRESS" v={contact.address} mono={false}/>
          </div>
        )}
      </div>

      {/* Recent releases */}
      {labelReleases.length>0 && (
        <div style={{padding:'20px 28px',borderBottom:'1px solid var(--rule)'}}>
          <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:12}}>RECENT RELEASES</div>
          {labelReleases.map(r=>(
            <button key={r.id} onClick={()=>{ onClose(); window.dispatchEvent(new CustomEvent('astro-open-release',{detail:{id:r.id}})); }}
              style={{display:'grid',gridTemplateColumns:'40px 1fr auto',gap:12,width:'100%',
                padding:'10px 0',borderBottom:'1px solid var(--rule-soft)',alignItems:'center',
                background:'transparent',border:0,cursor:'pointer',textAlign:'left'}}>
              <div style={{width:36,height:36,background:r.art}}/>
              <div style={{minWidth:0}}>
                <div style={{fontSize:13,fontWeight:500}}>{r.title}</div>
                <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:2}}>{r.artist} · {r.date}</div>
              </div>
              <Ic.Right width={12} height={12} style={{color:'var(--ink-3)'}}/>
            </button>
          ))}
        </div>
      )}

      {/* Footer */}
      {/* Footer — mode-aware */}
      <div style={{padding:'18px 28px',display:'flex',gap:8,flexWrap:'wrap',alignItems:'center'}}>
        {editMode ? (
          <>
            <button onClick={exitEdit} className="ff-mono upper"
              style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'var(--ink)',color:'var(--bg)',border:0,cursor:'pointer',fontWeight:600}}>
              SAVE CHANGES
            </button>
            <button onClick={()=>{
                setLogoFile(null);
                setDist({name:l.name,code:l.code,parent:l.parent,deals:l.deals,kind:l.kind||(/sony music|universal music|warner music|umg|wmg/i.test(l.parent||'')?'major':'indie'),status:'Active partner'});
                setNros(DEFAULT_NROS);
                setEditingNro(null);
                setContact({
                  primary:'Maya Okonkwo',
                  role:'Head of Rights & Royalties',
                  email:'rights@'+l.name.toLowerCase().replace(/[^a-z]/g,'')+'.com',
                  phone:'+1 (212) 833-8000',
                  address:'550 Madison Ave, New York, NY 10022',
                });
                setEditMode(false);
                if (typeof toast === 'function') toast(`${l.name} · changes discarded`);
              }} className="ff-mono upper"
              style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>
              DISCARD
            </button>
            <span className="ff-mono" style={{marginLeft:'auto',fontSize:10,color:'var(--ink-3)',letterSpacing:'.06em'}}>
              {nros.length} NRO · {logoFile?'logo set':'no logo'}
            </span>
          </>
        ) : (
          <>
            <button onClick={()=>{
                onClose && onClose();
                go && go('catalog', { tab:'releases', label: l.name, labelCode: l.code });
              }} className="ff-mono upper"
              style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'var(--ink)',color:'var(--bg)',border:0,cursor:'pointer',fontWeight:600}}>
              VIEW CATALOG
            </button>
            <button onClick={()=>{
                const period = (() => {
                  const d = new Date();
                  d.setMonth(d.getMonth()-1);
                  return d.toISOString().slice(0,7); // YYYY-MM (last month)
                })();
                setReportCfg({
                  period,
                  format: 'PDF',
                  recipients: [contact.email].filter(Boolean),
                  notes: '',
                  newRecipient: '',
                  sending: false,
                  sent: false,
                });
              }} className="ff-mono upper"
              style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>
              SEND DISTRO REPORT
            </button>
            <button onClick={()=>{
                setSyncRun({
                  rows: nros.map(n => ({n, status:'pending', detail:'Queued'})),
                  idx: 0,
                  done: false,
                  startedAt: new Date().toISOString().slice(11,19),
                });
              }}
              className="ff-mono upper"
              style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>
              SYNC NRO RECIPROCALS
            </button>
            <button onClick={()=>{
                const safe = (s)=>String(s||'').replace(/[\r\n,;]/g,' ').trim();
                const [first,...rest] = safe(contact.primary).split(' ');
                const last = rest.join(' ');
                const vcf = [
                  'BEGIN:VCARD',
                  'VERSION:3.0',
                  `N:${safe(last)};${safe(first)};;;`,
                  `FN:${safe(contact.primary)}`,
                  `ORG:${safe(l.name)};${safe(dist.parent)}`,
                  `TITLE:${safe(contact.role)}`,
                  `EMAIL;TYPE=WORK,INTERNET:${safe(contact.email)}`,
                  `TEL;TYPE=WORK,VOICE:${safe(contact.phone)}`,
                  `ADR;TYPE=WORK:;;${safe(contact.address)};;;;`,
                  `NOTE:Label ${safe(l.code)} · ${nros.length} neighboring rights territories`,
                  'END:VCARD',
                ].join('\r\n');
                const blob = new Blob([vcf],{type:'text/vcard;charset=utf-8'});
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `${l.code}_${safe(contact.primary).replace(/\s+/g,'_')}.vcf`;
                document.body.appendChild(a); a.click(); a.remove();
                setTimeout(()=>URL.revokeObjectURL(url), 1000);
                toast(`vCard downloaded · ${contact.primary}`);
              }} className="ff-mono upper"
              style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>
              EXPORT VCARD
            </button>
            {window.DetailDelete && (
              <window.DetailDelete kind="party" record={{ id: l.id || l.code || l.name, ...l }} title={l.name} subtitle={`Label · ${l.code || ''}`} onDeleted={() => onClose && onClose()} variant="ghost" label="DELETE" />
            )}
          </>
        )}
      </div>

      {/* NRO Sync modal — overlays the drawer */}
      {syncRun && (() => {
        const total = syncRun.rows.length;
        const completed = syncRun.rows.filter(r => r.status !== 'pending').length;
        const counts = syncRun.rows.reduce((a,r)=>{ a[r.status]=(a[r.status]||0)+1; return a; }, {});
        const pct = total ? Math.round(completed/total*100) : 0;
        return (
          <div style={{position:'fixed',top:0,right:0,bottom:0,width:'min(560px, 92vw)',
              background:'rgba(0,0,0,.42)',display:'flex',alignItems:'flex-end',justifyContent:'center',zIndex:62}}
               onClick={() => syncRun.done && setSyncRun(null)}>
            <div onClick={e=>e.stopPropagation()}
              style={{width:'100%',background:'var(--bg)',color:'var(--ink)',borderTop:'1px solid var(--rule)',
                maxHeight:'72%',display:'flex',flexDirection:'column',animation:'astro-slide-up .25s ease-out'}}>
              {/* Header */}
              <div style={{padding:'18px 24px',borderBottom:'1px solid var(--rule)',display:'flex',alignItems:'center',justifyContent:'space-between',gap:14}}>
                <div>
                  <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.14em',marginBottom:6}}>
                    NRO RECIPROCAL SYNC · STARTED {syncRun.startedAt} UTC
                  </div>
                  <div className="ff-display" style={{fontSize:22,fontWeight:600,letterSpacing:'-0.02em',lineHeight:1.1}}>
                    {syncRun.done ? 'Sync complete' : `Syncing ${completed} / ${total} territories…`}
                  </div>
                </div>
                <button onClick={()=>setSyncRun(null)} aria-label="Close sync"
                  style={{width:30,height:30,background:'var(--bg-2)',border:'1px solid var(--rule)',cursor:'pointer',color:'var(--ink)',fontSize:16,lineHeight:1}}>
                  ×
                </button>
              </div>

              {/* Progress bar */}
              <div style={{height:3,background:'var(--bg-2)',position:'relative'}}>
                <div style={{position:'absolute',inset:0,right:'auto',width:`${pct}%`,background:'var(--ink)',transition:'width .3s ease-out'}}/>
              </div>

              {/* Summary chips */}
              <div style={{padding:'12px 24px',borderBottom:'1px solid var(--rule)',display:'flex',gap:18,flexWrap:'wrap'}}>
                {[
                  {l:'OK',      v:counts.ok||0,      tone:'var(--ink)'},
                  {l:'WARN',    v:counts.warn||0,    tone:'var(--accent, #d4a02a)'},
                  {l:'SKIPPED', v:counts.skip||0,    tone:'var(--ink-3)'},
                  {l:'PENDING', v:counts.pending||0, tone:'var(--ink-3)'},
                ].map(c => (
                  <div key={c.l} style={{display:'flex',alignItems:'baseline',gap:6}}>
                    <span style={{display:'inline-block',width:8,height:8,background:c.tone}}/>
                    <span className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em'}}>{c.l}</span>
                    <span className="ff-mono num" style={{fontSize:13,fontWeight:600,color:c.tone}}>{c.v}</span>
                  </div>
                ))}
              </div>

              {/* Row list */}
              <div style={{flex:1,overflow:'auto'}}>
                {syncRun.rows.map((r,i) => {
                  const isCurrent = !syncRun.done && i === syncRun.idx;
                  const dotColor = r.status==='ok' ? 'var(--ink)'
                                : r.status==='warn' ? 'var(--accent, #d4a02a)'
                                : r.status==='skip' ? 'var(--ink-3)'
                                : isCurrent ? 'var(--ink-2)' : 'var(--rule)';
                  return (
                    <div key={i} style={{display:'grid',gridTemplateColumns:'30px 1.4fr 1.4fr 0.8fr 1.6fr',
                      gap:10,padding:'10px 24px',alignItems:'center',
                      borderBottom: i<syncRun.rows.length-1 ? '1px solid var(--rule-soft)' : 'none',
                      background: isCurrent ? 'var(--bg-2)' : 'transparent',fontSize:12}}>
                      <span style={{display:'inline-flex',alignItems:'center',gap:6}}>
                        <span style={{width:8,height:8,background:dotColor,
                          animation: isCurrent ? 'astro-pulse 1s ease-in-out infinite' : 'none'}}/>
                        <span className="ff-mono" style={{fontSize:10,color:'var(--ink-3)'}}>{r.n.iso}</span>
                      </span>
                      <span style={{fontWeight:500}}>{r.n.territory}</span>
                      <span className="ff-mono">{r.n.org}</span>
                      <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',
                        color: r.status==='ok' ? 'var(--ink)'
                            : r.status==='warn' ? 'var(--accent, #d4a02a)'
                            : r.status==='skip' ? 'var(--ink-3)'
                            : 'var(--ink-3)'}}>
                        {r.status==='pending' ? (isCurrent?'syncing…':'queued')
                          : r.status==='skip' ? 'skipped'
                          : r.status==='warn' ? 'warning'
                          : 'ok'}
                      </span>
                      <span className="ff-mono" style={{fontSize:11,color: r.status==='pending' ? 'var(--ink-3)' : 'var(--ink-2)'}}>{r.detail}</span>
                    </div>
                  );
                })}
              </div>

              {/* Footer */}
              <div style={{padding:'14px 24px',borderTop:'1px solid var(--rule)',display:'flex',gap:8,justifyContent:'flex-end',alignItems:'center'}}>
                {!syncRun.done && (
                  <span className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginRight:'auto',letterSpacing:'.04em'}}>
                    Streaming reciprocal feeds via SCAPR backbone…
                  </span>
                )}
                {syncRun.done && (
                  <>
                    <button onClick={()=>{
                        const lines = [
                          ['ISO','Territory','Organization','Status','Detail'].join(','),
                          ...syncRun.rows.map(r=>[r.n.iso,`"${r.n.territory}"`,`"${r.n.org}"`,r.status,`"${r.detail}"`].join(','))
                        ].join('\n');
                        const blob = new Blob([lines],{type:'text/csv'});
                        const url = URL.createObjectURL(blob);
                        const a = document.createElement('a');
                        a.href = url; a.download = `${l.code}_nro_sync_${Date.now()}.csv`;
                        document.body.appendChild(a); a.click(); a.remove();
                        setTimeout(()=>URL.revokeObjectURL(url), 1000);
                        toast(`Sync log exported · ${l.code}`);
                      }} className="ff-mono upper"
                      style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:'pointer'}}>
                      EXPORT LOG
                    </button>
                    <button onClick={()=>setSyncRun(null)} className="ff-mono upper"
                      style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'var(--ink)',color:'var(--bg)',border:0,cursor:'pointer',fontWeight:600}}>
                      DONE
                    </button>
                  </>
                )}
              </div>
            </div>
            <style>{`
              @keyframes astro-slide-up { from { transform: translateY(20px); opacity: 0 } to { transform: none; opacity: 1 } }
              @keyframes astro-pulse { 0%,100% { opacity: 1 } 50% { opacity: .35 } }
            `}</style>
          </div>
        );
      })()}

      {/* SEND DISTRO REPORT modal */}
      {reportCfg && (() => {
        const cfg = reportCfg;
        const validEmails = cfg.recipients.filter(e => /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(e));
        const canSend = validEmails.length > 0 && !cfg.sending;
        const isEmail = (s) => /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(s);
        const addRecipient = () => {
          const v = (cfg.newRecipient||'').trim();
          if (!v || !isEmail(v) || cfg.recipients.includes(v)) return;
          setReportCfg({...cfg, recipients:[...cfg.recipients, v], newRecipient:''});
        };
        const removeRecipient = (e) => setReportCfg({...cfg, recipients: cfg.recipients.filter(x=>x!==e)});

        // Period summary stats (mocked from label numbers)
        const periodStats = (() => {
          const seed = (l.releases || 1) + (l.artists || 1);
          return {
            releases: Math.max(1, Math.round((seed % 23) + 4)),
            streams:  ((seed * 31) % 9000 + 1200).toLocaleString() + 'K',
            payable:  '$' + ((seed * 1.7) % 240 + 40).toFixed(1) + 'K',
            territories: nros.length,
          };
        })();

        const send = () => {
          setReportCfg({...cfg, sending:true});
          setTimeout(() => {
            setReportCfg(c => c && {...c, sending:false, sent:true, sentAt:new Date().toISOString().slice(0,16).replace('T',' ')});
            toast(`Distro report sent · ${l.name} → ${validEmails.length} recipient${validEmails.length===1?'':'s'}`, 'ok');
          }, 900);
        };

        const downloadDraft = () => {
          // Compose a plain-text "report" — stand-in for PDF/CSV the real backend would produce
          const lines = [
            `DISTRIBUTION REPORT — ${l.name} (${l.code})`,
            `Period: ${cfg.period}`,
            `Generated: ${new Date().toISOString().slice(0,19).replace('T',' ')} UTC`,
            `Format requested: ${cfg.format}`,
            ``,
            `--- SUMMARY ---`,
            `Releases delivered: ${periodStats.releases}`,
            `Streams: ${periodStats.streams}`,
            `Payable royalties: ${periodStats.payable}`,
            `Active NRO territories: ${periodStats.territories}`,
            ``,
            `--- DISTRIBUTION ---`,
            `Code: ${dist.code}`,
            `Parent / distributor: ${dist.parent}`,
            `Deals: ${dist.deals}`,
            `Status: ${dist.status}`,
            ``,
            `--- NEIGHBORING RIGHTS ---`,
            ...nros.map(n => `  ${n.iso}  ${n.territory.padEnd(20)}  ${n.org.padEnd(22)}  ${n.member}  since ${n.since}`),
            ``,
            `--- RECIPIENTS ---`,
            ...cfg.recipients.map(r => `  ${r}`),
            ``,
            `Notes: ${cfg.notes || '—'}`,
            ``,
            `[End of report — preview only. Production reports are issued as ${cfg.format}.]`,
          ].join('\n');
          const ext = cfg.format === 'CSV' ? 'csv' : cfg.format === 'XLSX' ? 'xlsx' : 'txt';
          const mime = cfg.format === 'CSV' ? 'text/csv' : 'text/plain';
          const blob = new Blob([lines],{type:mime});
          const url = URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url; a.download = `${l.code}_distro_report_${cfg.period}.${ext}`;
          document.body.appendChild(a); a.click(); a.remove();
          setTimeout(()=>URL.revokeObjectURL(url), 1000);
          toast(`Draft downloaded · ${l.code} ${cfg.period}`);
        };

        return (
          <div style={{position:'fixed',top:0,right:0,bottom:0,width:'min(560px, 92vw)',
              background:'rgba(0,0,0,.42)',display:'flex',alignItems:'flex-end',justifyContent:'center',zIndex:62,
              animation:'astro-fade-in .18s ease-out'}}
              onClick={()=>!cfg.sending && setReportCfg(null)}>
            <div onClick={e=>e.stopPropagation()}
              style={{width:'100%',background:'var(--bg)',color:'var(--ink)',borderTop:'1px solid var(--rule)',
                maxHeight:'82%',display:'flex',flexDirection:'column',animation:'astro-slide-up .25s ease-out'}}>
              {/* Header */}
              <div style={{padding:'18px 24px',borderBottom:'1px solid var(--rule)',display:'flex',alignItems:'center',justifyContent:'space-between',gap:14}}>
                <div>
                  <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.14em',marginBottom:6}}>
                    DISTRO REPORT · {l.code}
                  </div>
                  <div className="ff-display" style={{fontSize:22,fontWeight:600,letterSpacing:'-0.02em',lineHeight:1.1}}>
                    {cfg.sent ? 'Report sent' : `Send distribution report — ${cfg.period}`}
                  </div>
                </div>
                <button onClick={()=>setReportCfg(null)} aria-label="Close report" disabled={cfg.sending}
                  style={{width:30,height:30,background:'var(--bg-2)',border:'1px solid var(--rule)',
                    cursor: cfg.sending ? 'not-allowed' : 'pointer',color:'var(--ink)',fontSize:16,lineHeight:1,opacity:cfg.sending?.4:1}}>
                  ×
                </button>
              </div>

              {/* Body */}
              <div style={{flex:1,overflow:'auto'}}>
                {cfg.sent ? (
                  <div style={{padding:'28px 24px'}}>
                    <div style={{padding:'18px',background:'var(--bg-2)',border:'1px solid var(--rule)'}}>
                      <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:10}}>DELIVERY RECEIPT</div>
                      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'12px 20px'}}>
                        <KV k="LABEL"      v={`${l.name} (${l.code})`} mono={false}/>
                        <KV k="PERIOD"     v={cfg.period}/>
                        <KV k="FORMAT"     v={cfg.format}/>
                        <KV k="SENT AT"    v={cfg.sentAt + ' UTC'}/>
                        <KV k="RECIPIENTS" v={validEmails.length + ' delivered'}/>
                        <KV k="MESSAGE-ID" v={'msg_' + Math.random().toString(36).slice(2,10)}/>
                      </div>
                      <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:12,letterSpacing:'.04em'}}>
                        ↳ {validEmails.join(', ')}
                      </div>
                    </div>
                  </div>
                ) : (
                  <div style={{padding:'18px 24px',display:'grid',gap:18}}>
                    {/* Period + format */}
                    <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:14}}>
                      <label>
                        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>PERIOD</div>
                        <input type="month" value={cfg.period} onChange={e=>setReportCfg({...cfg,period:e.target.value})}
                          className="ff-mono"
                          style={{width:'100%',height:32,boxSizing:'border-box',fontSize:13,padding:'0 10px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)'}}/>
                      </label>
                      <label>
                        <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>FORMAT</div>
                        <select value={cfg.format} onChange={e=>setReportCfg({...cfg,format:e.target.value})}
                          className="ff-mono"
                          style={{width:'100%',fontSize:13,padding:'0 10px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)'}}>
                          <option>PDF</option>
                          <option>CSV</option>
                          <option>XLSX</option>
                        </select>
                      </label>
                    </div>

                    {/* Period preview */}
                    <div style={{padding:'14px 16px',background:'var(--bg-2)',border:'1px solid var(--rule)'}}>
                      <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.12em',marginBottom:10}}>WHAT'S INCLUDED · {cfg.period}</div>
                      <div style={{display:'grid',gridTemplateColumns:'repeat(4,1fr)',gap:12}}>
                        {[
                          {l:'RELEASES',   v: periodStats.releases},
                          {l:'STREAMS',    v: periodStats.streams},
                          {l:'PAYABLE',    v: periodStats.payable},
                          {l:'NRO TERR.',  v: periodStats.territories},
                        ].map(s=>(
                          <div key={s.l}>
                            <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:3}}>{s.l}</div>
                            <div className="ff-display num" style={{fontSize:18,fontWeight:600,letterSpacing:'-0.02em'}}>{s.v}</div>
                          </div>
                        ))}
                      </div>
                    </div>

                    {/* Recipients */}
                    <div>
                      <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:6}}>
                        RECIPIENTS · {validEmails.length}
                      </div>
                      <div style={{display:'flex',flexWrap:'wrap',gap:6,marginBottom:8}}>
                        {cfg.recipients.length === 0 && (
                          <span className="ff-mono" style={{fontSize:11,color:'var(--ink-3)'}}>No recipients yet.</span>
                        )}
                        {cfg.recipients.map(e=>{
                          const ok = isEmail(e);
                          return (
                            <span key={e} className="ff-mono"
                              style={{display:'inline-flex',alignItems:'center',gap:6,
                                padding:'4px 6px 4px 10px',fontSize:11,
                                background: ok ? 'var(--bg-2)' : 'rgba(212,160,42,.12)',
                                color: ok ? 'var(--ink)' : 'var(--accent, #d4a02a)',
                                border:'1px solid var(--rule)'}}>
                              {e}
                              <button onClick={()=>removeRecipient(e)} title="Remove"
                                style={{background:'transparent',border:0,color:'var(--ink-3)',fontSize:14,cursor:'pointer',padding:'0 2px',lineHeight:1}}>×</button>
                            </span>
                          );
                        })}
                      </div>
                      <div style={{display:'flex',gap:6,alignItems:'flex-start'}}>
                        <div style={{flex:1}}>
                          <window.EmailField
                            value={cfg.newRecipient}
                            onChange={v => setReportCfg({...cfg, newRecipient: v})}
                            placeholder="add email…"
                            className="ff-mono"
                            style={{width:'100%',height:32,boxSizing:'border-box',fontSize:12,padding:'0 10px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)'}}/>
                        </div>
                        <button onClick={addRecipient}
                          disabled={!isEmail((cfg.newRecipient||'').trim())}
                          className="ff-mono upper"
                          style={{padding:'0 12px',height:32,fontSize:10,letterSpacing:'.1em',
                            background: isEmail((cfg.newRecipient||'').trim()) ? 'var(--ink)' : 'var(--bg-2)',
                            color:      isEmail((cfg.newRecipient||'').trim()) ? 'var(--bg)' : 'var(--ink-3)',
                            border:'1px solid var(--rule)',
                            cursor: isEmail((cfg.newRecipient||'').trim()) ? 'pointer' : 'not-allowed',fontWeight:600}}>
                          + ADD
                        </button>
                      </div>
                    </div>

                    {/* Notes */}
                    <label>
                      <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginBottom:4}}>NOTES (OPTIONAL)</div>
                      <textarea value={cfg.notes} onChange={e=>setReportCfg({...cfg,notes:e.target.value})}
                        rows={3} placeholder="Anything the recipient should know…"
                        style={{width:'100%',boxSizing:'border-box',fontSize:13,padding:'8px 10px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)',fontFamily:'inherit',resize:'vertical'}}/>
                    </label>
                  </div>
                )}
              </div>

              {/* Footer */}
              <div style={{padding:'14px 24px',borderTop:'1px solid var(--rule)',display:'flex',gap:8,alignItems:'center',justifyContent:'flex-end'}}>
                {!cfg.sent && !cfg.sending && (
                  <span className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginRight:'auto',letterSpacing:'.04em'}}>
                    Will deliver via labels-relay@astro · DKIM signed
                  </span>
                )}
                {cfg.sending && (
                  <span className="ff-mono upper" style={{fontSize:10,color:'var(--ink-3)',marginRight:'auto',letterSpacing:'.1em',animation:'astro-pulse 1s ease-in-out infinite'}}>
                    Encrypting & dispatching…
                  </span>
                )}
                {cfg.sent ? (
                  <button onClick={()=>setReportCfg(null)} className="ff-mono upper"
                    style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'var(--ink)',color:'var(--bg)',border:0,cursor:'pointer',fontWeight:600}}>
                    DONE
                  </button>
                ) : (
                  <>
                    <button onClick={downloadDraft} disabled={cfg.sending} className="ff-mono upper"
                      style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',cursor:cfg.sending?'not-allowed':'pointer',opacity:cfg.sending?.4:1}}>
                      DOWNLOAD DRAFT
                    </button>
                    <button onClick={send} disabled={!canSend} className="ff-mono upper"
                      style={{padding:'8px 14px',fontSize:11,letterSpacing:'.08em',
                        background: canSend ? 'var(--ink)' : 'var(--bg-2)',
                        color:      canSend ? 'var(--bg)' : 'var(--ink-3)',
                        border:0,cursor: canSend ? 'pointer' : 'not-allowed',fontWeight:600}}>
                      SEND REPORT
                    </button>
                  </>
                )}
              </div>
            </div>
            <style>{`
              @keyframes astro-fade-in { from { opacity: 0 } to { opacity: 1 } }
            `}</style>
          </div>
        );
      })()}
    </Drawer>
  );
}
// AgreementDrawer was removed in favor of full-page <ScreenAgreement>
// (see agreement-detail.jsx). The astro-open-agreement event now navigates
// to the agreement route instead of opening a drawer.

// ── GLOBAL HOST ────────────────────────────────────────────────
function GlobalEntityDrawers({ go }) {
  const [open, setOpen] = useEnS(null); // {kind, id, edit}

  useEnE(() => {
    const make = (kind) => (e) => { if (e.detail?.id) setOpen({kind, id:e.detail.id, edit: !!e.detail?.edit}); };
    const onR = make('release');
    const onP = make('publisher');
    const onL = make('label');
    // Agreement event navigates to the full-page detail instead of opening a drawer
    const onA = (e) => {
      if (!e.detail?.id) return;
      const AGR = (typeof window.AGREEMENTS !== 'undefined') ? window.AGREEMENTS : [];
      const ag = AGR.find(x => x.id === e.detail.id) || { id: e.detail.id };
      if (window.__astroGo) window.__astroGo('agreement', ag);
    };
    const onClose = () => setOpen(null);
    window.addEventListener('astro-open-release',   onR);
    window.addEventListener('astro-open-publisher', onP);
    window.addEventListener('astro-open-label',     onL);
    window.addEventListener('astro-open-agreement', onA);
    window.addEventListener('astro-close-entity',   onClose);
    return () => {
      window.removeEventListener('astro-open-release',   onR);
      window.removeEventListener('astro-open-publisher', onP);
      window.removeEventListener('astro-open-label',     onL);
      window.removeEventListener('astro-open-agreement', onA);
      window.removeEventListener('astro-close-entity',   onClose);
    };
  }, []);

  if (!open) return null;
  const close = () => setOpen(null);
  if (open.kind==='release') {
    // Look in RELEASES first (canonical group/edition set), then fall back to
    // RELEASES_X (the lite set that recording.releaseIds points into). The two
    // datasets share IDs for the canonical 8 albums but each carries different
    // edition + compilation rows.
    const REL_PRIMARY = (typeof window.RELEASES   !== 'undefined') ? window.RELEASES   : (typeof RELEASES   !== 'undefined' ? RELEASES   : null);
    const REL_FALLBACK= (typeof window.RELEASES_X !== 'undefined') ? window.RELEASES_X : null;
    const r = (REL_PRIMARY && REL_PRIMARY.find(x=>x.id===open.id))
           || (REL_FALLBACK && REL_FALLBACK.find(x=>x.id===open.id))
           || null;
    return r ? <ReleaseDrawer r={r} onClose={close} go={go}/> : null;
  }
  if (open.kind==='publisher') {
    const PUB = (typeof window.PUBLISHERS !== 'undefined') ? window.PUBLISHERS : (typeof PUBLISHERS !== 'undefined' ? PUBLISHERS : null);
    const p = PUB ? PUB.find(x=>x.id===open.id) : null;
    return p ? <PublisherDrawer p={p} onClose={close} go={go} initialEditMode={open.edit}/> : null;
  }
  if (open.kind==='label') {
    const LAB = (typeof window.LABELS !== 'undefined') ? window.LABELS : (typeof LABELS !== 'undefined' ? LABELS : null);
    const l = LAB ? LAB.find(x=>x.id===open.id) : null;
    return l ? <LabelDrawer l={l} onClose={close} go={go} initialEditMode={open.edit}/> : null;
  }
  return null;
}

Object.assign(window, { GlobalEntityDrawers, Drawer, CloseBtn, KV, toast });
