// app/kit.jsx — Scholia design system: tokens + responsive CSS + interactive shared components.

(function () {
  if (document.getElementById('scholia-tokens')) return;
  const link = document.createElement('link');
  link.rel = 'stylesheet';
  link.href = 'https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,600;1,6..72,400;1,6..72,500&family=Hanken+Grotesk:wght@400;500;600;700&family=Spline+Sans+Mono:wght@400;500&display=swap';
  document.head.appendChild(link);

  const s = document.createElement('style');
  s.id = 'scholia-tokens';
  s.textContent = `
  .coda{
    --paper:oklch(0.976 0.008 85); --paper-2:oklch(0.958 0.011 82); --paper-3:oklch(0.938 0.013 80);
    --ink:oklch(0.245 0.012 60); --ink-2:oklch(0.46 0.013 62); --ink-3:oklch(0.62 0.012 66);
    --rule:oklch(0.885 0.013 76); --rule-strong:oklch(0.80 0.015 72);
    --critic:oklch(0.52 0.15 32); --critic-soft:oklch(0.93 0.04 40);
    --fan:oklch(0.62 0.11 72); --fan-ink:oklch(0.52 0.10 68); --fan-soft:oklch(0.94 0.04 82);
    --serif:'Newsreader',Georgia,serif; --sans:'Hanken Grotesk',system-ui,sans-serif; --mono:'Spline Sans Mono',ui-monospace,monospace;
    font-family:var(--sans); color:var(--ink); background:var(--paper);
    -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  }
  .coda *{box-sizing:border-box;}
  .coda ::selection{background:var(--critic-soft);}
  .coda h1,.coda h2,.coda h3,.coda h4,.coda p{margin:0;}
  .c-eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:0.16em;text-transform:uppercase;color:var(--ink-3);}
  .c-serif{font-family:var(--serif);} .c-mono{font-family:var(--mono);}
  .c-btn{font-family:var(--sans);font-weight:600;border:1px solid var(--ink);background:var(--ink);color:var(--paper);
    border-radius:999px;padding:11px 20px;font-size:14px;cursor:pointer;white-space:nowrap;transition:transform .15s,box-shadow .15s,background .15s;}
  .c-btn:hover{transform:translateY(-1px);box-shadow:0 6px 18px rgba(40,30,20,.16);}
  .c-btn:disabled{opacity:.45;cursor:not-allowed;transform:none;box-shadow:none;}
  .c-btn--ghost{background:transparent;color:var(--ink);border-color:var(--rule-strong);}
  .c-btn--ghost:hover{background:var(--paper-2);box-shadow:none;}
  .c-listen{display:inline-flex;align-items:center;gap:9px;font-family:var(--sans);font-weight:600;font-size:14px;
    border:1px solid var(--rule-strong);background:#fff;color:var(--ink);border-radius:999px;padding:9px 16px 9px 13px;cursor:pointer;
    transition:border-color .15s,box-shadow .15s,transform .15s;}
  .c-listen:hover{border-color:var(--ink);transform:translateY(-1px);box-shadow:0 6px 16px rgba(40,30,20,.1);}
  .c-chip{font-family:var(--sans);font-size:13px;font-weight:500;color:var(--ink-2);border:1px solid var(--rule);
    background:#fff;border-radius:999px;padding:6px 13px;cursor:pointer;transition:.15s;white-space:nowrap;}
  .c-chip:hover{border-color:var(--ink-3);color:var(--ink);}
  .c-chip--on{background:var(--ink);color:var(--paper);border-color:var(--ink);}
  .c-link{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--rule-strong);padding-bottom:1px;transition:border-color .15s;cursor:pointer;}
  .c-link:hover{border-color:var(--ink);}
  .clickable{cursor:pointer;}

  /* layout */
  .app-wrap{max-width:1320px;margin:0 auto;padding:0 48px;}
  .nav{display:flex;align-items:center;gap:26px;padding:18px 48px;border-bottom:1px solid var(--rule);background:var(--paper);position:sticky;top:0;z-index:40;}
  .nav-logo{font-family:var(--serif);font-size:25px;font-weight:600;letter-spacing:.01em;cursor:pointer;}
  .nav-links{display:flex;gap:22px;}
  .nav-link{font-size:14px;font-weight:500;color:var(--ink-2);cursor:pointer;padding-bottom:2px;border-bottom:1.5px solid transparent;background:none;border-top:0;border-left:0;border-right:0;font-family:var(--sans);white-space:nowrap;}
  .nav-link:hover{color:var(--ink);}
  .nav-link.on{color:var(--ink);font-weight:600;border-bottom-color:var(--ink);}
  .nav-search{display:flex;align-items:center;gap:9px;border:1px solid var(--rule);border-radius:999px;padding:9px 16px;width:300px;background:#fff;}
  .nav-search input{border:0;outline:0;background:none;font-family:var(--mono);font-size:12.5px;color:var(--ink);width:100%;}
  .nav-search input::placeholder{color:var(--ink-3);}
  .nav-search-btn{display:none;}
  .nav-spacer{flex:1;}
  .avatar{width:34px;height:34px;border-radius:50%;background:var(--ink);color:var(--paper);display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:15px;font-weight:600;cursor:pointer;flex:0 0 34px;border:0;}
  .menu{position:absolute;right:0;top:46px;background:#fff;border:1px solid var(--rule-strong);border-radius:6px;box-shadow:0 12px 34px rgba(40,30,20,.16);min-width:184px;overflow:hidden;z-index:60;}
  .menu-item{display:flex;align-items:center;gap:10px;padding:12px 16px;font-size:14px;color:var(--ink);cursor:pointer;border:0;background:none;width:100%;text-align:left;font-family:var(--sans);}
  .menu-item:hover{background:var(--paper-2);}
  .menu-sep{height:1px;background:var(--rule);}

  .home-hero{display:grid;grid-template-columns:420px 1fr;gap:56px;align-items:center;padding-bottom:48px;border-bottom:1px solid var(--rule);}
  .hero-cover{width:420px;height:420px;}
  .picks-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:28px;}
  .home-lower{display:grid;grid-template-columns:1.5fr 1fr;gap:64px;padding-top:52px;}
  .work-header{display:grid;grid-template-columns:1fr auto;gap:40px;align-items:end;padding-bottom:30px;border-bottom:1px solid var(--rule);}
  .lb-row{display:grid;grid-template-columns:52px 56px 1fr auto 132px;align-items:center;gap:20px;padding:16px 20px;border-bottom:1px solid var(--rule);position:relative;background:#fff;transition:background .12s;}
  .lb-row.head{background:var(--paper-2);border-bottom:1px solid var(--rule-strong);padding:13px 20px;}
  .lb-row.clickable:hover{background:var(--paper-2);}
  .lb-rank{grid-area:rank;} .lb-cover{grid-area:cover;} .lb-meta{grid-area:meta;} .lb-scores{grid-area:scores;display:flex;gap:14px;justify-content:flex-end;} .lb-listen{grid-area:listen;display:flex;justify-content:flex-end;}
  .lb-row{grid-template-areas:"rank cover meta scores listen";}
  .rec-banner-grid{display:grid;grid-template-columns:128px 1fr auto;gap:32px;align-items:center;}
  .rec-scores{display:flex;gap:30px;padding-left:24px;border-left:1px solid var(--rule);}
  .tabs{display:flex;gap:30px;border-bottom:1px solid var(--rule);margin-top:4px;overflow-x:auto;}
  .tab{font-size:14.5px;font-weight:500;color:var(--ink-2);padding:20px 0 16px;border-bottom:2px solid transparent;margin-bottom:-1px;cursor:pointer;white-space:nowrap;background:none;border-top:0;border-left:0;border-right:0;font-family:var(--sans);}
  .tab.on{color:var(--ink);font-weight:600;border-bottom-color:var(--ink);}
  .pro-grid{display:grid;grid-template-columns:1fr 1fr;gap:22px;}
  .siblings-row{display:flex;gap:28px;overflow-x:auto;padding-bottom:6px;}
  .footer{border-top:1px solid var(--rule);margin-top:64px;padding:40px 48px;display:flex;justify-content:space-between;align-items:center;gap:24px;flex-wrap:wrap;color:var(--ink-3);}
  .c-toast{position:fixed;left:50%;bottom:32px;transform:translateX(-50%);background:var(--ink);color:var(--paper);font-size:14px;font-weight:500;padding:13px 22px;border-radius:999px;box-shadow:0 10px 30px rgba(40,30,20,.28);z-index:200;animation:toastIn .25s ease;}
  @keyframes toastIn{from{opacity:0;transform:translate(-50%,12px);}to{opacity:1;transform:translate(-50%,0);}}

  @media (max-width:1040px){
    .home-hero{grid-template-columns:1fr;gap:30px;}
    .hero-cover{width:100%;height:auto;aspect-ratio:1;max-width:460px;}
    .home-lower{grid-template-columns:1fr;gap:44px;}
    .picks-grid{grid-template-columns:repeat(2,1fr);}
  }
  @media (max-width:760px){
    .app-wrap{padding:0 20px;}
    .nav{padding:14px 20px;gap:14px;}
    .nav-links{display:none;}
    .nav-search{display:none;}
    .nav-search-btn{display:flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:50%;border:1px solid var(--rule);background:#fff;cursor:pointer;flex:0 0 38px;}
    .work-header{grid-template-columns:1fr;gap:24px;align-items:start;}
    .lb-row{grid-template-columns:34px 1fr auto;grid-template-areas:"rank meta scores";gap:14px;padding:14px 14px;}
    .lb-row.head{display:none;}
    .lb-cover{display:none;} .lb-listen{display:none;} .lb-scores{justify-content:flex-end;}
    .rec-banner-grid{grid-template-columns:1fr;gap:20px;}
    .rec-scores{padding-left:0;border-left:0;border-top:1px solid var(--rule);padding-top:18px;}
    .pro-grid{grid-template-columns:1fr;}
    .footer{padding:32px 20px;}
  }
  `;
  document.head.appendChild(s);
})();

function Ring({ value = 92, kind = 'critic', size = 64, stroke }) {
  const sw = stroke || Math.max(3, Math.round(size * 0.075));
  const r = (size - sw) / 2;
  const c = 2 * Math.PI * r;
  const col = kind === 'critic' ? 'var(--critic)' : 'var(--fan)';
  const num = kind === 'fan' ? 'var(--fan-ink)' : 'var(--critic)';
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: 'block', flex: `0 0 ${size}px` }}>
      <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--rule)" strokeWidth={sw} />
      <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke={col} strokeWidth={sw}
        strokeLinecap="round" strokeDasharray={c} strokeDashoffset={c * (1 - value / 100)}
        transform={`rotate(-90 ${size / 2} ${size / 2})`} />
      <text x="50%" y="50%" dominantBaseline="central" textAnchor="middle"
        fontFamily="var(--serif)" fontWeight="500" fontSize={size * 0.4} fill={num}>{value}</text>
    </svg>
  );
}

function ScoreStat({ value, kind, label, count, size = 78 }) {
  const col = kind === 'critic' ? 'var(--critic)' : 'var(--fan-ink)';
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
      <Ring value={value} kind={kind} size={size} />
      <div style={{ textAlign: 'center' }}>
        <div className="c-mono" style={{ fontSize: 11, letterSpacing: '0.14em', color: col, fontWeight: 500 }}>{label}</div>
        {count && <div className="c-mono" style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 3 }}>{count}</div>}
      </div>
    </div>
  );
}

function ScoreInline({ c, f, size = 42 }) {
  const Cell = ({ v, kind }) => (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3 }}>
      <Ring value={v} kind={kind} size={size} />
      <span className="c-mono" style={{ fontSize: 9, letterSpacing: '0.12em', color: kind === 'critic' ? 'var(--critic)' : 'var(--fan-ink)' }}>{kind === 'critic' ? 'CRIT' : 'FANS'}</span>
    </div>
  );
  return <div style={{ display: 'flex', gap: 14 }}><Cell v={c} kind="critic" /><Cell v={f} kind="fan" /></div>;
}

const CODA_TONES = {
  ink: { bg: 'oklch(0.27 0.02 60)', fg: '#efe7d8', sub: '#bcae98' },
  oxblood: { bg: 'oklch(0.37 0.09 28)', fg: '#f2e4dd', sub: '#cda79a' },
  forest: { bg: 'oklch(0.36 0.045 156)', fg: '#e9efe6', sub: '#a8bca6' },
  slate: { bg: 'oklch(0.40 0.035 248)', fg: '#e7ecf2', sub: '#a3b0c2' },
  ochre: { bg: 'oklch(0.66 0.10 74)', fg: '#2a2117', sub: '#5c4a2e' },
  bone: { bg: 'oklch(0.90 0.022 82)', fg: '#2a2722', sub: '#7c7363' },
};
function Cover({ composer = 'BEETHOVEN', work = 'Symphony No. 5', tone = 'ink', size = 200, label, style, className, onClick }) {
  const t = CODA_TONES[tone] || CODA_TONES.ink;
  const px = typeof size === 'number';
  return (
    <div className={className} onClick={onClick} style={{
      width: px ? size : '100%', height: px ? size : undefined, aspectRatio: px ? undefined : '1',
      flex: px ? `0 0 ${size}px` : undefined, background: t.bg, color: t.fg,
      display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
      padding: '10%', position: 'relative', overflow: 'hidden',
      boxShadow: 'inset 0 0 0 1px rgba(255,255,255,0.06)', containerType: px ? undefined : 'inline-size', ...style,
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
        <span className="c-mono" style={{ fontSize: px ? Math.max(8, size * 0.045) : '4.5cqw', letterSpacing: '0.14em', color: t.sub }}>{composer}</span>
        <span className="c-mono" style={{ fontSize: px ? Math.max(8, size * 0.04) : '4cqw', color: t.sub }}>{label || 'DG'}</span>
      </div>
      <div className="c-serif" style={{ fontSize: px ? Math.max(15, size * 0.14) : '13cqw', lineHeight: 1.02, fontWeight: 500, letterSpacing: '-0.01em' }}>{work}</div>
      <div style={{ position: 'absolute', left: '10%', right: '10%', bottom: '8.5%', height: 1, background: t.sub, opacity: 0.35 }} />
    </div>
  );
}

const CODA_SVC = { 'Spotify': 'oklch(0.62 0.16 150)', 'Apple Music': 'oklch(0.55 0.15 18)', 'Qobuz': 'oklch(0.50 0.11 255)', 'Tidal': 'oklch(0.42 0.03 230)' };
function Listen({ svc = 'Spotify', full }) {
  const app = useApp();
  const glyph = (
    <span style={{ width: 20, height: 20, borderRadius: '50%', background: CODA_SVC[svc] || 'var(--ink)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flex: '0 0 20px' }}>
      <span style={{ width: 0, height: 0, borderLeft: '6px solid #fff', borderTop: '4px solid transparent', borderBottom: '4px solid transparent', marginLeft: 2 }} />
    </span>
  );
  return (
    <button className="c-listen" style={full ? { width: '100%', justifyContent: 'flex-start' } : {}}
      onClick={(e) => { e.stopPropagation(); app && app.showToast('Opening ' + svc + ' …'); }}>
      {glyph}<span>Listen on <b>{svc}</b></span>
    </button>
  );
}

function Eyebrow({ children, style }) { return <div className="c-eyebrow" style={style}>{children}</div>; }

// ---- interactive nav ----
function Nav({ active }) {
  const app = useApp();
  const [menu, setMenu] = React.useState(false);
  const [q, setQ] = React.useState('');
  const links = [['Browse', '/'], ['Works', '/work/beethoven-5'], ['Performers', '/search?q=philharmonic'], ['Reviews', '/recording/kleiber-vpo-74']];
  const submit = (e) => { e.preventDefault(); if (q.trim()) navigate('/search?q=' + encodeURIComponent(q.trim())); };
  return (
    <header className="nav">
      <div className="nav-logo" onClick={() => navigate('/')}>Scholia</div>
      <nav className="nav-links">
        {links.map(([l, to]) => (
          <button key={l} className={'nav-link' + (l === active ? ' on' : '')} onClick={() => navigate(to)}>{l}</button>
        ))}
      </nav>
      <div className="nav-spacer" />
      <form className="nav-search" onSubmit={submit}>
        <span style={{ width: 14, height: 14, borderRadius: '50%', border: '1.6px solid var(--ink-3)', flex: '0 0 14px' }} />
        <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search recordings…" />
      </form>
      <button className="nav-search-btn" onClick={() => navigate('/search')} aria-label="Search">
        <span style={{ width: 14, height: 14, borderRadius: '50%', border: '1.6px solid var(--ink-3)' }} />
      </button>
      {app.user ? (
        <div style={{ position: 'relative' }}>
          <button className="avatar" onClick={() => setMenu((m) => !m)}>{app.user.initial}</button>
          {menu && (
            <React.Fragment>
              <div onClick={() => setMenu(false)} style={{ position: 'fixed', inset: 0, zIndex: 50 }} />
              <div className="menu">
                <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--rule)' }}>
                  <div className="c-serif" style={{ fontSize: 15, fontWeight: 600 }}>{app.user.name}</div>
                  <div className="c-mono" style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 2 }}>{app.user.handle}</div>
                </div>
                <button className="menu-item" onClick={() => { setMenu(false); navigate('/me'); }}>My reviews</button>
                <div className="menu-sep" />
                <button className="menu-item" onClick={() => { setMenu(false); app.signOut(); navigate('/'); }}>Sign out</button>
              </div>
            </React.Fragment>
          )}
        </div>
      ) : (
        <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
          <button className="nav-link" onClick={() => navigate('/signin')}>Sign in</button>
          <button className="c-btn" style={{ padding: '9px 16px' }} onClick={() => navigate('/signup')}>Join</button>
        </div>
      )}
    </header>
  );
}

function Footer() {
  return (
    <footer className="footer">
      <div className="c-serif" style={{ fontSize: 20, fontWeight: 600, color: 'var(--ink)' }}>Scholia</div>
      <div className="c-eyebrow">The classical recordings almanac · © 2026</div>
    </footer>
  );
}

function Toast() {
  const app = useApp();
  if (!app.toast) return null;
  return <div className="c-toast">{app.toast}</div>;
}

Object.assign(window, { Ring, ScoreStat, ScoreInline, Cover, CODA_TONES, Listen, Nav, Eyebrow, Footer, Toast });
