(function (root, factory) {
  if (typeof module === 'object' && module.exports) module.exports = factory;
  else root.createUpdateTriageGesture = factory;
})(typeof self !== 'undefined' ? self : this, function createUpdateTriageGesture(options) {
  const viewportWidth = options.viewportWidth || (() => root.innerWidth);
  const surface = options.surface;
  const threshold = options.threshold || 72;
  const edgeInset = options.edgeInset || 24;
  const interactive = 'a,button,input,textarea,select,label,summary,[contenteditable="true"],[role="button"]';
  let active = null;
  let busy = false;

  function horizontalScroller(target) {
    for (let node = target; node && node !== surface; node = node.parentElement) {
      if (Number(node.scrollWidth) > Number(node.clientWidth) + 1) return true;
    }
    return false;
  }

  function ignored(event) {
    return event.pointerType === 'mouse' || event.clientX <= edgeInset ||
      event.clientX >= viewportWidth() - edgeInset ||
      Boolean(event.target?.closest?.(interactive)) || horizontalScroller(event.target);
  }

  function reset() {
    active = null;
    delete surface.dataset.triageGesture;
  }

  function start(event) {
    if (busy || !options.enabled() || viewportWidth() > 700 || ignored(event) || active) return;
    active = {id:event.pointerId, x:event.clientX, y:event.clientY, cancelled:false};
    surface.setPointerCapture?.(event.pointerId);
  }

  function move(event) {
    if (!active || active.id !== event.pointerId) return;
    const dx = event.clientX - active.x;
    const dy = event.clientY - active.y;
    if (Math.abs(dy) > Math.abs(dx) || Math.abs(dy) > 36) {
      active.cancelled = true;
      delete surface.dataset.triageGesture;
      return;
    }
    if (Math.abs(dx) < 12) return;
    event.preventDefault?.();
    surface.dataset.triageGesture = dx > 0 ? 'keep' : 'read';
  }

  function decide(callback) {
    busy = true;
    let outcome;
    try {
      outcome = callback();
    } catch (error) {
      busy = false;
      throw error;
    }
    if (outcome && typeof outcome.then === 'function') {
      Promise.resolve(outcome).finally(() => { busy = false; });
    } else {
      busy = false;
    }
  }

  function finish(event) {
    if (!active || active.id !== event.pointerId) return;
    const gesture = active;
    const dx = event.clientX - gesture.x;
    const dy = event.clientY - gesture.y;
    surface.releasePointerCapture?.(event.pointerId);
    reset();
    if (gesture.cancelled || Math.abs(dx) < threshold || Math.abs(dx) <= Math.abs(dy)) return;
    decide(dx > 0 ? options.keepUnread : options.markRead);
  }

  surface.addEventListener('pointerdown', start);
  surface.addEventListener('pointermove', move);
  surface.addEventListener('pointerup', finish);
  surface.addEventListener('pointercancel', reset);

  function destroy() {
    surface.removeEventListener('pointerdown', start);
    surface.removeEventListener('pointermove', move);
    surface.removeEventListener('pointerup', finish);
    surface.removeEventListener('pointercancel', reset);
    reset();
  }

  return {destroy};
});
