<!-- SS · part 105 -->
es-roll-regen').addEventListener('click', function () { regen(S.rollLane, this); });
  var kitSel = $('select[data-snd="drums"]');
  kitSel.innerHTML = SOUNDS.drums.map(function (o) { return '<option' + (S.sounds.drums === o ? ' selected' : '') + '>' + o + '</option>'; }).join('');
  kitSel.addEventListener('change', function () { S.sounds.drums = this.value; setSound(E, 'drums', this.value); renderFaders(); save(); });

  // ------------------------------------------------------------------ transport readouts
  var keySel = $('#es-key'); keySel.innerHTML = KEYS.map(function (k) { return '<option>' + k + '</option>'; }).join('');
  function syncTop() { $('#es-bpm').value = S.bpm; $('#es-swing').value = S.swing; if (KEYS.indexOf(S.key) < 0) S.key = parseKey(S.key).name; keySel.value = S.key; }
  $('#es-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(); drawTimeline(); drawCurve(); if (playing) play(0); });
  $('#es-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(); renderRoll(); });

  // ------------------------------------------------------------------ mixer + master + spectrum
  function renderFaders() {
    $('#es-faders').innerHTML = LANES.map(function (t) {
      return '<div class="es-fader" style="--c:' + LANE_C[t] + '"><b>' + t.toUpperCase() + '</b><input type="range" min="-36" max="6" step="1" value="' + (S.vols[t] || 0) + '" data-fader="' + t + '" aria-label="' + t + ' volume">' +
        '<div class="es-ms"><button type="button" data-mute="' + t + '" class="' + (S.mutes[t] ? 'is-on' : '') + '" title="Mute">M</button><button type="button" data-solo="' + t + '" class="' + (S.solos[t] ? 'is-on' : '') + '" title="Solo">S</button></div>' +
        (t === 'vocals' ? '<span class="es-hint">Kokoro</span>' : '<select data-fsnd="' + t + '" aria-label="' + t + ' sound">' + SOUNDS[t].map(function (o) { return '<option' + (S.sounds[t] === o ? ' selected' : '') + '>' + o + '</option>'; }).join('') + '</select>') + '</div>';
    }).join('');
  }
  $('#es-faders').addEventListener('input', function (e) { var f = e.target.getAttribute('data-fader'); if (!f) return; S.vols[f] = +e.target.value; applyMix(E); save(); });
  $('#es-faders').addEventListener('click', function (e) {
    var m = e.target.getAttribute('data-mute'), so = e.target.getAttribute('data-solo');
    if (m) { S.mutes[m] = !S.mutes[m]; e.target.classList.toggle('is-on', S.mutes[m]); }
    else if (so) { S.solos[so] = !S.solos[so]; e.target.classList.toggle('is-on', S.solos[so]); } else return;
    applyMix(E); save();
  });
  $('#es-faders').addEventListener('change', function (e) { var t = e.target.getAttribute('data-fsnd'); if (!t) return; S.sounds[t] = e.target.value; setSound(E, t, e.target.value); if (t === 'drums') kitSel.value = e.target.value; if (t === S.rollLane) renderRoll(); save(); });
  function syncKnobs() { $$('[data-m-k]').forEach(function (k) { k.value = S.master[k.getAttribute('data-m-k')]; }); $('#es-master-state').textContent = 'MASTER: ' + (S.master.on ? 'ON · COMP · EQ · LIMITER' : 'OFF'); $('#es-master').classList.toggle('is-on', !!S.master.on); }
  $('#es-knobs').addEventListener('input', function (e) { var k = e.target.getAttribute('data-m-k'); if (!k) return; S.master[k] = +e.target.value; applyMaster(E); save(); });
  $('#es-master').addEventListener('click', function () {
    S.master.on = !S.master.on;
    if (S.master.on) { S.master.comp = Math.max(S.master.comp, 55); S.master.width = Math.max(S.master.width, 60); toast('Master chain on: glue compressor, EQ lift, limiter at −0.8 dB.'); }
    else toast('Master chain off.');
    applyMaster(E); syncKnobs(); save();
    if (window.innerWidth < 1100) setMTab('mix');
  });
  var specCv = $('#es-spec');
  function drawSpectrum() {
    if (!E || !E.fft) return; var cv = specCv, w = cv.clientWidth, h = cv.clientHeight; if (!w) return;
    var dpr = window.devicePixelRatio || 1; if (cv.width !== w * dpr) { cv.width = w * dpr; cv.height = h * dpr; }
    var g = cv.getContext('2d'); g.setTransform(dpr, 0, 0, dpr, 0, 0); g.fillStyle = '#050505'; g.fillRect(0, 0, w, h);
    var v = E.fft.getValue(), n = v.length, sr = Tone.getContext().sampleRate, bars = Math.min(96, Math.floor(w / 3));
    g.strokeStyle = '#1c1c1c'; g.font = '9px sans-serif';
    [100, 1000, 10000].forEach(function (f) { var x = Math.log(f / 20) / Math.log(1000) * w; g.beginPath(); g.moveTo(x, 0); g.lineTo(x, h); g.stroke(); g.fillStyle = '#555'; g.fillText(f >= 1000 ? f / 1000 + 'k' : f, x + 2, h - 3); });
    for (var i = 0; i < bars; i++) {
      var f0 = 20 * Math.pow(1000, i / bars), f1 = 20 * Math.pow(1000, (i + 1) / bars);
      var a = Math.floor(f0 / (sr / 2) * n), b = Math.max(a + 1, Math.floor(f1 / (sr / 2) * n)), m = -1