<!-- SS · part 16 -->
var html = TRACKS.map(function (t) {
      var id = t[0], P = S.patterns;
      var head = '<div class="ss-thead"><span class="ss-tname">' + t[1] + '</span>' +
        '<select class="ss-input ss-sel" data-snd="' + id + '" aria-label="' + t[1] + ' sound">' + SOUNDS[id].map(function (s) { return '<option' + (S.sounds[id] === s ? ' selected' : '') + '>' + s + '</option>'; }).join('') + '</select>' +
        '<input type="range" min="-36" max="6" step="1" value="' + S.vols[id] + '" data-vol="' + id + '" aria-label="' + t[1] + ' volume">' +
        '<button type="button" class="ss-btn ss-btn-sm ss-mute' + (S.mutes[id] ? ' is-on' : '') + '" data-mute="' + id + '">M</button>' +
        '<button type="button" class="ss-btn ss-btn-sm" data-regen="' + id + '">↻ AI</button></div>';
      var body = '';
      if (id === 'drums') {
        ['kick', 'snare', 'hat'].forEach(function (r) {
          body += '<div class="ss-rowlbl">' + r + '</div><div class="ss-grid" data-track="drums" data-row="' + r + '">';
          for (var i = 0; i < STEPS; i++) body += stepBtn(i, P.drums[r][i]);
          body += '</div>';
        });
      } else {
        var opts = penOptions(id); if (!S.pens[id] || opts.indexOf(S.pens[id]) < 0) S.pens[id] = opts[0];
        body += '<div class="ss-pen">Tap a step to place <select class="ss-input ss-sel" data-pen="' + id + '">' + opts.map(function (o) { return '<option' + (o === S.pens[id] ? ' selected' : '') + '>' + o + '</option>'; }).join('') + '</select></div>';
        body += '<div class="ss-grid" data-track="' + id + '" style="margin-top:6px">';
        for (var j = 0; j < STEPS; j++) body += stepBtn(j, !!P[id][j], P[id][j] || '');
        body += '</div>';
      }
      return '<div class="ss-track' + (S.mutes[id] ? ' is-muted' : '') + '" data-t="' + id + '">' + head + body + '</div>';
    }).join('');
    $('#ss-tracks').innerHTML = html;
  }
  function syncStudio() {
    $('#ss-bpm').value = S.bpm; $('#ss-swing').value = S.swing;
    if (KEYS.indexOf(S.key) < 0) S.key = parseKey(S.key).name;
    keySel.value = S.key;
    if (E) { E.T.bpm.value = S.bpm; E.T.swing = S.swing; }
    renderTracks(); updateNow();
  }
  $('#ss-tracks').addEventListener('click', function (e) {
    var cell = e.target.closest('.ss-step'); 
    if (cell) {
      var g = cell.parentNode, track = g.getAttribute('data-track'), i = +cell.getAttribute('data-i');
      if (track === 'drums') { var r = g.getAttribute('data-row'); S.patterns.drums[r][i] = S.patterns.drums[r][i] ? 0 : 1; cell.classList.toggle('on'); }
      else {
        var cur = S.patterns[track][i];
        S.patterns[track][i] = cur ? null : S.pens[track];
        cell.classList.toggle('on', !cur); cell.textContent = cur ? '' : S.pens[track];
        if (!cur && E && Tone.getContext().state === 'running' && !playing) { try { var n = track === 'chords' ? chordNotes(S.pens[track]) : S.pens[track]; if (n) E.inst[track].triggerAttackRelease(n, '8n'); } catch (x) {} }
      }
      save(); return;
    }
    var m = e.target.closest('[data-mute]');
    if (m) { var t = m.getAttribute('data-mute'); S.mutes[t] = !S.mutes[t]; m.classList.toggle('is-on', S.mutes[t]); m.closest('.ss-track').classList.toggle('is-muted', S.mutes[t]); if (E) E.ch[t].mute = S.mutes[t]; save(); return; }
    var rg = e.target.closest('[data-regen]');
    if (rg) regen(rg.getAttribute('data-regen'), rg);
  });
  $('#ss-tracks').addEventListener('change', function (e) {
    var t = e.target;
    if (t.hasAttribute('data-snd')) setSound(t.getAttribute('data-snd'), t.value);
    else if (t.hasAttribute('data-pen')) S.pens[t.getAttribute('data-pen')] = t.value;
  });
  $('#ss-tracks').addEventListener('input', function (e) {
    var t = e.target; if (!t.hasAttribute('data-vol')) return;
    var id = t.getAttribute('data-vol'); S.vols[id] = +t.value; if (E) E.ch[id].volume.value = +t.value; save();
  });
  $('#ss-bpm').addEventListener('change', function () { S.bpm = Math.min(200, Math.max(60, Math.round(+this.value || 92))); this.value = S.bpm; if (E) E.T.bpm.value = S.bpm; save(); renderLines(); });
  $('#ss-swing').addEventListener('input', function () { S.swing = +this.value; if (E) E.T.swing = S.swing; save(); });
  keySel.addEventListener('change', function () { S.key = this.value; save(); renderTracks(); });
  $('#ss-load-ai').addEventListener('click', function () {
    if (!S.ai) { toast('Write a song with AI first (Write tab).'); return; }
    S.patterns = JSON.parse(JSON.stringify(S.ai)); save(); renderTracks(); toast('AI beat loaded.');
  });
  $('#ss-clear').addEventListener('click', function () { if (!confirm('Clear all steps?')) return; S.patterns = emptyPatterns(); save(); renderTracks(); });
  function regen(track, btn) {
    busy(btn, true);
    api('POST', '/api/ss/pattern', { track: track, key: S.key, bpm: S.bpm, chords: S.chords, genre: S.genre, mood: S.mood, current: S.patterns[track] })
      .then(function (j) { S.patterns[track] = j.pattern;