<!-- SS · part 90 -->
s[S.sel].start * barSec()); else if (loopSection) play(); });
  function moveSel(d) { var i = S.sel, j = i + d; if (j < 0 || j >= S.arrangement.length) return; var a = S.arrangement, t = a[i]; a[i] = a[j]; a[j] = t; S.sel = j; arrChanged(); }
  $('#es-arr-left').addEventListener('click', function () { moveSel(-1); });
  $('#es-arr-right').addEventListener('click', function () { moveSel(1); });
  $('#es-arr-dup').addEventListener('click', function () { if (S.arrangement.length >= 24) return toast('24 sections max.'); S.arrangement.splice(S.sel + 1, 0, selName()); S.sel++; arrChanged(); });
  $('#es-arr-del').addEventListener('click', function () { if (S.arrangement.length <= 1) return; S.arrangement.splice(S.sel, 1); S.sel = Math.min(S.sel, S.arrangement.length - 1); arrChanged(); });
  $('#es-arr-add').addEventListener('change', function () { var v = this.value; this.value = ''; if (!v) return; if (S.arrangement.length >= 24) return toast('24 sections max.'); S.arrangement.splice(S.sel + 1, 0, v); S.sel++; arrChanged(); });
  $('#es-sec-bars').addEventListener('change', function () { var n = Math.max(1, Math.min(16, Math.round(+this.value || 4))); this.value = n; S.sections[selName()].bars = n; arrChanged(); });
  function arrChanged() { save(); PLAN = plan(); refreshSection(); drawCurve(); if (playing) play(Math.min(curPos(), Math.max(0, totalSec() - 0.1))); }

  // ------------------------------------------------------------------ sequencer + piano roll
  function refreshSection() {
    PLAN = plan();
    var n = selName(); $('#es-seq-sec').textContent = n.toUpperCase(); $('#es-sec-sel').value = n; $('#es-sec-bars').value = S.sections[n].bars;
    renderSeq(); renderRoll(); drawTimeline(); save();
  }
  $('#es-sec-sel').addEventListener('change', function () { var n = this.value, i = S.arrangement.indexOf(n); if (i < 0) { S.arrangement.push(n); i = S.arrangement.length - 1; toast(cap(n) + ' added to the end of the song.'); } S.sel = i; refreshSection(); });
  function renderSeq() {
    var p = selPat(), h = '<span></span>';
    for (var i = 0; i < 16; i++) h += '<span class="es-num">' + (i + 1) + '</span>';
    DRUM_ROWS.forEach(function (r) {
      h += '<span class="es-rl">' + r.toUpperCase() + '</span>';
      for (var s = 0; s < 16; s++) h += '<button type="button" class="es-cell' + (p.drums[r][s] ? ' on' : '') + (s % 4 === 0 ? ' q' : '') + '" data-r="' + r + '" data-s="' + s + '" aria-label="' + r + ' step ' + (s + 1) + '"></button>';
    });
    $('#es-seqgrid').innerHTML = h;
  }
  $('#es-seqgrid').addEventListener('click', function (e) {
    var c = e.target.closest('.es-cell'); if (!c) return; var r = c.getAttribute('data-r'), s = +c.getAttribute('data-s'), p = selPat();
    p.drums[r][s] = p.drums[r][s] ? 0 : 1; c.classList.toggle('on'); save(); drawTimeline();
    if (p.drums[r][s] && E && !playing && Tone.getContext().state === 'running') E.inst.drums.play(r, undefined, 0.9);
  });
  function rollRows(lane) {
    if (lane === 'chords') { var ch = (S.chords || []).slice(); diatonic(S.key).forEach(function (c) { if (ch.indexOf(c) < 0) ch.push(c); }); selPat().chords.forEach(function (c) { if (c && ch.indexOf(c) < 0) ch.push(c); }); return ch.slice(0, 14); }
    var rows = scaleNotes(S.key, lane === 'bass' ? [1, 2] : [4, 5]);
    selPat()[lane].forEach(function (n) { if (n && rows.indexOf(n) < 0) rows.push(n); });
    rows.sort(function (a, b) { return noteMidi(a) - noteMidi(b); });
    return rows.reverse();
  }
  function renderRoll() {
    var lane = S.rollLane, p = selPat()[lane], rows = rollRows(lane), h = '';
    $$('#es-roll-lane button').forEach(function (b) { b.classList.toggle('is-on', b.getAttribute('data-lane') === lane); });
    $('#es-roll-snd').innerHTML = SOUNDS[lane].map(function (o) { return '<option' + (S.sounds[lane] === o ? ' selected' : '') + '>' + o + '</option>'; }).join('');
    rows.forEach(function (rv) {
      var blk = lane !== 'chords' && /^[A-G](#|b)\d$/.test(rv);
      h += '<span class="es-key' + (blk ? ' blk' : '') + '">' + esc(rv) + '</span>';
      for (var s = 0; s < 16; s++) h += '<button type="button" class="es-cell' + (p[s] === rv ? ' on' : '') + (s % 4 === 0 ? ' q' : '') + '" data-v="' + esc(rv) + '" data-s="' + s + '" aria-label="' + esc(rv) + ' step ' + (s + 1) + '"></button>';
    });
    $('#es-rollgrid').innerHTML = h;
  }
  $('#es-roll-lane').addEventListener('click', function (e) { var b = e.target.closest('button[data-lane]'); if (!b) return; S.rollLane = b.getAttribute('data-lane'); renderRoll(); save(); });
  $('#es-roll-snd').addEventListener('change', function () { S.sounds[S.rollLane] = this.value; setSound(E, S.rollLane, this.value); renderFaders(); save(); });
  $('#es-rollgrid').addEventListener('click', function (e) {
    var c = e.target.closest('.es-cell'); if (!c) return; var lane = S.rollLane, s = +c.getAttribute('data-s'), v = c.getAttribute('data-v'), p = selPat()[lane];
    p[s] = p[s] === v ? null : v; save