<!-- SS · part 80 -->
t : [{ who: 'ai', text: 'Describe the song — I\'ll write the lyrics, build every section (intro, verse, chorus, bridge, outro), arrange it and voice it.' }];
    c.innerHTML = msgs.map(function (m) { return '<div class="es-msg' + (m.who === 'me' ? ' me' : '') + '">' + esc(m.text) + '</div>'; }).join(''); c.scrollTop = c.scrollHeight;
  }
  function renderBlocks() {
    var bl = blocks();
    $('#es-blocks').innerHTML = bl.length ? bl.map(function (b, i) { return '<div class="es-block"><b>' + esc(b.label.toUpperCase()) + '</b><textarea data-bi="' + i + '" rows="' + Math.max(1, b.lines.length) + '" aria-label="' + esc(b.label) + ' lyrics">' + esc(b.lines.join('\n')) + '</textarea></div>'; }).join('')
      : '<div class="es-hint">Lyrics appear here as section blocks. You can edit any line.</div>';
    $('#es-suno').value = S.suno || '';
  }
  $('#es-blocks').addEventListener('input', function (e) {
    var t = e.target; if (!t.hasAttribute('data-bi')) return;
    t.style.height = 'auto'; t.style.height = t.scrollHeight + 'px';
    var bl = blocks(); bl[+t.getAttribute('data-bi')].lines = t.value.split('\n');
    S.lyrics = bl.map(function (b) { return '[' + b.label + ']\n' + b.lines.join('\n'); }).join('\n\n'); save();
  });
  $('#es-blocks').addEventListener('change', function () { drawTimeline(); drawCurve(); });
  $('#es-copy-suno').addEventListener('click', function () { var t = $('#es-suno'); t.select(); (navigator.clipboard ? navigator.clipboard.writeText(t.value) : Promise.reject()).then(function () { toast('Copied.'); }, function () { try { document.execCommand('copy'); toast('Copied.'); } catch (e) { toast('Select the text and copy it.'); } }); });
  ['topic', 'mood', 'genre'].forEach(function (k) { var el = $('#es-' + k); el.value = S[k] || ''; el.addEventListener('input', function () { S[k] = el.value; save(); }); });
  var remix = null;
  function applySong(s) {
    stop();
    S.title = s.title; S.lyrics = s.lyrics; S.suno = s.suno_prompt || ''; S.bpm = s.bpm; S.key = parseKey(s.key).name; S.chords = s.chords || [];
    SECS.forEach(function (n) { if (s.sections[n]) S.sections[n] = { bars: s.sections[n].bars, patterns: normPat(s.sections[n].patterns) }; });
    S.ai = clone(S.sections); S.arrangement = s.arrangement.slice(); S.sel = Math.max(0, S.arrangement.indexOf('verse'));
    VOX.clips = {}; seekPos = 0; syncTop(); renderBlocks(); refreshSection(); drawCurve(); if (E) E.T.bpm.value = S.bpm; save();
  }
  function generate(btn, withVoice) {
    var topic = $('#es-topic').value.trim();
    if (!topic && !remix) { toast('Describe the song first.'); if (window.innerWidth < 1100) setMTab('write'); $('#es-topic').focus(); return; }
    chatAdd('me', topic || ('Remix "' + remix.title + '"'));
    busy(btn, true); busy($('#es-send'), true); busy($('#es-gen'), true);
    chatAdd('ai', 'Writing and arranging… (about 10–30 s)');
    api('POST', '/api/ss/arrange', { topic: topic, mood: $('#es-mood').value.trim(), genre: $('#es-genre').value.trim(), remix_id: remix ? remix.id : undefined })
      .then(function (j) {
        var s = j.song; S.chat.pop(); applySong(s);
        chatAdd('ai', 'Here\'s "' + s.title + '" — ' + s.bpm + ' BPM, ' + S.key + ', ' + s.arrangement.length + ' sections (' + mmss(totalSec()) + '). ' + (withVoice ? 'Voicing it now…' : 'Want a different vibe? Send another prompt.'));
        if (withVoice) return renderVocals($('#es-render')).then(function (ok) { if (ok) chatAdd('ai', 'Vocals placed. Press ▶ to hear the full song, then Export.'); });
      })
      .catch(function (e) { S.chat.pop(); chatAdd('ai', 'That didn\'t work: ' + e.message); toast(e.message, 5000); })
      .then(function () { busy(btn, false); busy($('#es-send'), false); busy($('#es-gen'), false); });
  }
  $('#es-send').addEventListener('click', function () { generate(this, false); });
  $('#es-gen').addEventListener('click', function () { generate(this, true); });

  var remixList = null;
  function drawRemix() { var q = $('#es-remix-q').value.trim().toLowerCase(); var items = (remixList || []).filter(function (s) { return !q || s.title.toLowerCase().indexOf(q) >= 0; }).slice(0, 200); $('#es-remix-list').innerHTML = items.length ? items.map(function (s) { return '<li><button type="button" data-id="' + esc(s.id) + '">' + esc(s.title) + (s.date ? '<small>' + esc(s.date) + '</small>' : '') + '</button></li>'; }).join('') : '<li class="es-hint">No songs found.</li>'; }
  function openRemix() {
    var d = $('#es-remix-dlg'); if (d.showModal) d.showModal(); else d.setAttribute('open', '');
    if (remixList) return drawRemix(); $('#es-remix-list').innerHTML = '<li class="es-hint">Loading…</li>';
    api('GET', '/api/ss/remix').then(function (j) { remixList = j.songs || []; drawRemix(); }).catch(function (e) { $('#es-remix-list').innerHTML = '<li class="es-hint">' + esc(e.message) + '</li>'; });
  }
  $('#es-remix-btn').addEventListener('click', openRemix); $('#es-remix2').addEventListener('