<!-- SS · part 21 -->
is.value; save(); });
  $('#ss-copy-suno').addEventListener('click', function () {
    var t = $('#ss-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.'); } });
  });
  $('#ss-write-btn').addEventListener('click', function () {
    var btn = this, topic = $('#ss-topic').value.trim();
    if (!topic && !S.remix) { toast('Tell the AI what the song is about first.'); $('#ss-topic').focus(); return; }
    S.mood = $('#ss-mood').value.trim(); S.genre = $('#ss-genre').value.trim();
    busy(btn, true); btn.textContent = 'Writing… (up to ~30s)';
    api('POST', '/api/ss/write', { topic: topic, mood: S.mood, genre: S.genre, remix_id: S.remix ? S.remix.id : undefined })
      .then(function (j) {
        var s = j.song;
        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 || [];
        S.ai = s.patterns; S.patterns = JSON.parse(JSON.stringify(s.patterns)); S.vox = null;
        save(); fillWrite(); syncStudio(); toast('Song written. Beat loaded in Studio.');
        $('#ss-write-out').scrollIntoView({ behavior: 'smooth', block: 'start' });
      })
      .catch(function (e) { toast(e.message, 5000); })
      .then(function () { busy(btn, false); btn.textContent = 'Write with AI'; });
  });
  $('#ss-to-studio').addEventListener('click', function () { showTab('studio'); });
  $('#ss-to-voice').addEventListener('click', function () { showTab('voice'); });

  // Remix picker
  var remixList = null;
  function drawRemix() {
    var q = $('#ss-remix-q').value.trim().toLowerCase();
    var items = (remixList || []).filter(function (s) { return !q || s.title.toLowerCase().indexOf(q) >= 0; }).slice(0, 200);
    $('#ss-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="ss-hint">No songs found.</li>';
  }
  $('#ss-remix-btn').addEventListener('click', function () {
    var dlg = $('#ss-remix-dlg');
    if (dlg.showModal) dlg.showModal(); else dlg.setAttribute('open', '');
    if (remixList) { drawRemix(); return; }
    $('#ss-remix-list').innerHTML = '<li class="ss-hint">Loading…</li>';
    api('GET', '/api/ss/remix').then(function (j) { remixList = j.songs || []; drawRemix(); }).catch(function (e) { $('#ss-remix-list').innerHTML = '<li class="ss-hint">' + esc(e.message) + '</li>'; });
  });
  $('#ss-remix-q').addEventListener('input', drawRemix);
  $('#ss-remix-list').addEventListener('click', function (e) {
    var b = e.target.closest('button[data-id]'); if (!b) return;
    var s = (remixList || []).filter(function (x) { return x.id === b.getAttribute('data-id'); })[0]; if (!s) return;
    S.remix = { id: s.id, title: s.title };
    $('#ss-remix-title').textContent = s.title; $('#ss-remix-box').hidden = false;
    var dlg = $('#ss-remix-dlg'); if (dlg.close) dlg.close(); else dlg.removeAttribute('open');
    if (!$('#ss-topic').value.trim()) $('#ss-topic').value = 'A fresh remix of "' + s.title + '"';
    toast('Now press Write with AI to remix it.');
  });
  $('#ss-remix-clear').addEventListener('click', function () { S.remix = null; $('#ss-remix-box').hidden = true; });

  // ---------------------------------------------------------------- AUDIO ENGINE
  var E = null; // built lazily after Tone loads
  var SOUNDS = { drums: ['808', 'Lo-fi', 'Chip'], bass: ['Sub', 'Saw', 'FM'], chords: ['Pad', 'Keys', 'Pluck'], lead: ['Saw', 'Square', 'Bell'] };
  function makeDrums(kit, out) {
    var d = {}, nodes = [];
    function keep(n) { nodes.push(n); return n; }
    if (kit === 'Lo-fi') {
      var lp = keep(new Tone.Filter(3200, 'lowpass').connect(out));
      d.kick = keep(new Tone.MembraneSynth({ pitchDecay: 0.03, octaves: 6, envelope: { attack: 0.001, decay: 0.35, sustain: 0, release: 0.1 } }).connect(lp));
      d.snare = keep(new Tone.NoiseSynth({ noise: { type: 'pink' }, envelope: { attack: 0.001, decay: 0.18, sustain: 0 } }).connect(lp));
      var hp = keep(new Tone.Filter(6000, 'highpass').connect(lp));
      d.hat = keep(new Tone.NoiseSynth({ noise: { type: 'white' }, envelope: { attack: 0.001, decay: 0.04, sustain: 0 }, volume: -10 }).connect(hp));
      d.kickNote = 'C1';
    } else if (kit === 'Chip') {
      d.kick = keep(new Tone.MembraneSynth({ oscillator: { type: 'square' }, pitchDecay: 0.02, octaves: 4, envelope: { attack: 0.001, decay: 0.18, sustain: 0 }, volume: -8 }).connect(out));
      d.snare = keep(new Tone.NoiseSynth({ noise: { type: 'brown' }, envelope: { attack: 0.001, decay: 0.09, sustain: 0 }, volume: 2 }).connect(out));
      var hp2 = keep(new Tone.Filter(8000, 'highpass').connect(out));
  