    /* and dragged: the fourth row lifted and dropped at the top, dragged
       back, refused while the filter is on, still opening the sheet when a
       press is released without moving, and — with the backend armed to
       say no — snapping back and saying so */
    { do: `__drag('.pl-rows .trk', 3, 0)`, name: "playlist-dragged", wait: 1400 },
    { do: `__drag('.pl-rows .trk', 0, 3)`, name: "playlist-dragged-back", wait: 1400 },
    { do: `(function () { var i = document.querySelector('.plfilter input'); i.value = 'track'; i.dispatchEvent(new Event('input', { bubbles: true })); })()`, wait: 500 },
    { do: `__drag('.pl-rows .trk', 0, 3)`, name: "playlist-drag-filtered", wait: 1000 },
    { do: `(function () { var i = document.querySelector('.plfilter input'); i.value = ''; i.dispatchEvent(new Event('input', { bubbles: true })); })()`, wait: 500 },
    { do: `__hold('.pl-rows .trk', 0)`, name: "playlist-drag-held", wait: 900 },
    { do: `document.querySelector('.scrim').click()`, wait: 600 },
    { do: `__ssMock.fail('playlist_set_order', 'database is locked')`, wait: 200 },
    { do: `__drag('.pl-rows .trk', 0, 2)`, name: "playlist-drag-refused", wait: 1400 },
    { do: `(function () { __ssMock.fail('playlist_set_order', ''); __ss.player.error = ''; return true; })()`, wait: 400 },
