(async function(){
  const workspaceLifecycle = await loadWorkspace({ document, window });
  const qs = (s, el=document) => el.querySelector(s);
  const announceWork = message => qs('#my-work-action-status').textContent = message;
  const fmt = (d) => new Date(d).toLocaleString();
  const cardPlanning = createCardPlanning(document);
  const mobileComposerViewport = createMobileComposerViewport({
    viewport: window.visualViewport,
    mediaQuery: window.matchMedia('(max-width: 600px)'),
    entries: [
      { panel:qs('#issue-sheet .issue-sheet-panel'), workspace:qs('.issue-comment-composer'), composer:qs('#issue-comment'), submit:qs('#send-issue-comment'), status:qs('#issue-comment-status') },
      { panel:qs('#issue-sheet .issue-sheet-panel'), workspace:qs('.checklist-add'), composer:qs('#add-checklist-step'), submit:qs('#save-checklist-step'), status:qs('#add-checklist-step-status') },
      { panel:qs('#pull-sheet .pull-sheet-panel'), workspace:qs('.pull-comment-composer'), composer:qs('#pull-comment'), submit:qs('#send-pull-comment'), status:qs('#pull-comment-status') },
      { panel:qs('#update-sheet .update-sheet-panel'), workspace:qs('.update-reply'), composer:qs('#update-reply'), submit:qs('#send-update-reply'), status:qs('#update-reply-status') },
      { panel:qs('#review-sheet .review-sheet-panel'), workspace:qs('#review-inline-composer'), composer:qs('#review-inline-body'), submit:qs('#save-inline-comment'), status:qs('#review-submit-status') },
      { panel:qs('.create-issue-panel'), workspace:qs('#create-issue-form'), focusWithin:true },
    ],
  });
  mobileComposerViewport.start();
  const issueDetailPanel = qs('#issue-sheet .issue-sheet-panel');
  const mobileIssueDetailNavigation = createMobileIssueDetailNavigation({
    root:issueDetailPanel,
    buttons:Object.fromEntries(Array.from(document.querySelectorAll('[data-issue-section]')).map(button => [button.dataset.issueSection, button])),
    targets:{
      overview:qs('#issue-overview'),
      conversation:qs('#issue-conversation'),
      reply:qs('#issue-comment'),
      actions:qs('#issue-planning'),
    },
    planning:qs('#issue-planning'),
    onSectionChange:(section, options) => workRoute.section(section, options),
    prefersReducedMotion:() => window.matchMedia('(prefers-reduced-motion: reduce)').matches,
  });
  mobileIssueDetailNavigation.start();
  const pullDetailPanel = qs('#pull-sheet .pull-sheet-panel');
  const mobilePullDetailNavigation = createMobileIssueDetailNavigation({
    root:pullDetailPanel,
    buttons:Object.fromEntries(Array.from(document.querySelectorAll('[data-pull-section]')).map(button => [button.dataset.pullSection, button])),
    targets:{
      overview:qs('#pull-overview'),
      conversation:qs('#pull-conversation'),
      reply:qs('#pull-comment'),
      review:qs('#pull-review'),
    },
    beforeNavigate:{review(target) { target.open = true; }},
    onSectionChange:(section, options) => workRoute.section(section, options),
    prefersReducedMotion:() => window.matchMedia('(prefers-reduced-motion: reduce)').matches,
  });
  mobilePullDetailNavigation.start();
  [
    [qs('.app-menu'), qs('#app-menu-toggle')],
    [qs('.work-settings'), qs('#work-settings-toggle')],
  ].forEach(([disclosure, launcher]) => {
    mobileLaunch.createDisclosure({disclosure, launcher}).start();
  });
  const PANEL_STATE_KEY = "stackchain.panel-state.v1";
  const panels = Array.from(document.querySelectorAll('details[data-panel-key]'));
  let savedState = {};
  try {
    savedState = JSON.parse(localStorage.getItem(PANEL_STATE_KEY) || '{}');
  } catch (e) {
    savedState = {};
  }
  panels.forEach((panel) => {
    if (Object.prototype.hasOwnProperty.call(savedState, panel.dataset.panelKey)) {
      panel.open = savedState[panel.dataset.panelKey];
    }
    panel.addEventListener('toggle', () => {
      const state = Object.fromEntries(panels.map((item) => [item.dataset.panelKey, item.open]));
      try {
        localStorage.setItem(PANEL_STATE_KEY, JSON.stringify(state));
      } catch (_) {}
    });
  });
  const mobileTaskButtons = Object.fromEntries(
    Array.from(document.querySelectorAll('[data-mobile-task]')).map(button => [button.dataset.mobileTask, button])
  );
  const mobileTaskOverlays = Array.from(document.querySelectorAll('[role="dialog"], #whiteboard-modal, #markdown-modal'));
  const attentionInterruption = qs('#attention-interruption');
  function renderAttentionInterruption() {
    const pending = timer.attentionInterruption();
    attentionInterruption.hidden = !pending;
    return pending;
  }

  function selectMobileQueue(name) {
    if (name === 'attention' && workSession.checkpointed()) timer.beginAttention();
    renderAttentionInterruption();
    timerView.render();
    qs('[data-work-filter="' + name + '"]').click();
    qs('#my-work').scrollIntoView({block:'start'});
    qs('#my-work').focus();
  }
  async function recoverMobileDelivery(item) {
    if (!item?.outbox_id || !activeFlushLogin) throw new Error('Sign in again to retry.');
    const authored = item.kind === 'authored-outbox';
    const result = await (authored ? authoredOutbox : issueOutbox).retry(item.outbox_id, activeFlushLogin);
    (authored ? applyAuthoredOutboxResult : applyOutboxResult)(result);
  }
  let mobileQueueCounts = {};
  let mobilePreparationItems = {};
  const mobileDeliveryRecovery = createMobileDeliveryRecovery({
    getItems: () => draftInbox.partition(lastDrafts).deliveries,
    getIndex: item => lastDrafts.indexOf(item),
    activate: recoverMobileDelivery,
    beforeOpen: () => selectMobileQueue('draft'),
    onComplete: () => {
      if (!mobileStartDay.completePhase('delivery')) showMobileQueueCompletion('Delivery', true);
    },
  });
  mobileDeliveryRecovery.start();
  function openFiledFollowUp() {
    selectMobileQueue('filed');
    const target = filedFollowUpTarget(completedFiledReview.visible(lastMyWork));
    if (!target) {
      qs('#my-work-action-status').textContent = 'No filed issues are ready to open.';
      return 'empty';
    }
    const index = lastMyWork.indexOf(target.item);
    const trigger = qs('#my-work-list [data-' + target.kind + '-index="' + index + '"]');
    openRoutedWork(target.kind === 'update' ? { ...target.item, kind:'update' } : target.item, trigger);
    return target.kind === 'update' ? 'opened-update' : 'opened-issue';
  }
  const mobileQueueLauncher = createMobileQueueLauncher({
    openDelivery: () => mobileDeliveryRecovery.open(),
    openToday: () => mobileWorkEntry.open(),
    openAgenda: openAgendaSession,
    openUpdates: openUpdateTriage,
    openFiled: openFiledFollowUp,
    selectFilter: selectMobileQueue,
    firstAction: name => qs('#my-work-list .my-work-card-main, #my-work-list .draft-resume, #my-work-list .draft-continue, #my-work-list .draft-edit'),
    announce: announceWork,
    getCounts: () => mobileQueueCounts,
    openFindWork: () => qs('#find-work').click(),
  });
  function openMobileStartDay() {
    const state = mobileStartDay.state();
    mobileStartDay.render();
    qs('#mobile-queue-heading').textContent = state.active ? 'Resume Prepare Today' : 'Prepare Today';
    const sheet = qs('#mobile-queue-sheet');
    if (!sheet.open) qs('#mobile-queue-sheet').showModal();
    qs('#mobile-start-day-action').focus();
  }
  const mobileFirstTask = createMobileFirstTask({
    getLogin: () => confirmedOwnerLogin,
    hasWork: () => todayMyWork.length > 0 || activeMyWork.length > 0,
    isTodayActive: () => workSession.checkpointed(),
  });
  mobileFirstTask.start();
  const mobileWorkEntry = createMobileWorkEntry({
    isTodayActive: () => workSession.checkpointed(),
    isTodayResumable: () => workSession.resumable(),
    getTodayCount: () => todayMyWork.length,
    getEligibleCount: () => activeMyWork.length,
    getPreparationState: () => mobileStartDay.state(),
    queueLauncher: mobileQueueLauncher,
    continueToday: continueTodaySession,
    resumeToday: resumeTodaySession,
    startToday: startTodaySession,
    planToday: () => openPlanToday(mobileTaskButtons.work),
    prepareToday: openMobileStartDay,
    shouldActivate: () => mobileFirstTask.required(),
    openActivation: () => mobileFirstTask.open(),
    findWork: () => qs('#find-work').click(),
  });
  const mobileStartDay = createMobileStartDay({
    getCounts: () => mobileQueueCounts,
    getPhaseItems: () => mobilePreparationItems,
    getLogin: () => confirmedOwnerLogin,
    openQueue: name => {
      const sheet = qs('#mobile-queue-sheet');
      if (sheet.open) sheet.close();
      return name === 'find' ? qs('#find-work').click() : mobileQueueLauncher.open(name);
    },
    onHandoff: current => {
      qs('#mobile-queue-heading').textContent = 'Prepare Today · ' + current.label;
      const sheet = qs('#mobile-queue-sheet');
      if (!sheet.open) sheet.showModal();
      qs('#mobile-start-day-action').focus();
    },
    elements: {
      summary: qs('#mobile-start-day-summary'),
      phases: qs('#mobile-start-day-phases'),
      action: qs('#mobile-start-day-action'),
      finish: qs('#finish-mobile-start-day'),
    },
  });
  mobileStartDay.start();
  qs('#finish-mobile-start-day').addEventListener('click', () => mobileStartDay.finish());
  function showMobileQueueCompletion(completedName, cleared = true, phase = '') {
    if (cleared && phase && mobileStartDay.completePhase(phase)) return;
    mobileStartDay.render();
    const next = mobileQueueLauncher.recommend();
    qs('#mobile-queue-heading').textContent = completedName + (cleared ? ' cleared' : '');
    document.querySelectorAll('[data-mobile-queue]').forEach(row => row.removeAttribute('data-recommended'));
    const row = qs('[data-mobile-queue="' + next.name + '"]');
    row.setAttribute('data-recommended', 'true');
    qs('#mobile-queue-sheet').showModal();
    row.focus();
  }
  let keptUpdateIdentities = [];
  function showUpdateTriageOutcome(outcome) {
    const box = qs('#mobile-update-outcome');
    const review = qs('#review-kept-updates');
    keptUpdateIdentities = outcome.keptIdentities;
    box.hidden = false;
    qs('#mobile-update-outcome-summary').textContent = outcome.reviewed + ' reviewed · ' + outcome.resolved +
      ' marked read · ' + outcome.kept + ' kept unread';
    review.hidden = !outcome.kept;
    review.textContent = 'Review ' + outcome.kept + ' kept unread';
    if (!outcome.kept && mobileStartDay.completePhase('update')) return;
    showMobileQueueCompletion(outcome.kept ? 'Updates reviewed' : 'Updates', !outcome.kept);
    if (outcome.kept) review.focus();
  }
  const mobileTaskDock = createMobileTaskDock({
    nav: qs('#mobile-task-dock'),
    sessionHud: qs('[data-mobile-today-hud]'),
    buttons: mobileTaskButtons,
    workLabel: qs('#mobile-work-label'),
    queueSheet: qs('#mobile-queue-sheet'),
    queueClose: qs('#close-mobile-queues'),
    queueRows: Object.fromEntries(
      Array.from(document.querySelectorAll('[data-mobile-queue]')).map(button => [button.dataset.mobileQueue, button])
    ),
    queueCounts: Object.fromEntries(
      Array.from(document.querySelectorAll('[data-mobile-queue-count]')).map(element => [element.dataset.mobileQueueCount, element])
    ),
    queueBadge: qs('#mobile-queue-count'),
    deadlineBadge: qs('#mobile-deadline-count'),
    onSelectQueue:(name, row) => name === 'recaps' ? qs('#open-today-recaps').click() :
      name === 'find' ? qs('#find-work').click() :
      name === 'week' ? openWeekPlanner(row) :
      name === 'tomorrow' ? openTomorrowPlanner(row) : mobileQueueLauncher.open(name),
    detour:() => timerView,
    overlays: mobileTaskOverlays,
    actions: {
      work: () => mobileWorkEntry.open(),
      find: () => qs('#find-work').click(),
      new: () => qs('#new-issue').click(),
      search: () => qs('#open-palette').click(),
      queues: () => refreshTomorrowQueueSummary(),
    },
    observe(callback, overlays) {
      const observer = new MutationObserver(callback);
      overlays.forEach(overlay => observer.observe(overlay, {attributes:true, attributeFilter:['class']}));
      return observer;
    },
  });
  mobileTaskDock.start();
  const mobileTodayActions = qs('#mobile-today-actions');
  createMobileTodayCommandBar({
    more:qs('[data-mobile-today-more]'),
    sheet:mobileTodayActions,
    close:qs('[data-mobile-today-actions-close]'),
    firstAction:qs('[data-work-session-previous]', mobileTodayActions),
    actionButtons:Array.from(mobileTodayActions.querySelectorAll(
      '[data-work-session-previous], [data-work-session-next], [data-mobile-today-update], [data-mobile-today-blocked], [data-today-break-open], [data-work-session-adjust-plan]'
    )),
    endAction:qs('[data-mobile-today-end]', mobileTodayActions),
    existingEndControl:qs('#end-today-session'),
    hud:qs('[data-mobile-today-hud]'),
    dock:qs('#mobile-task-dock'),
    style:document.documentElement.style,
  });
  const mobileInsights = createMobileInsights({
    root: qs('#insights-sheet'),
    launcher: qs('#open-insights'),
    closeButton: qs('#close-insights'),

    dock: qs('#mobile-task-dock'),
    hud: qs('[data-mobile-today-hud]'),
    backgrounds: [qs('header'), qs('#my-work')],
    history: window.history,
    mediaQuery: window.matchMedia('(max-width: 600px)'),
    detour:() => timerView,
  });
  qs('#empty-work-find').addEventListener('click', () => qs('#find-work').click());
  qs('#empty-work-create').addEventListener('click', () => qs('#new-issue').click());
  let liveMode = true;
  let offlineWorkMode = false;
  const WORK_FILTER_KEY = 'stackchain.my-work-filter.v1';
  const WORK_MILESTONE_KEY = 'stackchain.my-work-milestone.v1';
  let selectedWorkFilter = 'all';
  let selectedFiledView = 'needs-review';
  let selectedWorkMilestone = 'all';
  let queueFindQuery = '';
  let savedWorkFilter = null;
  let launchFilterResolved = false;
  try {
    const savedFilter = sessionStorage.getItem(WORK_FILTER_KEY);
    if (['all', 'today', 'agenda', 'attention', 'filed', 'issue', 'pull', 'review', 'update', 'later', 'draft'].includes(savedFilter)) {
      selectedWorkFilter = savedFilter;
      savedWorkFilter = savedFilter;
      launchFilterResolved = true;
    }
    const savedMilestone = sessionStorage.getItem(WORK_MILESTONE_KEY);
    if (savedMilestone) selectedWorkMilestone = savedMilestone;
  } catch (e) {}
  let lastMyWork = [];
  let lastDrafts = [];
  let lastNotifications = [];
  let lastContextSnapshot = null;
  let notificationPagination = { page: 1, total: 0, has_more: false };
  let workPagination = {};
  let agendaChecking = false;
  let agendaReplan = null;
  let hasContextSnapshot = false;
  let selectedReview = null;
  let reviewTrigger = null;
  let offlineReview = false;
  let selectedUpdate = null;
  let selectedUpdateDetail = null;
  let followUpSourceUpdate = null;
  let updateTrigger = null;
  let selectedIssue = null;
  let selectedIssueOffline = false;
  let selectedIssueDetail = null;
  let delegatedParentReview = null;
  let dismissedChecklistBody = null;

  let issueBlockerCandidates = [];
  let issueBlockerSearchTimer = null;
  let issueConversation = null;
  let issueTrigger = null;
  let issueEditHistoryActive = false;
  let selectedPull = null;
  let pullTrigger = null;
  let selectedPullDetail = null;
  let pullConversation = null;
  let pullReviewState = null;
  let creatingIssue = false;
  let createAndStartRequested = false;
  let pendingIssueFilingIntent = 'create-and-assign';
  let findingWork = false;
  let availablePagination = { page: 1, total: 0, has_more: false };
  let progress = null;
  let draft = null;
  let reviewFiles = [];
  let selectedReviewHead = '';
  let reviewHandoffSubmitted = false;
  let activeInlineTarget = null;
  let bulkConfirmationPending = false;
  let bulkMarkPending = false;
  let reviewHandoffPending = false;
  let editingOutboxId = null;
  let confirmedOwnerLogin = '';
  let planningOwnerLogin = '';
  let activeFlushLogin = '';
  let releaseReceipt = null;
  function attachReleaseReceipt() {
    if (releaseReceipt) return releaseReceipt;
    releaseReceipt = createReleaseReceipt({
      storage:localStorage, getLogin:()=>confirmedOwnerLogin, fetchJson:fetchReviewJson,
      launcher:qs('#release-receipt-launcher'), dialog:qs('#release-receipt-sheet'),
      statusNode:qs('#release-receipt-status'), checksNode:qs('#release-receipt-checks'),
      releaseNode:qs('#release-receipt-link'),
      listNode:qs('#release-watchlist'),
    });
    releaseReceipt.bind();
    qs('#close-release-receipt').addEventListener('click', () => qs('#release-receipt-sheet').close());
    qs('#refresh-release-receipt').addEventListener('click', () => releaseReceipt.refresh().catch(error => {
      qs('#release-receipt-status').textContent = error.message + ' Retry when connected.';
    }));
    qs('#dismiss-release-receipt').addEventListener('click', () => releaseReceipt.dismiss());
    return releaseReceipt;
  }
  const completedFiledReview = createCompletedFiledReview({
    storage: localStorage,
    getLogin() { return planningOwnerLogin; },
  });
  const filedHistoryTabs = createFiledHistoryTabs({
    root:qs('#filed-history-tabs'), review:completedFiledReview,
    onSelect:view => { selectedFiledView = view; renderMyWork(); },
  });
  let completedFiledSyncFlight = null;
  let activeMyWork = [];
  let laterMyWork = [];
  let todayMyWork = [];
  let rolloverReviewPlan = null;
  const outboxCoordinator = createOutboxCoordinator({ storage: localStorage });
  const todayRollover = createTodayRollover();
  let planningTomorrow = false;
  let latestTodayPlan = null;

  const tomorrowPlan = createTomorrowPlan({
    fetchJson:fetchReviewJson,
    localDate:todayRollover.localDate,
    timeZone:todayRollover.timeZone,
    storage:localStorage,
    getLogin:() => planningOwnerLogin,
  });
  const weekPlan = createWeekPlan({
    fetchJson:fetchReviewJson,localDate:todayRollover.localDate,timeZone:todayRollover.timeZone,
    storage:localStorage,getLogin:() => planningOwnerLogin,
  });
  function openWeekPlanner(trigger) { planningTomorrow=false; return weekWorkflow.open(trigger); }
  function renderTomorrowQueueSummary(value) {
    qs('#mobile-tomorrow-summary').textContent = value ? tomorrowPlan.summary(value) : tomorrowPlan.summary();
  }
  function syncPendingTomorrow() {
    if (!tomorrowPlan.pending()) return Promise.resolve(false);
    return tomorrowPlan.flush().then(saved => {
      renderTomorrowQueueSummary(saved);
      qs('#my-work-action-status').textContent = saved.ids.length ?
        `Tomorrow saved for ${saved.plan_date} without changing Today.` :
        `Tomorrow cleared for ${saved.plan_date}.`;
      return saved;
    }).catch(error => {
      const conflict = tomorrowPlan.conflict();
      if (conflict) renderTomorrowQueueSummary({ids:[],sync_pending:false,conflict:true});
      qs('#mobile-tomorrow-summary').textContent = conflict ? 'Conflict · review required' : qs('#mobile-tomorrow-summary').textContent;
      qs('#my-work-action-status').textContent = conflict ?
        'Another device changed Tomorrow. Both plans are preserved; open Tomorrow to choose one.' :
        `${error.message || 'Tomorrow sync is unavailable.'} Saved on this phone · sync pending.`;
      return false;
    });
  }
  async function refreshTomorrowQueueSummary() {
    try {
      const loaded = await tomorrowPlan.load();
      if (tomorrowPlan.conflict()) qs('#mobile-tomorrow-summary').textContent = 'Conflict · review required';
      else renderTomorrowQueueSummary(loaded);
      return true;
    } catch (_error) {
      qs('#mobile-tomorrow-summary').textContent = 'Unavailable · tap to retry';
      return false;
    }
  }
  async function openTomorrowPlanner(trigger) {
    if (!planningOwnerLogin) {
      qs('#my-work-action-status').textContent = 'Planning is unavailable until your operator identity is restored.';
      return false;
    }
    trigger.disabled = true;
    qs('#mobile-tomorrow-summary').textContent = 'Loading Tomorrow…';
    try {
      const loaded = await tomorrowPlan.load();
      renderTomorrowQueueSummary(loaded);
      planningTomorrow = true;
      openPlanToday(trigger);
      qs('#my-work-action-status').textContent = '';
      return true;
    } catch (error) {
      qs('#mobile-tomorrow-summary').textContent = 'Unavailable · tap to retry';
      qs('#my-work-action-status').textContent = `${error.message || 'Tomorrow is unavailable.'} Retry when connected.`;
      return false;
    } finally {
      trigger.disabled = false;
    }
  }
  const todayWork = createTodayWork({
    storage: localStorage,
    getLogin: () => planningOwnerLogin,
  });
  const weekWorkflow=createWeekPlanWorkflow({controller:weekPlan,qs,getLogin:()=>planningOwnerLogin,
    openPlanner:openPlanToday,escapeHtml,escapeAttribute:escAttr,todayWork,
    refresh:refreshMyWorkView,warm:warmTodayOffline});
  const todaySync = createTodaySync({
    storage: localStorage,
    getLogin: () => planningOwnerLogin,
    fetchJson: fetchReviewJson,
    coordinator: outboxCoordinator,
    onRemoteIds: ids => {
      if (!planningOwnerLogin || !todayWork.replace(ids)) return;
      refreshMyWorkView();
      warmTodayOffline();
    },
    onRemotePlan: plan => {
      if (!planningOwnerLogin) return;
      latestTodayPlan = plan;
      const startDayLaunch = window.location.hash === '#/my-work/start-day';
      weekWorkflow.promote(plan).finally(() => {
        if (!startDayLaunch) return;
        window.history.replaceState({}, '', '#/my-work/today');
        openMobileStartDay();
      });
      todayWork.replacePlanning({
        capacity_minutes: plan.capacity_minutes ?? null,
        estimates: plan.estimates || {},
      });
      const reviewState = todayRollover.reviewState(plan);
      if (!['stale', 'legacy'].includes(reviewState)) {
        rolloverReviewPlan = null;
        qs('#plan-today').textContent = 'Plan Today';
        return;
      }
      rolloverReviewPlan = plan;
      qs('#plan-today').textContent = 'Review new day';
      qs('#my-work-action-status').textContent = 'Review yesterday’s unfinished work before starting today.';
      const marker = `stackchain.today-rollover-reviewed.v1.${encodeURIComponent(planningOwnerLogin)}.${todayRollover.localDate()}`;
      if (!localStorage.getItem(marker)) {
        localStorage.setItem(marker, '1');
        setTimeout(() => {
          if (!workSession.checkpointed()) openPlanToday(qs('#plan-today'));
        }, 0);
      }
    },
    onStatus: (state, detail = {}) => {
      const status = qs('#today-sync-status');
      status.textContent = state === 'saved' ? 'Today saved to account.' :
        (state === 'recovered' ? `Today queue recovered · discarded ${detail.discarded} unreadable device record${detail.discarded === 1 ? '' : 's'}.` :
          (state === 'retrying' ? `Today saved on this device · retrying in ${Math.ceil(detail.delayMs / 1000)}s.` :
            (state === 'pending' ? 'Today saved on this device · sync pending.' :
              (state === 'full' ? 'Another device filled Today · showing its saved plan.' :
                (state === 'expired' ? `Today edit expired after 30 days offline${detail.count > 1 ? 's' : ''} · account plan kept.` :
                  'Today sync unavailable · changes stay on this device.')))));
    },
  });
  todaySync.startLifecycle({ window, document });
  tomorrowPlan.startLifecycle({
    windowObject:window,
    documentObject:document,
    check:() => Promise.all([
      syncPendingTomorrow(),
      weekPlan.pending() ? weekPlan.flush().catch(() => false) : false,
      latestTodayPlan ? weekWorkflow.promote(latestTodayPlan) : false,
    ]),
  });
  const todayHandoff = createTodayHandoff({
    storage:localStorage,
    getLogin:() => planningOwnerLogin,
    identity:item => todayWork.identity(item),
    items:() => [...todayMyWork, ...activeMyWork],
    todayWork,
    todaySync,
  });
  const todayHandoffView = todayHandoff.mount({ qs, escapeHtml,
    onComplete:() => refreshMyWorkView(),
  });
  const promptTodayHandoff = () => todayHandoffView.open();
  const laterWork = createLaterWork({
    storage: localStorage,
    getLogin: () => planningOwnerLogin,
    onChange: (action, itemId, wakeAt, handoff) => {
      if (laterSync.enqueue(action, itemId, wakeAt, handoff)) laterSync.flush();
    },
    onExpire: (ids, handoffs) => {
      if (handoffs.length) {
        todayHandoff.capture(handoffs);
        todayHandoffView.reset();
      }
      const queued = ids.map(id => laterSync.enqueue('restore', id)).every(Boolean);
      if (queued) laterSync.flush();
    },
    onWake: () => {
      qs('#my-work-action-status').textContent = 'Deferred work is ready again.';
      refreshMyWorkView();
      setTimeout(promptTodayHandoff, 0);
    },
  });
  const laterSync = createLaterSync({
    storage: localStorage,
    getLogin: () => planningOwnerLogin,
    fetchJson: fetchReviewJson,
    coordinator: outboxCoordinator,
    onRemoteRecords: records => {
      if (!planningOwnerLogin || !laterWork.adopt(records)) return;
      refreshMyWorkView();
    },
    onStatus: (state, detail = {}) => {
      qs('#later-sync-status').textContent = state === 'saved' ? 'Later saved to account.' :
        (state === 'conflict' ? `Another device changed this Later item${detail.count > 1 ? 's' : ''} · account plan kept.` :
          (state === 'retrying' ? `Later saved on this device · retrying in ${Math.ceil(detail.delayMs / 1000)}s.` :
            (state === 'pending' ? 'Later saved on this device · sync pending.' :
              (state === 'expired' ? `Later edit expired after 30 days offline${detail.count > 1 ? 's' : ''} · account plan kept.` :
                'Later sync unavailable · changes stay on this device.'))));
    },
  });
  laterSync.startLifecycle({ window, document });
  document.addEventListener('visibilitychange', () => {
    if (document.hidden) interruptionPrompt.background();
    else interruptionPrompt.foreground();
    if (!document.hidden) {
      refreshMyWorkView();
      if (updateTriage.active()) updateTriage.reconcile();
    }
  });

  async function fetchReviewJson(url, options) {
    const response = await fetch(url, options);
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) {
      const error = new Error(payload.error || payload.detail?.message || payload.detail || 'Review request failed.');
      error.status = response.status;

      error.code = payload.detail?.code;
      const retryAfter = response.headers.get('Retry-After');
      error.retryAfter = retryAfter === null ? undefined : Number(retryAfter);
      throw error;
    }
    return payload;
  }

  function syncCompletedFiledReviews() {
    if (!planningOwnerLogin) return Promise.resolve(false);
    if (completedFiledSyncFlight) return completedFiledSyncFlight;
    const pending = completedFiledReview.pending();
    const options = pending.length ? {
      method:'POST',
      headers:{Accept:'application/json', 'Content-Type':'application/json'},
      body:JSON.stringify({ receipts:pending }),
    } : { headers:{Accept:'application/json'} };
    completedFiledSyncFlight = fetchReviewJson('api/v1/completed-filed-reviews', options)
      .then(snapshot => {
        const changed = completedFiledReview.adopt(snapshot);
        if (lastContextSnapshot && changed) {
          lastMyWork = buildMyWork(lastContextSnapshot);
          refreshMyWorkView();
        }
        if (pending.length) qs('#my-work-action-status').textContent =
          'Completed Filed review saved to account.';
        return true;
      })
      .catch(() => {
        if (pending.length) qs('#my-work-action-status').textContent =
          'Acknowledged on this device · sync pending.';
        return false;
      })
      .finally(() => { completedFiledSyncFlight = null; });
    return completedFiledSyncFlight;
  }

  let commentActions = { isOwned: () => false, wire: () => {} };

  function loadMentionCandidates(repository, query) {
    return fetchReviewJson(
      'api/v1/repos/' + repository + '/mention-candidates?q=' + encodeURIComponent(query),
      {headers:{Accept:'application/json'}},
    );
  }
  const [issueMentions, pullMentions, updateMentions, todayProgressMentions] = [
    ['issue-comment',()=>selectedIssue?.repository],
    ['pull-comment',()=>selectedPull?.repository],
    ['update-reply',()=>selectedUpdate?.repository],
    ['today-progress-body',()=>currentTodayProgressTarget()?.repository],
  ].map(([id,getRepository]) => {
    const controller = createMentionComposer({
      textarea:qs('#'+id), listbox:qs('#'+id+'-mentions'),
      status:qs('#'+id+'-mention-status'), getRepository, loadCandidates:loadMentionCandidates,
    });
    controller.start();
    return controller;
  });

  async function api(url) {
    const response = await fetch(url, { headers: { Accept: 'application/json' } });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) {
      const error = new Error(payload.error || payload.detail || 'Shared work request failed.');
      error.unavailable = response.status === 404;
      throw error;
    }
    return payload;
  }
  let reviewController = null;
  let wrapPreference = null;
  const issueController = createIssueSheet({
    fetchJson: fetchReviewJson,
    storage: localStorage,
    enqueueDurably:message => authoredOutbox.enqueueDurably(message),
  });
  function overdueAgendaItems() {
    return agendaMyWork(activeMyWork).filter(item => item.agenda_group === 'Overdue');
  }
  function renderAgendaReplan() {
    const state = agendaReplan.snapshot();
    qs('#agenda-replan-controls').hidden = !state.active;
    if (!state.active) return;
    qs('#agenda-replan-progress').textContent =
      'Overdue deadline ' + (state.index + 1) + ' of ' + state.total + ' · ' + (agendaReplan.current()?.key || '');
  }
  function openAgendaReplanCurrent() {
    const item = agendaReplan.current();
    if (!item) {
      closeIssueSheet(false);
      renderAgendaReplan();
      qs('#my-work-action-status').textContent = 'Overdue sweep complete. Agenda updated.';
      return;
    }
    renderAgendaReplan();
    openIssueSheet(item, qs('#start-agenda-replan'));
  }
  agendaReplan = createAgendaReplan({
    update: async (item, dueDate) => {
      const confirmed = await issueController.updateDueDate(item, dueDate);
      lastContextSnapshot = buildMyWork.replaceIssueDueDate(
        lastContextSnapshot, item.repository, item.number, confirmed.due_date
      );
      paintMyWork(lastContextSnapshot);
      return confirmed;
    },
  });
  qs('#start-agenda-replan').addEventListener('click', () => {
    const overdue = overdueAgendaItems();
    agendaReplan.start(overdue);
    openAgendaReplanCurrent();
  });
  async function runAgendaReplan(action) {
    const result = await action();
    if (!result.ok) {
      qs('#agenda-replan-progress').textContent = result.error + ' Current deadline retained; retry.';
      return;
    }
    openAgendaReplanCurrent();
  }
  qs('#agenda-replan-keep').addEventListener('click', () => runAgendaReplan(() => agendaReplan.keep()));
  qs('#agenda-replan-tomorrow').addEventListener('click', () => runAgendaReplan(() => agendaReplan.tomorrow()));
  qs('#agenda-replan-choose').addEventListener('click', () =>
    runAgendaReplan(() => agendaReplan.choose(qs('#agenda-replan-date').value))
  );
  qs('#agenda-replan-cancel').addEventListener('click', () => {
    agendaReplan.cancel();
    closeIssueSheet(false);
    renderAgendaReplan();
    window.location.hash = '#/my-work/agenda';
    qs('#my-work-action-status').textContent = 'Overdue sweep cancelled. No remaining deadline was changed.';
  });

  StackchainAgendaCalendar.mountAgendaCalendarExport({
    qs,
    getItems:() => agendaMyWork(activeMyWork),
    escapeHtml,
    onDone:result => {
      qs('#my-work-action-status').textContent = result === 'shared' ?
        'Agenda calendar snapshot shared.' : 'Agenda calendar snapshot downloaded.';
    },
  });
  let searchReplyAttachmentTarget = null;
  let searchReplyRestoreGeneration = 0;
  let restoringSearchReplyPhotos = false;
  const searchReplyDraftStore = 'indexedDB' in window ? createSearchReplyDraftStore({
    indexedDB:window.indexedDB,
    getOwnerLogin:() => confirmedOwnerLogin,
  }) : null;
  const sameSearchReplyTarget = (left, right) => left && right && left.kind === right.kind &&
    left.repository === right.repository && Number(left.number) === Number(right.number);
  async function persistSearchReplyPhotos() {
    const target = searchReplyAttachmentTarget ? { ...searchReplyAttachmentTarget } : null;
    if (!target || !searchReplyDraftStore || !searchReplyAttachmentController || restoringSearchReplyPhotos) return;
    try {
      const attachments = await searchReplyAttachmentController.serialize();
      await searchReplyDraftStore.save(target, attachments);
    } catch (error) {
      qs('#search-preview-reply-status').textContent = error?.message ||
        'Photos could not be saved. They remain in this preview; retry before leaving.';
      throw error;
    }
  }
  async function restoreSearchReplyPhotos(target) {
    if (!searchReplyDraftStore || !target) return;
    const generation = ++searchReplyRestoreGeneration;
    try {
      const attachments = await searchReplyDraftStore.load(target);
      if (generation !== searchReplyRestoreGeneration || !sameSearchReplyTarget(target, searchReplyAttachmentTarget)) return;
      if (attachments?.length) {
        restoringSearchReplyPhotos = true;
        try { searchReplyAttachmentController.restore(attachments); }
        finally { restoringSearchReplyPhotos = false; }
        updateSearchReplyButtons(searchReplyAttachmentController.state());
        qs('#search-preview-reply-status').textContent = 'Saved photo evidence restored.';
      }
    } catch (error) {
      if (generation === searchReplyRestoreGeneration) {
        qs('#search-preview-reply-status').textContent = error?.message || 'Saved photo evidence could not be restored.';
      }
    }
  }
  const updateSearchReplyButtons = state => {
    const enabled = Boolean(state) || Boolean(qs('#search-preview-reply').value.trim());
    qs('#send-search-preview-reply').disabled = !enabled;
    qs('#send-search-preview-reply-next').disabled = !enabled;
  };
  const searchReplyAttachmentController = issueAttachment.mount({
    maxFiles: 5,
    input: qs('#search-reply-attachment'),
    inputs: [qs('#take-search-reply-photo'), qs('#search-reply-attachment')],
    preview: qs('#search-reply-attachment-preview'),
    image: qs('#search-reply-attachment-image'),
    meta: qs('#search-reply-attachment-meta'),
    remove: qs('#remove-search-reply-attachment'),
    tray: qs('#search-reply-attachment-tray'),
    earlier: qs('#move-search-reply-attachment-earlier'),
    later: qs('#move-search-reply-attachment-later'),
    note: qs('#search-reply-attachment-note'),
    noteLabel: qs('#search-reply-attachment-note-label'),
    status: qs('#search-preview-reply-status'),
    readyMessage: 'Photo ready to send with this Search reply.',
    removedMessage: 'Photo removed. Your Search reply is unchanged.',
    onChange: state => {
      updateSearchReplyButtons(state);
      persistSearchReplyPhotos().catch(() => {});
    },
    onCheckpoint:() => persistSearchReplyPhotos(),
    editor: {
      document,
      edit: qs('#edit-search-reply-attachment'),
      dialog: qs('#issue-evidence-editor'),
      canvas: qs('#issue-evidence-editor-canvas'),
      exportCanvas: qs('#issue-evidence-editor-export'),
      crop: qs('#crop-issue-evidence'), redact: qs('#redact-issue-evidence'),
      highlight: qs('#highlight-issue-evidence'), arrow: qs('#arrow-issue-evidence'),
      undo: qs('#undo-issue-evidence-edit'), reset: qs('#reset-issue-evidence-edit'),
      cancel: qs('#cancel-issue-evidence-edit'), apply: qs('#apply-issue-evidence-edit'),
      status: qs('#issue-evidence-editor-status'),
      appliedMessage: 'Edited photo flattened and ready to send.',
    },
    createObjectURL: file => URL.createObjectURL(file),
    revokeObjectURL: url => URL.revokeObjectURL(url),
    upload: payload => {
      const target = searchReplyAttachmentTarget;
      if (!target || target.repository !== payload.repository || Number(target.number) !== Number(payload.number)) {
        return Promise.reject(new Error('Search result changed. Reopen it before sending this photo.'));
      }
      const repository = payload.repository.split('/').map(encodeURIComponent).join('/');
      return fetchReviewJson(
        'api/v1/repos/' + repository + '/issues/' + encodeURIComponent(payload.number) +
          '/preview/attachments?kind=' + encodeURIComponent(target.kind),
        {
          method:'POST',
          headers:{Accept:'application/json','Idempotency-Key':payload.operation_id},
          body:issueAttachment.multipart(payload),
        },
      );
    },
  });
  const issueAttachmentController = issueAttachment.mount({
    maxFiles: 5,
    input: qs('#issue-attachment'),
    inputs: [qs('#take-issue-comment-photo'), qs('#issue-attachment')],
    preview: qs('#issue-attachment-preview'),
    image: qs('#issue-attachment-image'),
    meta: qs('#issue-attachment-meta'),
    remove: qs('#remove-issue-attachment'),
    tray: qs('#issue-attachment-tray'),
    earlier: qs('#move-issue-attachment-earlier'),
    later: qs('#move-issue-attachment-later'),
    note: qs('#issue-attachment-note'),
    noteLabel: qs('#issue-attachment-note-label'),
    status: qs('#issue-comment-status'),
    onChange:() => conversationPhotoDrafts.checkpoint('issue').catch(() => {}),
    onCheckpoint:() => conversationPhotoDrafts.checkpoint('issue'),
    editor: {
      document,
      edit: qs('#edit-issue-attachment'),
      dialog: qs('#issue-evidence-editor'),
      canvas: qs('#issue-evidence-editor-canvas'),
      exportCanvas: qs('#issue-evidence-editor-export'),
      crop: qs('#crop-issue-evidence'), redact: qs('#redact-issue-evidence'),
      highlight: qs('#highlight-issue-evidence'), arrow: qs('#arrow-issue-evidence'),
      undo: qs('#undo-issue-evidence-edit'), reset: qs('#reset-issue-evidence-edit'),
      cancel: qs('#cancel-issue-evidence-edit'), apply: qs('#apply-issue-evidence-edit'),
      status: qs('#issue-evidence-editor-status'),
      appliedMessage: 'Edited photo flattened and ready to send.',
    },
    createObjectURL: file => URL.createObjectURL(file),
    revokeObjectURL: url => URL.revokeObjectURL(url),
    readDataUrl: file => new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.onerror = () => reject(new Error('The screenshot could not be read. Choose it again.'));
      reader.readAsDataURL(file);
    }),
    upload: payload => {
      const repository = payload.repository.split('/').map(encodeURIComponent).join('/');
      return fetchReviewJson(
        'api/v1/repos/' + repository + '/issues/' + encodeURIComponent(payload.number) + '/attachments',
        {
          method: 'POST',
          headers: {
            Accept: 'application/json',
            'Idempotency-Key': payload.operation_id,
          },
          body: issueAttachment.multipart(payload),
        },
      );
    },
  });
  const pullAttachmentController = issueAttachment.mount({
    maxFiles: 5,
    input: qs('#pull-attachment'),
    inputs: [qs('#take-pull-comment-photo'), qs('#pull-attachment')],
    preview: qs('#pull-attachment-preview'),
    image: qs('#pull-attachment-image'),
    meta: qs('#pull-attachment-meta'),
    remove: qs('#remove-pull-attachment'),
    tray: qs('#pull-attachment-tray'),
    earlier: qs('#move-pull-attachment-earlier'),
    later: qs('#move-pull-attachment-later'),
    note: qs('#pull-attachment-note'),
    noteLabel: qs('#pull-attachment-note-label'),
    status: qs('#pull-comment-status'),
    onChange:() => conversationPhotoDrafts.checkpoint('pull').catch(() => {}),
    onCheckpoint:() => conversationPhotoDrafts.checkpoint('pull'),
    editor: {
      document,
      edit: qs('#edit-pull-attachment'),
      dialog: qs('#issue-evidence-editor'),
      canvas: qs('#issue-evidence-editor-canvas'),
      exportCanvas: qs('#issue-evidence-editor-export'),
      crop: qs('#crop-issue-evidence'), redact: qs('#redact-issue-evidence'),
      highlight: qs('#highlight-issue-evidence'), arrow: qs('#arrow-issue-evidence'),
      undo: qs('#undo-issue-evidence-edit'), reset: qs('#reset-issue-evidence-edit'),
      cancel: qs('#cancel-issue-evidence-edit'), apply: qs('#apply-issue-evidence-edit'),
      status: qs('#issue-evidence-editor-status'),
      appliedMessage: 'Edited photo flattened and ready to send.',
    },
    createObjectURL: file => URL.createObjectURL(file),
    revokeObjectURL: url => URL.revokeObjectURL(url),
    upload: payload => {
      const repository = payload.repository.split('/').map(encodeURIComponent).join('/');
      return fetchReviewJson(
        'api/v1/repos/' + repository + '/pulls/' + encodeURIComponent(payload.number) + '/attachments',
        {
          method: 'POST',
          headers: { Accept:'application/json', 'Idempotency-Key':payload.operation_id },
          body: issueAttachment.multipart(payload),
        },
      );
    },
  });
  const updateReplyAttachmentController = issueAttachment.mount({
    maxFiles: 5,
    input: qs('#update-reply-attachment'),
    inputs: [qs('#take-update-reply-photo'), qs('#update-reply-attachment')],
    preview: qs('#update-reply-attachment-preview'),
    image: qs('#update-reply-attachment-image'),
    meta: qs('#update-reply-attachment-meta'),
    remove: qs('#remove-update-reply-attachment'),
    tray: qs('#update-reply-attachment-tray'),
    earlier: qs('#move-update-reply-attachment-earlier'),
    later: qs('#move-update-reply-attachment-later'),
    note: qs('#update-reply-attachment-note'),
    noteLabel: qs('#update-reply-attachment-note-label'),
    status: qs('#update-reply-status'),
    onChange:() => conversationPhotoDrafts.checkpoint('update').catch(() => {}),
    onCheckpoint:() => conversationPhotoDrafts.checkpoint('update'),
    readyMessage: 'Screenshot ready to send with this reply.',
    removedMessage: 'Screenshot removed. Your reply is unchanged.',
    editor: {
      document,
      edit: qs('#edit-update-reply-attachment'),
      dialog: qs('#issue-evidence-editor'),
      canvas: qs('#issue-evidence-editor-canvas'),
      exportCanvas: qs('#issue-evidence-editor-export'),
      crop: qs('#crop-issue-evidence'), redact: qs('#redact-issue-evidence'),
      highlight: qs('#highlight-issue-evidence'), arrow: qs('#arrow-issue-evidence'),
      undo: qs('#undo-issue-evidence-edit'), reset: qs('#reset-issue-evidence-edit'),
      cancel: qs('#cancel-issue-evidence-edit'), apply: qs('#apply-issue-evidence-edit'),
      status: qs('#issue-evidence-editor-status'),
      appliedMessage: 'Edited photo flattened and ready to send.',
    },
    createObjectURL: file => URL.createObjectURL(file),
    revokeObjectURL: url => URL.revokeObjectURL(url),
    upload: payload => fetchReviewJson(
      'api/v1/notifications/' + encodeURIComponent(payload.notificationId) + '/attachments',
      { method:'POST', headers:{ Accept:'application/json', 'Idempotency-Key':payload.operation_id },
        body:issueAttachment.multipart(payload) },
    ),
  });
  const conversationPhotoDraftStore = createConversationReplyDraftStore({
    indexedDB:window.indexedDB, getOwnerLogin:() => confirmedOwnerLogin,
  });
  const photoDraftLane = (controller, status) => ({ controller, onError:error => {
    qs(status).textContent = error.message + ' Your photos remain here; retry before leaving.';
  } });
  const conversationPhotoDrafts = createConversationPhotoDrafts({
    store:conversationPhotoDraftStore,
    lanes:{
      issue:photoDraftLane(issueAttachmentController, '#issue-comment-status'),
      pull:photoDraftLane(pullAttachmentController, '#pull-comment-status'),
      update:photoDraftLane(updateReplyAttachmentController, '#update-reply-status'),
    },
  });
  const todayProgressPhotos = createTodayProgressPhotos({
    qs, document, issueAttachment, fetchJson:fetchReviewJson,
    createStore:createConversationReplyDraftStore, createDrafts:createConversationPhotoDrafts,
    getLogin:() => confirmedOwnerLogin,
  });
  const voiceTranscriptStore = createVoiceTranscriptStore();
  const voiceOptions = {
    qs, Recognition:window.SpeechRecognition || window.webkitSpeechRecognition,
    transcriptStore:voiceTranscriptStore, getLogin:() => confirmedOwnerLogin,
  };
  const [issueVoiceReply, pullVoiceReply, updateVoiceReply, searchVoiceReply, todayProgressVoice] = [
    ['issue-comment', '#issue-comment'], ['pull-comment', '#pull-comment'],
    ['update-reply', '#update-reply'], ['search-reply', '#search-preview-reply'],
    ['today-progress', '#today-progress-body'],
  ].map(([kind, draftSelector]) => mountVoiceConversation({...voiceOptions, kind, draftSelector}));
  function conversationVoiceTarget(kind, item) {
    return kind + ':' + String(item?.repository || '').trim().toLowerCase() + '#' + Number(item?.number);
  }
  function searchConversationVoiceTarget(item) {
    return 'search:' + conversationVoiceTarget(item?.kind, item);
  }
  const createIssueAttachmentController = issueAttachment.mount({
    input: qs('#create-issue-attachment'),
    inputs: [qs('#take-create-issue-photo'), qs('#create-issue-attachment')],
    preview: qs('#create-issue-attachment-preview'),
    image: qs('#create-issue-attachment-image'),
    meta: qs('#create-issue-attachment-meta'),
    remove: qs('#remove-create-issue-attachment'),
    tray: qs('#create-issue-evidence-tray'),
    earlier: qs('#move-create-issue-attachment-earlier'),
    later: qs('#move-create-issue-attachment-later'),
    note: qs('#create-issue-evidence-note'),
    noteLabel: qs('#create-issue-evidence-note-label'),
    status: qs('#create-issue-attachment-status'),
    readyMessage: 'Screenshot ready to file with this issue.',
    removedMessage: 'Screenshot removed. Your issue draft is unchanged.',
    editor: {
      document,
      edit: qs('#edit-create-issue-attachment'),
      dialog: qs('#issue-evidence-editor'),
      canvas: qs('#issue-evidence-editor-canvas'),
      exportCanvas: qs('#issue-evidence-editor-export'),
      crop: qs('#crop-issue-evidence'),
      redact: qs('#redact-issue-evidence'),
      highlight: qs('#highlight-issue-evidence'),
      arrow: qs('#arrow-issue-evidence'),
      undo: qs('#undo-issue-evidence-edit'),
      reset: qs('#reset-issue-evidence-edit'),
      cancel: qs('#cancel-issue-evidence-edit'),
      apply: qs('#apply-issue-evidence-edit'),
      status: qs('#issue-evidence-editor-status'),
    },
    createObjectURL: file => URL.createObjectURL(file),
    revokeObjectURL: url => URL.revokeObjectURL(url),
    readDataUrl: file => new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.onerror = () => reject(new Error('The screenshot could not be read. Choose it again.'));
      reader.readAsDataURL(file);
    }),
    upload: async () => { throw new Error('Create the issue before uploading its screenshot.'); },
  });
  const planningLoader = createIssueSheet.createPlanningLoader({
    loadLabels: item => issueController.loadLabels(item),
    loadMilestones: item => issueController.loadMilestones(item),
  });
  let issueCapture = null;
  let checklistPromotion = null;
  let issueOwnerPicker = null;
  let issueTemplatePicker = null;
  let issueFilingMetadata = null;
  let updateFollowUp = null;
  const unfiledAttachmentStore = 'indexedDB' in window ? createUnfiledAttachmentStore() : null;
  const unfiledCaptures = createUnfiledCaptures({
    storage: localStorage,
    attachmentStore: unfiledAttachmentStore,
    getCaptureLogin: () => String(lastContextSnapshot?.user?.login || '').trim(),
    getCurrentLogin: () => activeFlushLogin,
  });
  createUnfiledDraftSync(
    unfiledCaptures, fetchReviewJson
  );
  const dFS = createDraftFilingSession({list:()=>unfiledCaptures.list().filter(item=>!item.quarantined)});
  dFS.attach(qs, {
    captures:unfiledCaptures, capture:()=>issueCapture, attachment:createIssueAttachmentController,
    getLogin:()=>activeFlushLogin, setResumedId:id=>{ rUC = id; },
    openSheet:openCreateIssueSheet, setFilingMode:setIssueFilingMode,
    review:r=>loadIssueFilingMetadata(r.repository,r)
      .then(()=>issueCapture.findDuplicates(currentIssueCaptureDraft())).then(renderIssueDuplicates),
  });
  let rUC = '';
  let backgroundIssueSync = null;
  if ('indexedDB' in window) {
    const backgroundIssueStore = createIssueSyncStore();
    backgroundIssueSync = createBackgroundIssueSync({
      store: backgroundIssueStore, fetchJson: fetchReviewJson,
    });
    backgroundIssueSync.requestSync = async () => {
      if (!('serviceWorker' in navigator)) throw new Error('Background Sync unavailable');
      const registration = await navigator.serviceWorker.ready;
      if (!registration.sync) throw new Error('Background Sync unavailable');
      await registration.sync.register('stackchain-issue-outbox-v1');
    };
  }
  const issueOutbox = createIssueOutbox({
    storage: localStorage, fetchJson: fetchReviewJson, coordinator: outboxCoordinator,
    backgroundSync: backgroundIssueSync,
    getOwnerLogin: () => confirmedOwnerLogin,
  });
  const filingReview = createIssueFilingReview({
    sheet: qs('#issue-filing-review'),
    confirmButton: qs('#confirm-issue-filing'),
    backButton: qs('#back-to-issue-edit'),
    evidenceList: qs('#issue-filing-review-evidence'),
    evidenceEmpty: qs('#issue-filing-review-evidence-empty'),
    evidencePreview: qs('#issue-filing-review-evidence-preview'),
    evidenceImage: qs('#issue-filing-review-evidence-image'),
    evidencePosition: qs('#issue-filing-review-evidence-position'),
    evidenceFilename: qs('#issue-filing-review-evidence-filename'),
    evidenceNote: qs('#issue-filing-review-evidence-note'),
    repository: qs('#issue-filing-review-repository'),
    intent: qs('#issue-filing-review-intent'),
    issueType: qs('#issue-filing-review-template'),
    title: qs('#issue-filing-review-title'),
    body: qs('#issue-filing-review-body'),
    metadata: qs('#issue-filing-review-metadata'),
    blockerList: qs('#issue-filing-review-blockers'),
    status: qs('#issue-filing-review-status'),
    document,
    createObjectURL: blob => URL.createObjectURL(blob),
    revokeObjectURL: url => URL.revokeObjectURL(url),
    onConfirm: admitReviewedIssue,
  });
  const authoredOutbox = createAuthoredOutbox({
    storage: localStorage, fetchJson: fetchReviewJson, coordinator: outboxCoordinator,
    backgroundSync: backgroundIssueSync,
    getOwnerLogin: () => confirmedOwnerLogin,
    mergeChecklistConflict: mergeChecklistConflict,
  });
  const todayProgress = createTodayProgress({
    storage:localStorage,
    getLogin:() => confirmedOwnerLogin,
    admit:message => authoredOutbox.enqueueDurably(message),
  });
  const queueOfflineIssueBlocker = createOfflineIssueBlocker({
    enqueueDurably: message => authoredOutbox.enqueueDurably(message),
  });
  const notificationReadOutbox = createNotificationReadOutbox({
    storage: localStorage, fetchJson: fetchReviewJson, coordinator: outboxCoordinator,
    backgroundSync: backgroundIssueSync,
    getOwnerLogin: () => confirmedOwnerLogin,
  });
  if (backgroundIssueSync) {
    backgroundIssueSync.snapshot().then(records => {
      issueOutbox.reconcileBackground(records);
      authoredOutbox.reconcileBackground(records);
      notificationReadOutbox.reconcileBackground(records);
    }).catch(() => {});
  }
  const shareParams = new URLSearchParams(location.search);
  const appShortcut = mobileAppShortcuts.createController({
    search: location.search,
    continueWork: () => mobileWorkEntry.open(),
    newIssue: () => openCreateIssueSheet(),
    agenda: () => openAgendaSession(),
  });
  const sharedLaunch = {
    title: shareParams.get('title') || '',
    text: shareParams.get('text') || '',
    url: shareParams.get('url') || '',
  };
  const sharedImageMarker = shareParams.get('shared') || '';
  let sharedImageHandled = false;
  const commentActionFeatures = createFeatureLoader({
    document,
    urls: {
      'comment-actions': document.querySelector('meta[name="stackchain-feature-comment-actions"]')?.content || '',
    },
  });
  const actionHydrator = createConversationActionHydrator({
    load: () => commentActionFeatures.load('comment-actions'),
    activate: () => {
      commentActions = createCommentActions({
        fetchJson: fetchReviewJson,
        getLogin: () => confirmedOwnerLogin,
        confirmDelete: message => window.confirm(message),
      });
      return commentActions;
    },
  });
  const issueCaptureFeatures = createFeatureLoader({
    document,
    urls: {
      'issue-capture': document.querySelector('meta[name="stackchain-feature-issue-capture"]')?.content || '',
      'push-notifications': document.querySelector('meta[name="stackchain-feature-push-notifications"]')?.content || '',
      'device-setup': document.querySelector('meta[name="stackchain-feature-device-setup"]')?.content || '',
    },
  });
  let sharedLaunchState = null;
  let sharedLaunchHandled = false;
  let voiceIssueCapture = null;
  async function ensureIssueCapture() {
    return await issueCaptureFeatures.run('issue-capture', {
      trigger: qs('#new-issue'), status: qs('#my-work-action-status'),
    }, () => {
      if (!issueCapture) {
        issueCapture = createIssueCapture({ fetchJson: fetchReviewJson, storage: localStorage });
        voiceIssueCapture = createVoiceIssueCapture({
          Recognition: window.SpeechRecognition || window.webkitSpeechRecognition,
          elements: {
            root:qs('#voice-issue-capture'), start:qs('#start-voice-issue-capture'),
            stop:qs('#stop-voice-issue-capture'), review:qs('#voice-issue-review'),
            transcript:qs('#voice-issue-transcript'), append:qs('#append-voice-issue-transcript'),
            replace:qs('#replace-with-voice-issue-transcript'), discard:qs('#discard-voice-issue-transcript'),
            status:qs('#voice-issue-status'), title:qs('#create-issue-title'), body:qs('#create-issue-body'),
          },
          transcriptStore:createVoiceTranscriptStore(),
          getLogin:()=>confirmedOwnerLogin,
        });
        issueOwnerPicker = createIssueCapture.createOwnerPicker(issueCapture, document,
          () => { saveIssueCaptureDraft(); updateIssueCreateActions(); });
        issueTemplatePicker = issueCapture.bindTemplatePicker({
          field:qs('#create-issue-template-field'), select:qs('#create-issue-template'),
          status:qs('#create-issue-template-status'), document,
          getRepository:()=>qs('#create-issue-repository').value,
          labelInputs:()=>document.querySelectorAll('input[name="create-issue-label"]'),
        }, {
          getDraft:currentIssueCaptureDraft,
          setDraft:draft=>{ qs('#create-issue-title').value=draft.title; qs('#create-issue-body').value=draft.body; },
          changed:()=>{ saveIssueCaptureDraft(); scheduleIssueDuplicateCheck(); },
        });
        issueFilingMetadata = issueCapture.bindFilingMetadata({
          document,
          labelList:qs('#create-issue-label-list'),
          labelStatus:qs('#create-issue-label-status'),
          milestoneSelect:qs('#create-issue-milestone'),
          milestoneStatus:qs('#create-issue-milestone-status'),
          templateStatus:qs('#create-issue-template-status'),
          getRepository:()=>qs('#create-issue-repository').value,
        }, issueTemplatePicker);
        updateFollowUp = createUpdateFollowUp({ storage:localStorage, getLogin:()=>confirmedOwnerLogin });
        checklistPromotion = createIssueCapture.createChecklistPromotion({
          issueController, issueCapture,
          clearAttachments:()=>createIssueAttachmentController.clear(),
          onLinked:(promotion, confirmed) => {
            if (selectedIssue?.repository === promotion.item.repository &&
                selectedIssue?.number === promotion.item.number) {
              applyIssueContent(promotion.item, promotion.detail, confirmed);
              qs('#issue-sheet').classList.add('open');
            }
          },
          onStatus:message=>{ qs('#my-work-action-status').textContent = message; },
        });
      }
      if (!sharedLaunchHandled && Object.values(sharedLaunch).some(Boolean)) {
        sharedLaunchState = issueCapture.stageSharedContent(sharedLaunch);
        sharedLaunchHandled = true;
      }
    });
  }
  if (Object.values(sharedLaunch).some(Boolean) || sharedImageMarker) await ensureIssueCapture();
  const pullWorkflowFeatures = createFeatureLoader({
    document,
    urls: {
      'pull-workflow': document.querySelector('meta[name="stackchain-feature-pull-workflow"]')?.content || '',
    },
  });
  let pullController = null;
  async function ensurePullWorkflow(trigger = null) {
    return await pullWorkflowFeatures.run('pull-workflow', {
      trigger, status: qs('#my-work-action-status'), retryLabel:'Tap the work card to retry.',
    }, () => {
      if (!pullController) {
        pullController = createPullSheet({ fetchJson: fetchReviewJson, storage: localStorage });
        createPullSheet.bindOwnershipControls(document, pullController, () => selectedPull, async item => {
          const continuing = workSession.checkpointed(item);
          lastContextSnapshot = createPullSheet.removeFromSnapshot(lastContextSnapshot, item);
          closePullSheet();
          if (continuing) return await completeOwnershipExitToday(item);
          paintMyWork(lastContextSnapshot);
          return false;
        });
      }
      attachReleaseReceipt();
      if (!reviewController) reviewController = createReviewController({ fetchJson: fetchReviewJson, storage: localStorage });
      if (!wrapPreference) {
        wrapPreference = createReviewController.createWrapPreference({
          storage: localStorage,
          mobile: window.matchMedia('(max-width: 600px)').matches,
        });
      }
    });
  }
  function restoreReleaseReceipt() {
    const account = String(confirmedOwnerLogin || '').trim().toLowerCase();
    if (!account) return;
    try {
      if (!localStorage.getItem('stackchain.release-receipt.v1:' + account)) return;
    } catch (_error) { return; }
    ensurePullWorkflow().then(() => releaseReceipt.restore()).catch(() => {});
  }
  const draftInbox = createDraftInbox({ storage: localStorage, getCurrentLogin: () => activeFlushLogin });
  outboxCoordinator.subscribe(() => refreshMyWorkView());
  const offlineWorkStore = createOfflineWorkStore({ storage: localStorage, indexedDB:window.indexedDB });
  let offlineStorageReady = await offlineWorkStore.ready();
  function renderOfflineTodayStatus(status) {
    const container = qs('#offline-today-readiness');
    const label = qs('#offline-today-status');
    const retry = qs('#retry-offline-today');
    const visible = offlineWorkStore.enabled() && status.total > 0;
    container.hidden = !visible;
    if (!visible) return;
    label.textContent = 'Today offline: ' + status.ready + ' of ' + status.total + ' ready' +
      (status.pending ? ' · saving ' + status.pending : '') +
      (status.failed ? ' · retry ' + status.failed : '');
    retry.hidden = status.failed === 0;
  }
  const offlineToday = createOfflineToday({
    loadDetail: async item => {
      if (item.is_review || item.kind === 'pull') {
        if (!await ensurePullWorkflow()) throw new Error('Pull workspace is unavailable.');
        return item.is_review ? reviewController.load(item) : pullController.load(item);
      }
      return issueController.load(item);
    },
    loadSavedDetail: (login, item) => offlineWorkStore.loadDetail(login, item),
    saveDetail: (login, item, detail) => offlineWorkStore.saveDetail(login, item, detail),
    onStatus: renderOfflineTodayStatus,
  });
  function warmTodayOffline() {
    if (!offlineWorkStore.enabled() || !confirmedOwnerLogin || offlineWorkMode) {
      offlineToday.cancel();
      renderOfflineTodayStatus({ total:0, ready:0, failed:0, pending:0 });
      return Promise.resolve();
    }
    return offlineToday.warm(confirmedOwnerLogin, todayMyWork);
  }
  let findWorkNavigation = null;
  const findWorkController = createFindWork({
    fetchJson: fetchReviewJson,
    onItems: renderAvailableIssues,
    onPagination: pagination => {
      availablePagination = pagination;
      qs('#load-more-available').hidden = !pagination.has_more;
    },
    onStatus: message => { qs('#find-work-status').textContent = message; },
    onSelection: state => {
      qs('#batch-find-work-actions').hidden = !state.active;
      qs('#select-find-work').hidden = state.active;
      qs('#find-work-selection-status').textContent = state.count ?
        state.count + ' issue' + (state.count === 1 ? '' : 's') + ' selected.' : 'No work selected.';
      qs('#claim-selected-work').disabled = state.count === 0;
      findWorkNavigation?.sync({ selectedCount:state.count });
      renderAvailableIssues(findWorkController.items());
    },
  });

  findWorkNavigation = createMobileFindWorkNavigation({
    document,
    history:window.history,
    eventTarget:window,
    controller:findWorkController,
    todayWork,
    openFit:openFindWorkEstimateReview,
  });
  findWorkNavigation.start();
  let findWorkSearchTimer = null;

  function updateFindWorkMatchStatus() {
    const query = findWorkController.query();
    qs('#find-work-match-status').textContent = query ?
      availablePagination.total + ' match' + (availablePagination.total === 1 ? '' : 'es') +
        ' for “' + query + '”.' : '';
  }

  function setStatus(msg) { qs('#status').textContent = msg || 'Live'; }
  function setClock() { qs('#clock').textContent = fmt(new Date()); }
  setClock(); setInterval(setClock, 1000);

  async function fetchLiveSnapshot(revisions = {}, { signal } = {}) {
    const query = createContextPoller.buildRevisionQuery(revisions);
    const res = await fetch('api/v1/live' + (query ? '?' + query : ''), {
      headers: { Accept: 'application/json' },
      signal,
    });
    if (!res.ok) {
      const error = new Error('HTTP ' + res.status);
      error.retryAfterMs = createContextPoller.retryAfterMs(res.headers.get('Retry-After'));
      throw error;
    }
    return res.json();
  }

  async function markNotificationRead(notificationId) {
    const response = await fetch('api/v1/notifications/' + encodeURIComponent(notificationId) + '/read', {
      method: 'PATCH',
      headers: { Accept: 'application/json' },
    });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) throw new Error(payload.error || 'Mark read failed.');
    return payload;
  }

  async function acknowledgeNotification(notificationId) {
    const response = await fetch('api/v1/notifications/' + encodeURIComponent(notificationId) +
      '/acknowledge', { method: 'POST', headers: { Accept: 'application/json' } });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) throw new Error(payload.error || 'Acknowledging the update failed.');
    return payload;
  }

  async function muteNotification(notificationId) {
    const response = await fetch('api/v1/notifications/' + encodeURIComponent(notificationId) +
      '/mute', { method: 'POST', headers: { Accept: 'application/json' } });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) {
      const error = new Error(payload.error || 'Muting future updates failed.');
      error.muted = payload.muted === true;
      throw error;
    }
    return payload;
  }

  async function markNotificationsRead(ids) {
    const response = await fetch('api/v1/notifications/read', {
      method: 'PATCH',
      headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
      body: JSON.stringify({ ids }),
    });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) throw new Error(payload.error || 'Bulk mark read failed.');
    return payload;
  }

  async function fetchNotificationPage(page) {
    const response = await fetch('api/v1/notifications?page=' + encodeURIComponent(page), {
      headers: { Accept: 'application/json' },
    });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) throw new Error(payload.error || 'Loading unread updates failed.');
    return payload;
  }

  async function fetchNotificationDetail(notificationId) {
    const response = await fetch('api/v1/notifications/' + encodeURIComponent(notificationId), {
      headers: { Accept: 'application/json' },
    });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) throw new Error(payload.error || 'Loading the update failed.');
    return payload;
  }

  async function fetchNotificationConversation(notificationId, page) {
    const pageQuery = Number.isInteger(page) ? '&page=' + encodeURIComponent(page) : '';
    const response = await fetch('api/v1/notifications/' + encodeURIComponent(notificationId) +
      '/conversation?limit=20' + pageQuery, {
        headers: { Accept: 'application/json' },
      });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) throw new Error(payload.error || 'Loading older messages failed.');
    return payload;
  }

  async function fetchWorkPage(stream, page) {
    const response = await fetch('api/v1/work/' + encodeURIComponent(stream) + '?page=' + encodeURIComponent(page), {
      headers: { Accept: 'application/json' },
    });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) throw new Error(payload.error || 'Loading older work failed.');
    return payload;
  }

  async function postNotificationReply(notificationId, body, operationId) {
    const response = await fetch('api/v1/notifications/' + encodeURIComponent(notificationId) + '/reply', {
      method: 'POST',
      headers: {
        Accept: 'application/json', 'Content-Type': 'application/json',
        'Idempotency-Key': operationId,
      },
      body: JSON.stringify({ body }),
    });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) throw new Error(payload.error || 'Posting the reply failed.');
    return payload;
  }

  const notificationAcknowledger = createNotificationAcknowledger({
    markRead: markNotificationRead,
    onItems: items => {
      lastMyWork = items;
      refreshMyWorkView();
    },
    onStatus: message => { qs('#my-work-action-status').textContent = message; },
  });
  const bulkNotificationAcknowledger = createBulkNotificationAcknowledger({
    markRead: markNotificationsRead,
    onItems: items => {
      lastMyWork = items;
      refreshMyWorkView();
    },
    onStatus: message => { qs('#my-work-action-status').textContent = message; },
  });
  const notificationSelection = createNotificationSelection({
    limit: 50,
    onChange: () => {
      bulkConfirmationPending = false;
      renderMyWork();
    },
  });
  const workSelection = createWorkSelection({ limit: 50, onChange: () => renderMyWork() });
  const notificationPager = createNotificationPager({
    load: fetchNotificationPage,
    onNotifications: items => {
      lastNotifications = items;
      if (lastContextSnapshot) {
        lastContextSnapshot.notifications = lastNotifications;
        paintMyWork(lastContextSnapshot);
      }
    },
    onPagination: pagination => {
      notificationPagination = pagination;
      const loaded = Math.min(pagination.total, pagination.page * 50);
      qs('#notification-page-status').textContent = pagination.total ?
        loaded + ' of ' + pagination.total + ' unread updates loaded.' : '';
      qs('#load-more-notifications').hidden =
        selectedWorkFilter !== 'update' || !pagination.has_more;
    },
    onStatus: message => { qs('#my-work-action-status').textContent = message; },
  });
  const workPager = createWorkPager({
    load: fetchWorkPage,
    onItems: (stream, items) => {
      if (!lastContextSnapshot) return;
      if (stream === 'issue' || stream === 'filed') lastContextSnapshot.issues = items;
      else lastContextSnapshot.pull_requests = items;
      paintMyWork(lastContextSnapshot);
    },
    onPagination: pagination => {
      workPagination = pagination;
      updateWorkPaginationControls();
    },
    onStatus: message => { qs('#my-work-action-status').textContent = message; },
  });
  const notificationReplier = createNotificationReplier({
    post: postNotificationReply,
    storage: localStorage,
    authoredOutbox,
    onStatus: message => { qs('#update-reply-status').textContent = message; },
  });
  const updateOwnership = createUpdateOwnership({
    available: () => createAndStart.available(),
    claim: item => fetchReviewJson(
      'api/v1/repos/' + item.repository.split('/').map(encodeURIComponent).join('/') +
      '/issues/' + encodeURIComponent(item.number) + '/claim',
      { method:'PATCH', headers:{ Accept:'application/json' } }
    ),
    addToday: item => {
      const result = todayWork.add(item);
      refreshMyWorkView();
      if (result === 'added') {
        todaySync.enqueue('add', todayWork.identity(item));
        todaySync.flush();
        warmTodayOffline();
      }
      return result;
    },
    start: item => {
      const outcome = createAndStart.complete(item);
      if (outcome === 'started') openRoutedWork(item, qs('#update-ownership-start'));
      return outcome;
    },
    recover: item => openRoutedWork(item, qs('#update-ownership-start')),
    onClaimed: item => {
      if (!lastContextSnapshot) return;
      const issues = (lastContextSnapshot.issues || []).filter(candidate =>
        candidate.repository !== item.repository || candidate.number !== item.number
      );
      lastContextSnapshot = { ...lastContextSnapshot, issues:issues.concat(item) };
      paintMyWork(lastContextSnapshot);
    },
    onState: state => {
      const button = qs('#update-ownership-action');
      button.hidden = state.action === 'hidden';
      button.disabled = state.busy;
      button.textContent = state.action === 'today' ? 'Add to Today' : 'Take ownership';
      if (state.message) qs('#update-sheet-status').textContent = state.message;
    },
    onStartState: state => {
      const button = qs('#update-ownership-start');
      button.hidden = state.action === 'hidden';
      button.disabled = state.busy;
      if (state.message) qs('#update-sheet-status').textContent = state.message;
    },
  });
  const notificationUndo = createDashboardNotificationUndo({
    restore: requestNotificationUnread,
    getItems: () => lastMyWork,
    setItems: items => { lastMyWork = items; },
    getNotifications: () => lastNotifications,
    setNotifications: items => { lastNotifications = items; },
    refresh: refreshMyWorkView,
    select: qs,
  });
  const updateReadPosition = createUpdateReadPosition({
    panel: qs('#update-sheet .update-sheet-panel'),
    jump: qs('#jump-update-new-activity'),
  });
  const mobileUpdateDetailNavigation = createMobileUpdateDetailNavigation({
    root:qs('#update-sheet .update-sheet-panel'),
    buttons:Object.fromEntries(Array.from(document.querySelectorAll('[data-update-section]')).map(button => [button.dataset.updateSection, button])),
    targets:{
      conversation:qs('#update-conversation'),
      context:qs('#update-subject-context'),
      reply:qs('#update-reply-workspace'),
    },
    replyComposer:qs('#update-reply'),
    jumpToNewActivity:() => updateReadPosition.jump(),
    onSectionChange:(section, options) => workRoute.section(section, options),
    prefersReducedMotion:() => window.matchMedia('(prefers-reduced-motion: reduce)').matches,
  });
  mobileUpdateDetailNavigation.start();
  const mobileReviewDetailNavigation = createMobileReviewDetailNavigation({
    root:qs('#review-sheet .review-sheet-panel'),
    buttons:Object.fromEntries(Array.from(document.querySelectorAll('[data-review-section]')).map(button => [button.dataset.reviewSection, button])),
    targets:{
      overview:qs('#review-overview'),
      files:qs('#review-files-workspace'),
      feedback:qs('#review-feedback'),
      history:qs('#review-history-workspace'),
    },
    summaryComposer:qs('#review-summary'),
    onSectionChange:(section, options) => workRoute.section(section, options),
    prefersReducedMotion:() => window.matchMedia('(prefers-reduced-motion: reduce)').matches,
  });
  mobileReviewDetailNavigation.start();
  const issueDetailPosition = createWorkDetailPosition({ panel: qs('#issue-sheet .issue-sheet-panel') });
  const pullDetailPosition = createWorkDetailPosition({ panel: qs('#pull-sheet .pull-sheet-panel') });
  const reviewDetailPosition = createWorkDetailPosition({ panel: qs('#review-sheet .review-sheet-panel') });
  const workDetailIdentity = (kind, item) => kind + ':' + item.key;
  qs('#jump-update-new-activity').addEventListener('click', () => updateReadPosition.jump());
  qs('#focus-update-reply').addEventListener('click', () => {
    const composer = qs('#update-reply');
    composer.scrollIntoView({ behavior:'smooth', block:'center' });
    qs('#update-reply').focus({ preventScroll:true });
  });
  qs('#toggle-update-more').addEventListener('click', event => {
    const more = qs('.update-more-actions');
    more.open = !more.open;
    event.currentTarget.setAttribute('aria-expanded', String(more.open));
    if (more.open) more.scrollIntoView({ behavior:'smooth', block:'end' });
  });
  const updateDecision = createUpdateDecisionTransaction({
    controls: [
      qs('#keep-update-unread'), qs('#mark-update-read-next'),
      qs('#review-update-now'), qs('#focus-update-reply'), qs('#toggle-update-more'),
    ],
    status: qs('#update-gesture-status'),
  });
  const notificationReader = createNotificationReader({
    load: fetchNotificationDetail,
    getScope: () => confirmedOwnerLogin,
    loadConversation: fetchNotificationConversation,
    markRead: markNotificationRead,
    acknowledge: acknowledgeNotification,
    queueRead: notificationId => notificationReadOutbox.enqueueDurably(notificationId),
    loadSaved: item => offlineWorkStore.loadDetail(confirmedOwnerLogin, item),
    onOpen: item => {
      selectedUpdate = item;
      void conversationPhotoDrafts.switchTo('update',
        { kind:'update', notificationId:item.notification_id }, () => selectedUpdate === item);
      void updateVoiceReply.open('update:' + item.notification_id);
      selectedUpdateDetail = null;
      updateReadPosition.open(String(item.notification_id));
      mobileUpdateDetailNavigation.reset();
      updateMentions.dismiss();
      qs('#update-sheet').classList.add('open');
      qs('.update-more-actions').open = false;
      qs('#toggle-update-more').setAttribute('aria-expanded', 'false');
      qs('#update-sheet-key').textContent = item.key || '';
      qs('#update-sheet-title').textContent = item.title || 'Unread update';
      qs('#update-comments').textContent = '';
      qs('#update-conversation-status').textContent = '';
      qs('#retry-update-conversation').hidden = true;
      qs('#load-older-update-comments').hidden = true;
      qs('#update-subject-body').textContent = '';
      qs('#update-subject-type').textContent = item.subject_type || 'Update';
      qs('#update-subject-state').textContent = item.state || '';
      qs('#open-update-gitea').href = item.url || '#';
      qs('#update-reply').value = notificationReplier.loadDraft(item);
      qs('#update-reply-status').textContent = '';
      qs('#send-update-reply').disabled = false;
      qs('#send-update-reply-read-next').disabled = false;
      qs('#acknowledge-update-next').hidden = true;
      qs('#mute-update-next').hidden = true;
      qs('#update-ownership-action').hidden = true;
      qs('#update-ownership-start').hidden = true;
      qs('#create-update-follow-up').hidden = true;
      qs('#review-update-now').hidden = true;
      qs('#retry-update-load').hidden = true;
      setOfflineUpdateControls(false);
      qs('#keep-update-unread').focus();
    },
    onDetail: async detail => {
      selectedUpdateDetail = detail;
      qs('#update-sheet-title').textContent = detail.title || 'Unread update';
      qs('#update-subject-type').textContent = detail.subject_type || 'Update';
      qs('#update-subject-state').textContent = detail.state || '';
      qs('#update-subject-body').innerHTML = renderMarkdown(detail.subject_body || 'No subject context was provided.');
      qs('#open-update-gitea').href = detail.url || selectedUpdate?.url || '#';
      qs('#acknowledge-update-next').hidden = !detail.acknowledge_supported;
      qs('#mute-update-next').hidden = !detail.mute_supported;
      qs('#create-update-follow-up').hidden = !['Issue', 'Pull'].includes(detail.subject_type);
      qs('#review-update-now').hidden = !updateReviewHandoff.eligible(detail, selectedUpdate);
      if (offlineWorkMode) {
        setOfflineUpdateControls(true);
      } else {
        updateOwnership.open(detail, selectedUpdate);
        if (offlineWorkStore.enabled() && confirmedOwnerLogin && selectedUpdate) {
          await offlineWorkStore.saveDetail(confirmedOwnerLogin, selectedUpdate, detail);
        }
      }
      qs('#retry-update-load').hidden = true;
    },
    onConversation: renderUpdateConversation,
    onConversationStatus: message => {
      qs('#update-conversation-status').textContent = message;
      qs('#retry-update-conversation').hidden = !message.startsWith('Conversation temporarily unavailable.');
    },
    onItems: items => {
      const readId = selectedUpdate?.notification_id;
      lastMyWork = items;
      if (Number.isInteger(readId)) {
        lastNotifications = lastNotifications.filter(item => item.id !== readId);
      }
      refreshMyWorkView();
    },
    onStatus: message => {
      qs('#update-sheet-status').textContent = message;
      if (message === 'Update ready.' && updateTriage.active() && !offlineWorkMode) {
        notificationReader.prefetch(updateTriage.next());
      }
      qs('#retry-update-load').hidden = !message.startsWith('Could not load update.');
      if (message === 'Inbox cleared.') {
        qs('#my-work-action-status').textContent = message;
        if (!mobileStartDay.completePhase('update')) showMobileQueueCompletion('Updates');
      }
    },
    onClose: () => closeUpdateSheet(false),
  });

  const updateTriage = createUpdateTriageSession({
    storage: localStorage,
    getLogin: () => confirmedOwnerLogin,
    getItems: () => lastMyWork.filter(item => item?.has_update && Number.isInteger(item.notification_id)),
    onOpen: item => notificationReader.open(
      item,
      offlineWorkMode ? offlineWorkStore.loadDetail(confirmedOwnerLogin, item) : null
    ),
    onProgress: state => {
      const progress = qs('#update-triage-progress');
      progress.hidden = false;
      progress.textContent = 'Update ' + state.index + ' of ' + state.total +
        (state.reason ? ' · ' + state.reason : '');
    },
    onFinish: outcome => {
      notificationReader.prefetch();
      qs('#update-triage-progress').hidden = true;
      showUpdateTriageOutcome(outcome);
    },
  });
  const updateReviewHandoff = createUpdateReviewHandoff({
    openReview: item => {
      qs('#update-sheet').classList.remove('open');
      reviewHandoffSubmitted = false;
      openReviewSheet(item, qs('#review-update-now'),
        offlineWorkMode ? offlineWorkStore.loadDetail(confirmedOwnerLogin, item) : null);
    },
    restoreUpdate: () => {
      qs('#review-sheet').classList.remove('open');
      selectedReview = null;
      qs('#update-sheet').classList.add('open');
      qs('#review-update-now').focus();
    },
    admitRead: notificationId => offlineWorkMode ?
      notificationReadOutbox.enqueueDurably(notificationId) : markNotificationRead(notificationId),
    advance: source => {
      mobileComposerViewport.close(qs('#review-sheet .review-sheet-panel'));
      qs('#review-sheet').classList.remove('open');
      selectedReview = null;
      offlineReview = false;
      progress = null;
      draft = null;
      reviewFiles = [];
      selectedReviewHead = '';
      notificationReader.acceptReadAndNext(lastMyWork, source);
      if (updateTriage.active()) updateTriage.acceptCompleted();
      reviewHandoffSubmitted = false;
    },
  });
  qs('#review-update-now').addEventListener('click', () => updateReviewHandoff.begin(selectedUpdate));
  qs('#review-kept-updates').addEventListener('click', () => {
    qs('#mobile-queue-sheet').close();
    updateTriage.reviewKept(keptUpdateIdentities);
  });

  const updateTriageLauncher = createUpdateTriageLauncher({
    selectUpdates: () => selectMobileQueue('update'),
    discover: () => api('api/v1/notifications/snapshot'),
    applySnapshot: snapshot => {
      lastNotifications = snapshot.items || [];
      notificationPager.reset({page:1, total:snapshot.total || 0, has_more:false});
      if (lastContextSnapshot) {
        lastContextSnapshot.notifications = lastNotifications;
        paintMyWork(lastContextSnapshot);
      }
    },
    isUpdatesSelected: () => selectedWorkFilter === 'update',
    hasMore: () => Boolean(notificationPagination.has_more),
    hasCheckpoint: () => updateTriage.resumable(),
    resume: () => updateTriage.resume(),
    start: () => updateTriage.start(),
    announce: announceWork,
  });

  function openUpdateTriage() {
    return updateTriageLauncher.open();
  }

  function routedWorkItem(item) {
    if (item?.has_update && item.kind === 'update') {
      return { ...item, kind:'update' };
    }
    return { ...item, kind:item?.is_review ? 'review' : item?.kind };
  }

  function openRoutedWork(item, trigger, options = {}) {
    if (!item) return;
    if (offlineWorkMode) {
      const offlineLogin = planningOwnerLogin || confirmedOwnerLogin ||
        String(offlineWorkStore.load()?.user?.login || '').trim();
      const savedDetail = offlineWorkStore.loadDetail(offlineLogin, item);
      const savedUpdate = item.kind === 'update' && item.has_update;
      if ((!savedUpdate && !todayWork.contains(item)) || !savedDetail) {
        qs('#my-work-action-status').textContent = 'Details not saved—reconnect to open this item.';
        return;
      }
      if (item.kind === 'issue') {
        issueTrigger = trigger;
        openIssueSheet(item, trigger, savedDetail);
      } else if (item.is_review) {
        reviewTrigger = trigger;
        openReviewSheet(item, trigger, savedDetail);
      } else if (item.kind === 'pull') {
        pullTrigger = trigger;
        openPullSheet(item, trigger, savedDetail);
      } else if (savedUpdate) {
        updateTrigger = trigger;
        notificationReader.open(item, savedDetail).then(opened => {
          if (opened && selectedUpdate === item) {
            qs('#update-sheet-status').textContent = 'Offline update · saved ' + fmt(savedDetail.saved_at) +
              ' · replies and read acknowledgements queue for sync. Reconnect to take ownership, defer, or load older messages.';
          }
        });
      } else {
        qs('#my-work-action-status').textContent = 'Details not saved—reconnect to open this item.';
      }
      return;
    }
    if (item.has_update && item.kind === 'update') updateTrigger = trigger;
    else if (item.is_review) reviewTrigger = trigger;
    else if (item.kind === 'issue') issueTrigger = trigger;
    else if (item.kind === 'pull') pullTrigger = trigger;
    workRoute.open(routedWorkItem(item), options);
  }

  function navigateWorkSection(kind, section) {
    if (['issue', 'filed'].includes(kind)) {
      mobileIssueDetailNavigation.navigate(section, { focus:false });
    } else if (kind === 'pull') {
      mobilePullDetailNavigation.navigate(section, { focus:false });
    } else if (kind === 'update') {
      mobileUpdateDetailNavigation.navigate(section, { focus:false });
    } else if (kind === 'review') {
      mobileReviewDetailNavigation.navigate(section, { focus:false });
    }
  }

  async function openRoutedWorkSection(item) {
    if (item.kind === 'update') await notificationReader.open(item, lastMyWork);
    else if (item.kind === 'review') await openReviewSheet(item, reviewTrigger);
    else if (item.kind === 'issue' || item.kind === 'filed') await openIssueSheet(item, issueTrigger);
    else if (item.kind === 'pull') await openPullSheet(item, pullTrigger);
  }

  const workRoute = createWorkRoute.createController({
    location: window.location,
    history: window.history,
    eventTarget: window,
    resolve: route => {
      const params = new URLSearchParams({ kind:route.kind });
      if (route.kind === 'update') params.set('notification_id', route.notification_id);
      else {
        params.set('repository', route.repository);
        params.set('number', route.number);
      }
      return api('api/v1/work-route?' + params.toString());
    },
    onResolving: () => {
      qs('#retry-work-route').hidden = true;
      qs('#my-work-action-status').textContent = 'Loading shared work item…';
    },
    onOpen: async item => {
      qs('#retry-work-route').hidden = true;
      qs('#my-work-action-status').textContent = '';
      closeOpenWorkSheets();
      await openRoutedWorkSection(item);
      const route = createWorkRoute.parse(window.location.hash);
      if (route?.section === item.section) navigateWorkSection(item.kind, item.section);
    },
    onSection: (section, options) => {
      const route = createWorkRoute.parse(window.location.hash);
      if (options.restore) navigateWorkSection(route?.kind, section);
    },
    onQueue: openWorkQueueRoute,
    onClose: () => {
      if (selectedIssue) closeIssueSheet(false);
      if (selectedPull) closePullSheet(false);
      if (selectedReview) closeReviewSheet(false);
      if (selectedUpdate) closeUpdateSheet(true, false);
    },
    onInvalid: () => {
      qs('#retry-work-route').hidden = true;
      window.history.replaceState(null, '', window.location.pathname + window.location.search);
      closeOpenWorkSheets();
      qs('#my-work-action-status').textContent = 'Route unavailable · this item is no longer in My Work.';
      qs('#my-work').scrollIntoView({ block:'start' });
    },
    onError: () => {
      qs('#my-work-action-status').textContent = 'Could not load shared work item. The link is preserved; retry when connected.';
      qs('#retry-work-route').hidden = false;
    },
  });
  workRoute.start();
  qs('#retry-work-route').addEventListener('click', () => workRoute.sync());

  function closeOpenWorkSheets() {
    issueVoiceReply.cancel();
    pullVoiceReply.cancel();
    updateVoiceReply.cancel();
    ['#issue-sheet .issue-sheet-panel', '#pull-sheet .pull-sheet-panel', '#review-sheet .review-sheet-panel', '#update-sheet .update-sheet-panel']
      .forEach(selector => mobileComposerViewport.close(qs(selector)));
    ['#issue-sheet', '#pull-sheet', '#review-sheet', '#update-sheet'].forEach(selector =>
      qs(selector).classList.remove('open')
    );
    selectedIssue = null;
    selectedIssueDetail = null;
    selectedPull = null;
    selectedPullDetail = null;
    selectedReview = null;
    selectedUpdate = null;
  }

  function openWorkSessionItem(item) {
    timerView.open(workIdentity(item), workSession.checkpointed(item));
    openRoutedWork(item, null, { replace:true });
  }

  const sessionCheckpoint = createWorkSessionCheckpoint({
    storage: localStorage,
    getLogin: () => confirmedOwnerLogin,
    onError: () => {
      qs('#my-work-action-status').textContent =
        'Session recovery could not be saved on this device. You can keep working.';
    },
  });
  const agendaSessionCheckpoint = createWorkSessionCheckpoint({
    storage: localStorage,
    getLogin: () => confirmedOwnerLogin,
    key: 'stackchain.agenda-session.v1',
    onError: () => {
      qs('#my-work-action-status').textContent =
        'Agenda progress could not be saved on this device. You can keep working.';
    },
  });
  let todaySessionSync = null;
  let todayLockScreen = null;
  const timer = createTodayTimer({
    storage: localStorage,
    getLogin: () => confirmedOwnerLogin,
    onChange: snapshot => {
      todaySessionSync?.publish(snapshot);
      queueMicrotask(() => {
        if (todayLockScreen) todayLockScreen.sync(snapshot, workSession.checkpointed());
      });
    },
  });
  const timerView = createTodayTimerView({
    timer,
    isActive: () => workSession.checkpointed(),
    queryAll: s => document.querySelectorAll(s),
    formatEstimate: formatPlanMinutes,
    getItem: identity => [...todayMyWork, ...activeMyWork].find(item => todayWork.identity(item) === identity),
    onReopen: identity => {
      taskOverlayHistory.leave();
      selectTodayWork();
      const item = [...todayMyWork, ...activeMyWork].find(item => todayWork.identity(item) === identity);
      if (!workSession.reopen(item)) workSession.resume(item);
    },
    onResume: identity => {
      selectTodayWork();
      const item = todayMyWork.find(entry => todayWork.identity(entry) === identity);
      if (!workSession.resume(item)) resumeTodaySession();
    },
    onComplete: identity => {
      const item = todayMyWork.find(entry => todayWork.identity(entry) === identity);
      return completeTodayItem(item);
    },
    onCapture:() => openCreateIssueSheet(),
  });
  window.stackchainTodayTimerView = timerView;
  mobileInsights.start();
  todaySessionSync = attachTodaySessionHandoff({
    fetchJson:fetchReviewJson, storage:localStorage, timer, qs,
    items:() => [...todayMyWork, ...activeMyWork],
    identity:item => todayWork.identity(item),
    selectToday:() => selectTodayWork(),
    startItem:item => workSession.start(item),
    announce:message => { qs('#my-work-action-status').textContent = message; },
    renderTimer:() => timerView.render(),
  });
  renderAttentionInterruption();
  qs('#return-to-today').addEventListener('click', () => {
    const returned = timer.returnFromAttention();
    renderAttentionInterruption();
    if (!returned) return;
    selectTodayWork();
    const item = todayMyWork.find(entry => todayWork.identity(entry) === returned.identity);
    if (item) workSession.reopen(item);
    else continueTodaySession();
    timerView.render();
  });
  const interruptionPrompt = createTodayInterruptionPrompt({
    timer,
    sheet: qs('#today-interruption-sheet'),
    description: qs('#today-interruption-description'),
    getItemLabel: identity => {
      const item = [...todayMyWork, ...activeMyWork].find(entry => todayWork.identity(entry) === identity);
      return item?.title || '';
    },
    onResolved: () => timerView.render(),
  });
  window.addEventListener('pagehide', () => interruptionPrompt.background());
  interruptionPrompt.restore();
  document.querySelectorAll('[data-today-interruption]').forEach(button => {
    button.addEventListener('click', () =>
      interruptionPrompt.resolve(button.dataset.todayInterruption)
    );
  });
  const todaySummaryView = setupTodaySummary({
    qs, escapeHtml, getLogin:() => planningOwnerLogin, fetchJson:api,
    enqueueDurably:message => authoredOutbox.enqueueDurably(message),
  });
  todaySummaryView.resume();
  const todayWrapUpView = setupTodayWrapUp({ todayWork, tomorrowPlan, todaySync, qs, escapeHtml,
    onComplete:(_result, _actualMinutes, workedItems, tomorrowItems) => {
      todayRecapView['completeReplan']();
      refreshMyWorkView();
      warmTodayOffline();
      renderTomorrowQueueSummary();
      syncPendingTomorrow();
      todaySummaryView.open(workedItems, tomorrowItems);
    },
  });
  const todayRecapView = setupTodayRecap(
    timer, timerView, todayWork, api, qs, escapeHtml, closeOpenWorkSheets, updateWorkSessionActions,
    () => planningOwnerLogin,
    identity => [...todayMyWork, ...activeMyWork].find(item => todayWork.identity(item) === identity) || null,
    (actualMinutes, workedItems) => todayWrapUpView.open(todayMyWork, actualMinutes, workedItems)
  );
  function updateDetailDeferLabels(active) {
    document.querySelectorAll('[data-detail-defer-preset=today]').forEach(button => {
      button.textContent = active ? 'Later today & next' : 'Later today';
    });
    document.querySelectorAll('[data-detail-defer-preset=tomorrow]').forEach(button => {
      button.textContent = active ? 'Tomorrow & next' : 'Tomorrow';
    });
    document.querySelectorAll('[data-detail-defer-custom]').forEach(button => {
      button.textContent = active ? 'Choose date & time & next' : 'Choose date & time';
    });
  }
  function updateWorkSessionActions() {
    const active = workSession.active();
    const startWorkSession = qs('#start-work-session');
    startWorkSession.hidden = active;
    startWorkSession.textContent = selectedWorkFilter === 'agenda' ?
      (agendaSessionCheckpoint.read() ? 'Resume Agenda' : 'Start Agenda') : 'Start work';
    qs('#resume-today-session').hidden = active || selectedWorkFilter !== 'today' ||
      !todayMyWork.length || !workSession.resumable();
    qs('#end-today-session').hidden = !active;
    todayProgressView.update();
    updateDetailDeferLabels(active);
    mobileTaskDock.updateWork(mobileWorkEntry.mode());
    mobileTaskDock.updateAttention(countMyWork(activeMyWork).attention);
  }

  const workSession = createWorkSession({
    getItems: () => selectedWorkFilter === 'today' ? todayMyWork :
      selectedWorkFilter === 'agenda' ? agendaMyWork(activeMyWork) : activeMyWork,
    getFilter: () => selectedWorkFilter === 'today' ? 'all' :
      selectedWorkFilter === 'agenda' ? 'all' : selectedWorkFilter,
    getMilestone: () => selectedWorkFilter === 'agenda' ? 'all' : selectedWorkMilestone,
    checkpoint: () => selectedWorkFilter === 'agenda' ? agendaSessionCheckpoint : sessionCheckpoint,
    checkpointEnabled: () => ['today', 'agenda'].includes(selectedWorkFilter),
    checkpointedEnabled: () => selectedWorkFilter === 'today',
    onOpen: openWorkSessionItem,
    onProgress: state => {
      updateWorkSessionActions();
      document.querySelectorAll('.work-session-nav').forEach(nav => { nav.hidden = false; });
      const runway = selectedWorkFilter === 'today' ? todayWork.runway(todayMyWork, state.index - 1) : null;
      timerView.update(state, runway);
      document.querySelectorAll('[data-work-session-previous]').forEach(button => {
        button.disabled = !state.can_previous;
      });
      document.querySelectorAll('[data-work-session-next]').forEach(button => {
        button.textContent = state.can_next ? 'Next work item' : 'Finish session';
      });
      document.querySelectorAll('[data-work-session-complete]').forEach(button => {
        button.hidden = !workSession.checkpointed();
      });
      todayProgressView.update();
    },
    onFinish: () => {
      updateWorkSessionActions();
      if (selectedWorkFilter === 'agenda') {
        closeOpenWorkSheets();
        if (mobileStartDay.completePhase('agenda')) return;
        window.location.hash = '#/my-work/agenda';
        qs('#my-work-action-status').textContent = 'Agenda complete.';
        return;
      }
      todayRecapView.finish(selectedWorkFilter);
    },
  });
  function currentTodayProgressTarget() {
    if (!workSession.checkpointed()) return null;
    const item = workSession.target('continue');
    if (!item || item.is_review || !['issue', 'pull'].includes(item.kind) ||
        !item.repository || !Number.isInteger(item.number)) return null;
    return {
      identity:todayWork.identity(item), kind:item.kind, repository:item.repository,
      number:item.number, label:item.key || item.repository + '#' + item.number,
      title:item.title || '', item,
    };
  }
  const todayProgressView = createTodayProgressView({
    progress:todayProgress, currentTarget:currentTodayProgressTarget, qs, photos:todayProgressPhotos,
    voice:todayProgressVoice, mentions:todayProgressMentions,
    activity:mountTodayProgressActivity(qs,fetchReviewJson,actionHydrator,renderMarkdown),
    announce:message => { qs('#my-work-action-status').textContent = message; },
    onAdmitted:() => refreshMyWorkView(),
    moveOn:(target,until) => detailDefer.deferUntil(target.item,until),
  });
  function selectTodayWork() {
    qs('[data-work-filter="today"]').click();
  }

  const agendaSessionLauncher = createAgendaSessionLauncher({
    selectAgenda: () => selectMobileQueue('agenda'),
    discover: completeAgendaIssues,
    isAgendaSelected: () => selectedWorkFilter === 'agenda',
    hasMore: () => Boolean(workPagination.issue?.has_more),
    hasCheckpoint: () => Boolean(agendaSessionCheckpoint.read()),
    resume: () => workSession.resume(),
    start: () => workSession.start(),
    announce: announceWork,
  });
  function openAgendaSession() {
    return agendaSessionLauncher.open();
  }

  let todayReadinessTrigger = null;
  let todayReadinessBlockerFocus = null;
  let searchPreviewReturnKind = null;
  function inspectTodayDependencies(item) {
    if (offlineWorkMode) {
      const login = confirmedOwnerLogin || String(offlineWorkStore.load()?.user?.login || '').trim();
      const detail = offlineWorkStore.loadDetail(login, item);
      return Promise.resolve({
        available:detail?.dependencies_available === true,
        dependencies:Array.isArray(detail?.dependencies) ? detail.dependencies : [],
      });
    }
    const [owner, repo] = String(item.repository || '').split('/');
    return api('api/v1/repos/' + encodeURIComponent(owner) + '/' + encodeURIComponent(repo) +
      '/issues/' + encodeURIComponent(item.number) + '/detail').then(detail => ({
        available:detail?.dependencies_available === true,
        dependencies:Array.isArray(detail?.dependencies) ? detail.dependencies : [],
      }));
  }

  function suspendTodayReadiness() {
    qs('#today-readiness-sheet').hidden = true;
    document.body.classList.remove('task-overlay-open');
  }

  function closeTodayReadiness(navigate = true) {
    suspendTodayReadiness();
    if (navigate) taskOverlayHistory.close();
    else {
      todayReadiness.cancel();
      todayReadinessBlockerFocus = null;
      requestAnimationFrame(() => todayReadinessTrigger?.focus());
    }
  }

  function renderTodayReadiness(state) {
    if (!state?.target) return;
    const unknown = state.status === 'unknown';
    qs('#today-readiness-title').textContent = unknown ? 'Blocker status unavailable' : 'This item is blocked';
    qs('#today-readiness-summary').textContent = unknown
      ? 'Stackchain could not confirm whether this issue is ready. Retry or choose an explicit override.'
      : state.dependencies.length + (state.dependencies.length === 1 ? ' open dependency must finish first.' : ' open dependencies must finish first.');
    qs('#today-readiness-item').innerHTML = '<strong>' + escapeHtml(state.target.title || 'Untitled issue') +
      '</strong><div class="small">' + escapeHtml(state.target.repository + '#' + state.target.number) + '</div>';
    const blockers = qs('#today-readiness-blockers');
    blockers.innerHTML = state.dependencies.map((blocker, index) =>
      '<button class="issue-blocker today-readiness-blocker" type="button" data-today-blocker-index="' + index + '"><strong>' +
      escapeHtml(blocker.repository + '#' + blocker.number) + ' · ' + escapeHtml(blocker.title || 'Untitled blocker') +
      '</strong><span class="small">State: ' + escapeHtml(blocker.state || 'open') + ' · Preview and work blocker</span></button>'
    ).join('');
    blockers.querySelectorAll('[data-today-blocker-index]').forEach(button => {
      button.addEventListener('click', () => {
        const blocker = state.dependencies[Number(button.dataset.todayBlockerIndex)];
        todayReadinessBlockerFocus = blocker?.repository + '#' + blocker?.number;
        todayReadiness.previewBlocker(blocker);
      });
    });
    qs('#today-readiness-next').hidden = !state.nextReady;
    if (state.nextReady) qs('#today-readiness-next').textContent = 'Start next ready · ' +
      (state.nextReady.title || state.nextReady.key || 'work item');
    qs('#today-readiness-retry').hidden = !unknown;
    qs('#today-readiness-sheet').hidden = false;
    document.body.classList.add('task-overlay-open');
    requestAnimationFrame(() => {
      const blocker = state.dependencies.findIndex(candidate =>
        candidate?.repository + '#' + candidate?.number === todayReadinessBlockerFocus
      );
      if (blocker >= 0) blockers.querySelector('[data-today-blocker-index="' + blocker + '"]')?.focus();
      else (state.nextReady ? qs('#today-readiness-next') : qs('#today-readiness-anyway')).focus();
    });
  }

  function performTodayTransition(action, item = null) {
    qs('#today-readiness-sheet').hidden = true;
    document.body.classList.remove('task-overlay-open');
    if (taskOverlayHistory.current?.() === 'today-readiness') taskOverlayHistory.close();
    const transitioned = ({
      start: () => workSession.start(item),
      resume: () => workSession.resume(item),
      continue: () => workSession.reopen(item),
      next: () => workSession.next(item),
      complete: () => workSession.complete(item),
    })[action]?.();
    if (!transitioned && action !== 'next' && action !== 'complete') {
      qs('#my-work-action-status').textContent = 'Saved Today item is no longer available.';
      updateWorkSessionActions();
    }
  }

  const todayReadiness = createTodayReadiness({
    inspect:inspectTodayDependencies,
    onOpen:performTodayTransition,
    onGate:state => {
      todayReadinessTrigger = document.activeElement;
      renderTodayReadiness(state);
      taskOverlayHistory.open('today-readiness');
    },
    onPreview:blocker => {
      searchPreviewReturnKind = 'today-readiness';
      searchPreview.open({ ...blocker, kind:'issue' }).catch(() => {});
      taskOverlayHistory.open('search-preview');
    },
  });

  function runTodayTransition(action) {
    selectTodayWork();
    const target = workSession.target(action);
    if (!target) {
      performTodayTransition(action);
      return Promise.resolve('empty');
    }
    qs('#my-work-action-status').textContent = 'Checking Today readiness…';
    return todayReadiness.run(action, workSession.items(), target);
  }

  function continueTodaySession() {
    return runTodayTransition('continue');
  }

  function resumeTodaySession() {
    return runTodayTransition('resume');
  }

  function startTodaySession() {
    return runTodayTransition('start');
  }

  const createAndStart = createCreateAndStart({
    todayWork,
    todaySync,
    refresh: refreshMyWorkView,
    warm: warmTodayOffline,
    start: item => {
      qs('[data-work-filter="today"]').click();
      workSession.start(item);
    },
    announce: announceWork,
  });
  function renderCreateStartCapacity() {
    const result = createAndStart.capacity(qs('#create-issue-estimate').value);
    qs('#create-issue-estimate-status').textContent = createAndStart.capacityMessage(result);
    return result;
  }
  qs('#create-issue-estimate').addEventListener('input', () => { renderCreateStartCapacity(); saveIssueCaptureDraft(); });

  const queueToday = createQueueToday({
    todayWork,
    todaySync,
    refresh: refreshMyWorkView,
    warm: warmTodayOffline,
  });
  const laterAndStart = createLaterAndStart({
    todayWork,
    todaySync,
    laterWork,
    refresh: refreshMyWorkView,
    warm: warmTodayOffline,
    start: item => {
      qs('[data-work-filter="today"]').click();
      qs('#my-work-action-status').textContent = 'Checking Today readiness…';
      return todayReadiness.run('start', workSession.items(), item);
    },
    announce: announceWork,
  });

  const selectedSessionItem = kind => ({
    issue: selectedIssue,
    pull: selectedPull,
    review: selectedReview,
    update: selectedUpdate,
  })[kind] || null;
  const completeTodayItem = createTodayCompletion({
    todayWork,
    todaySync,
    workSession,
    refresh: () => refreshMyWorkView({ reconcileSession:false }),
    warm: warmTodayOffline,
    announce: announceWork,
    advance: () => (mobileFirstTask.completeOutcome(), runTodayTransition('complete')),
  });
  todayLockScreen = createTodayLockScreen({
    storage:localStorage,
    getLogin:() => confirmedOwnerLogin,
    serviceWorker:navigator.serviceWorker,
    NotificationRef:window.Notification,
    control:qs('#today-lock-screen'),
    status:qs('#today-lock-screen-status'),
    locationRef:window.location,
    historyRef:window.history,
    onAction:(action, expectedIdentity) => {
      const state = timer.snapshot();
      if (action === 'complete') {
        selectTodayWork();
        if (!state.identity || state.identity !== expectedIdentity) {
          qs('#my-work-action-status').textContent =
            'That lock-screen action is stale. The current Today item was not changed.';
          return;
        }
        const item = todayMyWork.find(entry => todayWork.identity(entry) === expectedIdentity);
        if (!item) {
          qs('#my-work-action-status').textContent =
            'That Today item is no longer available. Nothing was changed.';
          return;
        }
        workSession.reopen(item);
        completeTodayItem(item);
        timerView.render();
        return;
      }
      if (!state.identity || (action === 'pause' && !state.running) ||
          (action === 'resume' && state.running)) return;
      const changed = action === 'pause' ? timer.pause() : timer.resume();
      if (changed === false) return;
      selectTodayWork();
      const item = todayMyWork.find(entry => todayWork.identity(entry) === state.identity);
      if (item) workSession.reopen(item);
      timerView.render();
    },
  });
  await todayLockScreen.sync(timer.snapshot(), workSession.checkpointed());
  await todayLockScreen.consumeLaunchAction();
  async function completeOwnershipExitToday(item) {
    if (!item || !todayWork.remove(item)) return null;
    todaySync.enqueue('remove', todayWork.identity(item));
    todaySync.flush();
    refreshMyWorkView({ reconcileSession:false });
    warmTodayOffline();
    return await runTodayTransition('complete');
  }
  function setCommentNextVisibility(kind) {
    const item = kind === 'issue' ? selectedIssue : selectedPull;
    qs('#send-' + kind + '-comment-next').hidden = !item || !workSession.checkpointed(item);
  }

  const issueCommentNext = createCommentNext({
    post: async (item, body) => {
      const comment = await issueController.comment(item, body);
      if (selectedIssue === item && issueConversation) renderIssueConversation(issueConversation.append(comment));
      return comment;
    },
    queue: message => authoredOutbox.enqueueDurably(message),
    canQueue: canQueueMessage,
    accept: item => {
      issueController.saveDraft(item, '');
      if (selectedIssue === item) qs('#issue-comment').value = '';
    },
    complete: item => completeTodayItem(item, {
      successMessage: 'Comment saved. Next Today item opened.',
      failureMessage: 'Comment saved, but Today still needs completion.',
    }),
  });
  const pullCommentNext = createCommentNext({
    post: async (item, body) => {
      const comment = await pullController.comment(item, body);
      if (selectedPull === item && pullConversation) renderPullConversation(pullConversation.append(comment));
      return comment;
    },
    queue: message => authoredOutbox.enqueueDurably(message),
    canQueue: canQueueMessage,
    accept: item => {
      pullController.saveDraft(item, '');
      if (selectedPull === item) qs('#pull-comment').value = '';
    },
    complete: item => completeTodayItem(item, {
      successMessage: 'Comment saved. Next Today item opened.',
      failureMessage: 'Comment saved, but Today still needs completion.',
    }),
  });
  const updateReplyReadNext = createUpdateReplyReadNext({
    post: (item, body, operationId) => postNotificationReply(item.notification_id, body, operationId),
    markRead: markNotificationRead,
    queue: message => authoredOutbox.enqueueDurably(message),
    deliver: item => authoredOutbox.retry(item.id, activeFlushLogin),
    canQueue: canQueueMessage,
    accept: item => {
      notificationReplier.saveDraft(item, '');
      if (selectedUpdate === item) qs('#update-reply').value = '';
    },
    next: item => notificationReader.acceptReadAndNext(lastMyWork, item),
  });
  const closeOfflineIssue = createOfflineIssueClose({
    enqueueDurably: message => authoredOutbox.enqueueDurably(message),
    completeToday: (item, options) => completeTodayItem(item, options),
  });

  function reviewingActiveTodayItem() {
    return workSession.checkpointed();
  }

  function acceptClaimedIssue(confirmed) {
    lastContextSnapshot = lastContextSnapshot || { user: {}, repos: [], issues: [], pull_requests: [] };
    lastContextSnapshot.issues = [confirmed].concat((lastContextSnapshot.issues || []).filter(candidate =>
      candidate.repository !== confirmed.repository || candidate.number !== confirmed.number
    ));
    lastMyWork = buildMyWork(lastContextSnapshot);
    return lastMyWork.find(work =>
      work.kind === 'issue' && work.repository === confirmed.repository && work.number === confirmed.number
    );
  }

  const assignAndStart = createAssignAndStart({
    available: createAndStart.available,
    claim: item => findWorkController.claim(item),
    start: confirmed => {
      const claimed = acceptClaimedIssue(confirmed);
      taskOverlayHistory.leave();
      refreshMyWorkView();
      return createAndStart.complete(claimed);
    },
    queue: confirmed => {
      const claimed = acceptClaimedIssue(confirmed);
      return queueToday(claimed);
    },
    recover: confirmed => {
      const claimed = acceptClaimedIssue(confirmed);
      taskOverlayHistory.leave();
      refreshMyWorkView();
      openRoutedWork(claimed, qs('#find-work'));
    },
    announce: message => {
      qs('#find-work-status').textContent = message;
      qs('#my-work-action-status').textContent = message;
    },
  });

  const filedAssignAndStart = createAssignAndStart({
    available: createAndStart.available,
    claim: item => findWorkController.claim(item),
    start: confirmed => {
      const claimed = acceptClaimedIssue(confirmed);
      closeIssueSheet(false);
      refreshMyWorkView();
      return createAndStart.complete(claimed);
    },
    queue: confirmed => {
      const claimed = acceptClaimedIssue(confirmed);
      const outcome = queueToday(claimed);
      closeIssueSheet(false);
      refreshMyWorkView();
      openRoutedWork(claimed, qs('#my-work'));
      return outcome;
    },
    recover: confirmed => {
      const claimed = acceptClaimedIssue(confirmed);
      closeIssueSheet(false);
      refreshMyWorkView();
      openRoutedWork(claimed, qs('#my-work'));
    },
    announce: message => {
      qs('#issue-sheet-status').textContent = message;
      qs('#my-work-action-status').textContent = message;
    },
  });

  const batchFindWork = createBatchFindWork({
    capacity: () => Math.max(0, todayWork.limit - todayWork.read().length),
    owner:()=>planningOwnerLogin,timeBudget:()=>{
      const plan = todayWork.planning();
      return {
        capacity_minutes: plan.capacity_minutes,
        planned_minutes: Object.values(plan.estimates).reduce((sum, minutes) => sum + minutes, 0),
      };
    },
    claim: item => findWorkController.claim(item),
    queue: confirmed => queueToday(acceptClaimedIssue(confirmed)),
    persistEstimate: (confirmed, minutes) => {
      const plan = todayWork.planning();
      plan.estimates[todayWork.identity(confirmed)] = minutes;
      todayWork.replacePlanning(plan);
      todaySync.enqueueConfiguration(plan.capacity_minutes, plan.estimates);
      todaySync.flush();
    },
    onProgress: progress => {
      if (progress.status === 'full') {
        qs('#find-work-status').textContent = 'Today has ' + progress.available +
          ' open slot' + (progress.available === 1 ? '' : 's') + '. Reduce the selection before assigning.';
      } else if (progress.status === 'estimates-required') {
        qs('#find-work-estimate-summary').textContent = 'Add an estimate for every issue.';
      } else if (progress.status === 'over-budget') {
        qs('#find-work-estimate-summary').textContent = formatPlanMinutes(progress.over_minutes) +
          ' over Today’s remaining time. Reduce an estimate or selection.';
      } else if (progress.status === 'running') {
        qs('#find-work-status').textContent = 'Assigning and queueing ' + progress.processed +
          ' of ' + progress.selected + '…';
      }
    },
  });

  function findWorkEstimateValues() {
    return Object.fromEntries(Array.from(document.querySelectorAll('[data-find-work-estimate]')).map(input =>
      [input.dataset.findWorkEstimate, Number(input.value)]
    ));
  }

  function openFindWorkEstimateReview(items) {
    const plan = todayWork.planning();
    const planned = Object.values(plan.estimates).reduce((sum, minutes) => sum + minutes, 0);
    const estimatesRequired = Number.isInteger(plan.capacity_minutes) && plan.capacity_minutes > 0;
    qs('#find-work-estimate-summary').textContent = estimatesRequired ?
      formatPlanMinutes(Math.max(0, plan.capacity_minutes - planned)) +
        ' remaining. Estimate selected work before assigning it.' :
      items.length + ' selected. Confirm to assign and queue this batch in Today.';
    qs('#find-work-estimate-list').innerHTML = items.map(item => {
      const id = String(item.repository || '') + '#' + String(item.number || '');
      return '<div class="find-work-estimate-row"><div><span class="small">' + escapeHtml(id) +
        '</span><strong>' + escapeHtml(item.title || 'Untitled work') + '</strong></div>' +
        (estimatesRequired ? '<label class="small"><input type="number" inputmode="numeric" min="5" max="1440" step="5" data-find-work-estimate="' +
          escAttr(id) + '" aria-label="Estimate for ' + escAttr(item.title || id) + ' in minutes" /> min</label>' : '') + '</div>';
    }).join('');
    if (estimatesRequired) qs('[data-find-work-estimate]')?.focus();
  }

  function formatCalendarDueDate(value) {
    const match = String(value || '').match(/^(\d{4})-(\d{2})-(\d{2})(?:$|T)/);
    if (!match) return '';
    return new Intl.DateTimeFormat(undefined).format(
      new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]))
    );
  }

  let planTodayTrigger = null;
  let pendingProtectToday = null;
  function formatPlanMinutes(minutes) {
    if (!Number.isInteger(minutes)) return 'Not set';
    const absolute = Math.abs(minutes);
    const hours = Math.floor(absolute / 60);
    const remainder = absolute % 60;
    return [hours ? hours + 'h' : '', remainder ? remainder + 'm' : ''].filter(Boolean).join(' ') || '0m';
  }

  function planTodayItemMarkup(item, selected, index = -1) {
    const id = todayWork.identity(item);
    const key = escapeHtml(item.key || (item.repository + '#' + (item.number || '')));
    const title = escapeHtml(item.title || 'Untitled work');
    const state = planToday.snapshot();
    const estimate = state.estimates?.[id] || '';
    const recommendation = state.recommendations?.[id];
    const estimateControl = selected ? '<label class="small plan-today-estimate-wrap">Estimate <input class="plan-today-estimate" type="number" inputmode="numeric" min="5" max="1440" step="5" value="' + escAttr(estimate) + '" data-plan-estimate="' + escAttr(id) + '" aria-label="Estimate for ' + escAttr(item.title || key) + ' in minutes" /> min</label>' : '';
    const recommendationControl = selected && recommendation ? '<button class="plan-today-recommendation" type="button" data-plan-recommendation="' +
      escAttr(id) + '">Use ' + formatPlanMinutes(recommendation) + ' as new estimate</button>' : '';
    const controls = selected ?
      '<div class="plan-today-item-actions"><button type="button" data-plan-move="up" data-plan-id="' + escAttr(id) + '"' + (index === 0 ? ' disabled' : '') + '>Up</button><button type="button" data-plan-move="down" data-plan-id="' + escAttr(id) + '"' + (index === state.count - 1 ? ' disabled' : '') + '>Down</button><button type="button" data-plan-remove="' + escAttr(id) + '">Remove</button></div>' :
      (item.kind === 'issue' ?
        '<div class="plan-today-candidate-actions"><button type="button" data-plan-preview="' + escAttr(id) + '">Preview to add</button></div>' :
        '<div class="plan-today-candidate-actions"><button type="button" data-plan-preview="' + escAttr(id) + '">Preview</button><button type="button" data-plan-add="' + escAttr(id) + '">Add</button></div>');
    return '<article class="plan-today-item"><div class="plan-today-item-copy"><span class="small">' + key + '</span><strong class="my-work-card-title">' + title + '</strong>' + estimateControl + recommendationControl + '</div>' + controls + '</article>';
  }

  function resetPlanTodayConfirmation() {
    const save = qs('#save-today-plan');
    const start = qs('#save-and-start-today');
    save.dataset.confirmOverCapacity = '';
    start.dataset.confirmOverCapacity = '';
    save.textContent = 'Save plan';
    start.textContent = 'Save & start';
  }

  function renderPlanToday() {
    resetPlanTodayConfirmation();
    const state = planToday.snapshot();
    const capacityText = state.capacity_minutes === null ? 'Set available time to check fit' :
      (state.over_capacity ? formatPlanMinutes(-state.remaining_minutes) + ' over capacity' :
        formatPlanMinutes(state.remaining_minutes) + ' free');
    qs('#plan-today-capacity').textContent = state.count + ' of ' + state.limit + ' selected · Planned ' +
      formatPlanMinutes(state.planned_minutes) + ' · ' + capacityText +
      (state.unestimated_count ? ' · ' + state.unestimated_count + ' unestimated' : '');
    qs('#plan-today-available').value = state.capacity_minutes || '';
    const build = state.build;
    qs('#plan-today-build-status').textContent = build ?
      ('Built ' + build.selected.length + ' ready ' + (build.selected.length === 1 ? 'item' : 'items') +
        (build.skipped.length ? ' · Skipped ' + build.skipped.length + ' blocked or unverified' : '') +
        (build.needs_estimate.length ? ' · ' + build.needs_estimate.length + ' need estimates' : '')) : '';
    const estimateSection = qs('#plan-today-estimates');
    estimateSection.hidden = !build?.needs_estimate.length;
    qs('#plan-today-estimate-list').innerHTML = (build?.needs_estimate || []).map(id => {
      const item = planToday.item(id);
      const key = escapeHtml(item?.key || ((item?.repository || '') + '#' + (item?.number || '')));
      return '<div class="plan-today-estimate-row"><div><span class="small">' + key + '</span><strong class="my-work-card-title">' +
        escapeHtml(item?.title || 'Untitled work') + '</strong></div><label class="small"><input type="number" inputmode="numeric" min="5" max="1440" step="5" data-plan-missing-estimate="' +
        escAttr(id) + '" aria-label="Estimate for ' + escAttr(item?.title || key) + ' in minutes" /> min</label></div>';
    }).join('');
    qs('#plan-today-skipped').innerHTML = (build?.skipped || []).map(entry =>
      '<div class="small plan-today-skipped-item"><strong>' + escapeHtml(planToday.item(entry.id)?.title || entry.id) +
      '</strong> · ' + escapeHtml(entry.reason) + '</div>'
    ).join('');
    qs('#plan-today-list').innerHTML = state.ids.length ? state.ids.map((id, index) =>
      planTodayItemMarkup(planToday.item(id), true, index)
    ).join('') : '<p class="muted">No work selected yet.</p>';
    const candidates = planToday.candidates();
    qs('#plan-today-candidates').innerHTML = candidates.length ? candidates.map(item =>
      planTodayItemMarkup(item, false)
    ).join('') : '<p class="muted">All available work is already selected.</p>';
    document.querySelectorAll('[data-plan-add]').forEach(button => button.addEventListener('click', () => {
      const result = planToday.toggle(planToday.item(button.dataset.planAdd));
      qs('#plan-today-error').textContent = result === 'full' ? 'Today is full. Remove an item before adding another.' : '';
      renderPlanToday();
    }));
    document.querySelectorAll('[data-plan-preview]').forEach(button => button.addEventListener('click', () => {
      const item = planToday.item(button.dataset.planPreview);
      if (!canPreviewPlanItem(item)) {
        qs('#plan-today-error').textContent = 'Preview unavailable offline. Reconnect or add the item without previewing it.';
        return;
      }
      qs('#plan-today-error').textContent = '';
      if (planTodayPreview.open(item, button)) taskOverlayHistory.open('plan-today-preview');
    }));
    document.querySelectorAll('[data-plan-remove]').forEach(button => button.addEventListener('click', () => {
      planToday.toggle(planToday.item(button.dataset.planRemove));
      qs('#plan-today-error').textContent = '';
      renderPlanToday();
    }));
    document.querySelectorAll('[data-plan-move]').forEach(button => button.addEventListener('click', () => {
      planToday.move(button.dataset.planId, button.dataset.planMove);
      renderPlanToday();
      document.querySelector('[data-plan-id="' + CSS.escape(button.dataset.planId) + '"][data-plan-move="' + button.dataset.planMove + '"]')?.focus();
    }));
    document.querySelectorAll('[data-plan-estimate]').forEach(input => input.addEventListener('change', () => {
      planToday.setEstimate(input.dataset.planEstimate, Number(input.value));
      renderPlanToday();
    }));
    document.querySelectorAll('[data-plan-missing-estimate]').forEach(input => input.addEventListener('change', () => {
      const id = input.dataset.planMissingEstimate;
      if (!input.checkValidity() || !planToday.setEstimate(id, Number(input.value))) {
        qs('#plan-today-error').textContent = 'Enter an estimate from 5 minutes to 24 hours.';
        input.focus();
        return;
      }
      qs('#plan-today-error').textContent = '';
      renderPlanToday();
      document.querySelector('[data-plan-missing-estimate]')?.focus();
    }));
    document.querySelectorAll('[data-plan-recommendation]').forEach(button => button.addEventListener('click', () => {
      planToday.applyRecommendation(button.dataset.planRecommendation);
      renderPlanToday();
      document.querySelector('[data-plan-estimate="' + CSS.escape(button.dataset.planRecommendation) + '"]')?.focus();
    }));
  }

  function closePlanToday(navigate = true) {
    planTodayReadiness.cancel();
    qs('#build-today-plan').disabled = false;
    qs('#plan-today-build-status').textContent = '';
    if (navigate) {
      taskOverlayHistory.close();
      return;
    }
    planToday.cancel();
    planningTomorrow = false;
    weekWorkflow.clear();
    qs('#tomorrow-conflict-review').hidden = true;
    qs('#plan-today-sheet').classList.remove('tomorrow-conflict-mode');
    qs('#week-conflict-review').hidden = true;
    qs('#plan-today-sheet').classList.remove('week-conflict-mode');
    qs('#plan-today-sheet').hidden = true;
    document.body.classList.remove('task-overlay-open');
    if (planTodayTrigger?.dataset.mobileQueue === 'tomorrow') {
      if (!qs('#mobile-queue-sheet').open) qs('#mobile-queue-sheet').showModal();
    }
    planTodayTrigger?.focus();
  }

  function saveTodayPlan(plan) {
    const capacityAware = !Array.isArray(plan);
    const ids = capacityAware ? plan.ids : plan;
    const previous = todayWork.read();
    if (rolloverReviewPlan) {
      const operation = todayRollover.operation({
        operation_id: 'pending', base_revision: rolloverReviewPlan.revision,
        selected_ids: ids, capacity_minutes: plan.capacity_minutes, estimates: plan.estimates,
      });
      if (!todaySync.enqueueRollover(operation)) return false;
      rolloverReviewPlan = null;
      qs('#plan-today').textContent = 'Plan Today';
      qs('#plan-today-title').textContent = 'Plan Today';
    } else {
      const operations = previous.map(id => ['remove', id]).concat(ids.map(id => ['add', id]));
      if (!operations.every(([action, id]) => todaySync.enqueue(action, id))) return false;
      if (capacityAware && !todaySync.enqueueConfiguration(plan.capacity_minutes, plan.estimates)) return false;
    }
    if (!todayWork.replace(ids)) return false;
    if (capacityAware && !todayWork.replacePlanning(plan)) return false;
    todayRecapView.completeReplan();
    refreshMyWorkView();
    todaySync.flush();
    warmTodayOffline();
    qs('#my-work-action-status').textContent = ids.length ? 'Today plan saved in your chosen order and available time.' : 'Today plan cleared.';
    return true;
  }

  function saveTomorrowPlan(plan) {
    const normalized = Array.isArray(plan) ?
      {ids:plan, capacity_minutes:null, estimates:{}} : plan;
    const staged = tomorrowPlan.stage(normalized);
    if (!staged) {
      qs('#my-work-action-status').textContent =
        'Tomorrow could not be saved on this phone. Free browser storage and retry.';
      return false;
    }
    renderTomorrowQueueSummary(staged);
    qs('#my-work-action-status').textContent = 'Tomorrow saved on this phone · sync pending.';
    syncPendingTomorrow();
    return true;
  }

  const planToday = createPlanToday({
    identity: item => todayWork.identity(item),
    limit: todayWork.limit,
    save: plan => weekWorkflow.active() ? weekWorkflow.save(plan) :
      (planningTomorrow ? saveTomorrowPlan(plan) : saveTodayPlan(plan)),
    start: () => {
      qs('[data-work-filter="today"]').click();
      startTodaySession();
    },
  });

  const planTodayReadiness = createPlanTodayReadiness({
    concurrency:3,
    identity:item => todayWork.identity(item),
    inspect:async item => {
      if (item.kind !== 'issue') return { status:'ready' };
      const detail = await inspectTodayDependencies(item);
      if (!detail.available) return { status:'unverified' };
      if (detail.dependencies.length) return {
        status:'blocked', reason:detail.dependencies.length + ' open ' +
          (detail.dependencies.length === 1 ? 'dependency' : 'dependencies'),
      };
      return { status:'ready' };
    },
  });

  async function buildTodayPlan() {
    const button = qs('#build-today-plan');
    const state = planToday.snapshot();
    const candidates = state.ids.map(id => planToday.item(id)).concat(planToday.candidates());
    button.disabled = true;
    qs('#plan-today-build-status').textContent = 'Checking readiness and fitting your highest-ranked work…';
    const checks = await planTodayReadiness.run(candidates);
    if (!checks) return;
    planToday.buildRecommendation(checks);
    button.disabled = false;
    renderPlanToday();
  }

  function canPreviewPlanItem(item) {
    if (!item || !offlineWorkMode) return Boolean(item);
    const login = planningOwnerLogin || confirmedOwnerLogin ||
      String(offlineWorkStore.load()?.user?.login || '').trim();
    return Boolean(offlineWorkStore.loadDetail(login, item));
  }

  function openPlanPreviewDetail(item, trigger) {
    qs('#plan-today-sheet').hidden = true;
    qs('#plan-preview-actions').hidden = false;
    if (item.kind === 'issue') renderPlanIssueDependencies(null, true);
    if (offlineWorkMode) {
      openRoutedWork(item, trigger);
    } else if (item.kind === 'update' && item.has_update) {
      updateTrigger = trigger;
      notificationReader.open(item, lastMyWork);
    } else if (item.is_review || item.kind === 'review') {
      reviewTrigger = trigger;
      openReviewSheet(item, trigger);
    } else if (item.kind === 'issue') {
      issueTrigger = trigger;
      openIssueSheet(item, trigger);
    } else if (item.kind === 'pull') {
      pullTrigger = trigger;
      openPullSheet(item, trigger);
    }
  }

  const planTodayPreview = createPlanTodayPreview({
    planner: planToday,
    identity: item => todayWork.identity(item),
    getScroll: () => qs('.plan-today-panel').scrollTop,
    setScroll: value => requestAnimationFrame(() => { qs('.plan-today-panel').scrollTop = value; }),
    onOpen: openPlanPreviewDetail,
    onClose: (_item, trigger) => {
      closeOpenWorkSheets();
      qs('#plan-preview-actions').hidden = true;
      qs('#issue-blockers').hidden = true;
      qs('#issue-blocker-list').textContent = '';
      qs('#add-plan-preview').disabled = false;
      qs('#add-plan-preview').textContent = 'Add to Today & back';
      qs('#plan-today-sheet').hidden = false;
      renderPlanToday();
      requestAnimationFrame(() => trigger?.focus());
    },
  });

  function renderPlanIssueDependencies(detail, loading = false) {
    const preview = planTodayPreview.snapshot();
    const assignedIssue = Boolean(!preview.open && selectedIssue && selectedIssueDetail === detail);
    if (!assignedIssue && (!preview.open || preview.item?.kind !== 'issue')) return;
    const panel = qs('#issue-blockers');
    const list = qs('#issue-blocker-list');
    const status = qs('#issue-blocker-status');
    const addButton = qs('#add-plan-preview');
    panel.hidden = false;
    list.innerHTML = '';
    qs('#manage-issue-blockers').hidden = !assignedIssue;
    qs('#start-unblocked-issue').hidden = true;
    if (!assignedIssue) qs('#issue-blocker-manager').hidden = true;
    if (assignedIssue) {
      const available = detail?.dependencies_available === true;
      const dependencies = Array.isArray(detail?.dependencies) ? detail.dependencies : [];
      list.innerHTML = dependencies.map((blocker, index) =>
        '<div class="issue-blocker-row"><a class="issue-blocker" href="' + escAttr(blocker.url || '#') +
        '" target="_blank" rel="noopener noreferrer"><strong>' + escapeHtml(blocker.repository + '#' + blocker.number) +
        ' · ' + escapeHtml(blocker.title || 'Untitled blocker') + '</strong><span class="small">State: ' +
        escapeHtml(blocker.state || 'open') + '</span></a><button class="issue-blocker-remove" type="button" data-remove-blocker-index="' +
        index + '">Remove blocker</button></div>'
      ).join('');
      list.querySelectorAll('[data-remove-blocker-index]').forEach(button => {
        button.addEventListener('click', () => {
          const blocker = dependencies[Number(button.dataset.removeBlockerIndex)];
          if (blocker && window.confirm('Remove ' + blocker.repository + '#' + blocker.number + ' as a blocker?')) {
            mutateIssueBlocker(blocker, true, button);
          }
        });
      });
      status.textContent = available ? (dependencies.length ?
        dependencies.length + (dependencies.length === 1 ? ' unresolved blocker.' : ' unresolved blockers.') :
        'No unresolved blockers. Add one without leaving this issue.') :
        'Blocker status unavailable. Reload before changing relationships.';
      qs('#manage-issue-blockers').disabled = !available;
      return;
    }
    addButton.disabled = loading;
    addButton.dataset.planOverride = '';
    if (loading) {
      status.textContent = 'Checking unresolved blockers…';
      addButton.textContent = 'Checking blockers…';
      return;
    }
    const available = detail?.dependencies_available === true;
    const dependencies = Array.isArray(detail?.dependencies) ? detail.dependencies : [];
    planTodayPreview.setDependencies({ available, dependencies });
    if (!available) {
      status.textContent = 'Blocker status unavailable. Adding requires an explicit override.';
      addButton.textContent = 'Add without blocker status anyway & back';
      addButton.dataset.planOverride = 'true';
      return;
    }
    if (dependencies.length) {
      list.innerHTML = dependencies.map(blocker =>
        '<a class="issue-blocker" href="' + escAttr(blocker.url || '#') + '" target="_blank" rel="noopener noreferrer"><strong>' +
          escapeHtml(blocker.repository + '#' + blocker.number) + ' · ' + escapeHtml(blocker.title || 'Untitled blocker') +
          '</strong><span class="small">State: ' + escapeHtml(blocker.state || 'open') + '</span></a>'
      ).join('');
      status.textContent = dependencies.length + (dependencies.length === 1 ? ' unresolved blocker.' : ' unresolved blockers.');
      addButton.textContent = 'Add blocked item anyway & back';
      addButton.dataset.planOverride = 'true';
      return;
    }
    panel.hidden = true;
    status.textContent = '';
    addButton.textContent = 'Add to Today & back';
  }

  async function mutateIssueBlocker(blocker, remove, button) {
    if (!selectedIssue) return;
    const item = selectedIssue;
    button.disabled = true;
    qs('#issue-blocker-status').textContent = remove ? 'Removing blocker…' : 'Adding blocker…';
    try {
      if (selectedIssueOffline) {
        await queueOfflineIssueBlocker(item, blocker, !remove);
        if (selectedIssue !== item) return;
        button.textContent = 'Queued';
        qs('#issue-blocker-status').textContent = remove ?
          'Blocker removal queued. Today remains blocked until Stackchain confirms delivery.' :
          'Blocker addition queued. Today readiness will update after Stackchain confirms delivery.';
        return { queued:true };
      }
      const result = remove ?
        await issueController.updateBlocker(selectedIssue, blocker, true) :
        await issueController.updateBlocker(selectedIssue, blocker, false);
      if (selectedIssue !== item) return;
      selectedIssueDetail = { ...selectedIssueDetail, ...result };
      renderPlanIssueDependencies(selectedIssueDetail);
      if (remove && result.dependencies.length === 0 && workSession.checkpointed(item)) {
        qs('#issue-blocker-status').textContent = 'All blockers cleared. This Today item is ready.';
        qs('#start-unblocked-issue').hidden = false;
      }
    } catch (error) {
      if (selectedIssue !== item) return;
      qs('#issue-blocker-status').textContent = error.message + ' The previous blocker list is unchanged; reload before retrying.';
      button.disabled = false;
      button.focus();
    }
  }

  function renderIssueBlockerCandidates(items) {
    issueBlockerCandidates = items;
    const results = qs('#issue-blocker-results');
    results.innerHTML = items.map((result, index) =>
      '<button type="button" role="option" data-blocker-result="' + index + '"><strong>' +
      escapeHtml(result.repository + '#' + result.number) + '</strong><span class="small">' +
      escapeHtml(result.title || 'Untitled issue') + '</span></button>'
    ).join('');
    results.querySelectorAll('[data-blocker-result]').forEach(button => {
      button.addEventListener('click', () => {
        const blocker = issueBlockerCandidates[Number(button.dataset.blockerResult)];
        if (blocker) mutateIssueBlocker(blocker, false, button).then(outcome => {
          if (outcome?.queued || selectedIssueDetail?.dependencies?.some(candidate =>
            candidate.repository === blocker.repository && candidate.number === blocker.number
          )) {
            qs('#issue-blocker-manager').hidden = true;
            qs('#issue-blocker-search').setAttribute('aria-expanded', 'false');
          }
        });
      });
    });
  }

  qs('#manage-issue-blockers').addEventListener('click', () => {
    qs('#issue-blocker-manager').hidden = false;
    qs('#issue-blocker-search').setAttribute('aria-expanded', 'true');
    qs('#issue-blocker-search-status').textContent = 'Enter at least 2 characters.';
    qs('#issue-blocker-search').focus();
  });
  qs('#cancel-issue-blocker').addEventListener('click', () => {
    qs('#issue-blocker-manager').hidden = true;
    qs('#issue-blocker-search').setAttribute('aria-expanded', 'false');
    qs('#manage-issue-blockers').focus();
  });
  qs('#issue-blocker-search').addEventListener('keydown', event => {
    if (event.key === 'Escape') qs('#cancel-issue-blocker').click();
  });
  qs('#issue-blocker-search').addEventListener('input', event => {
    clearTimeout(issueBlockerSearchTimer);
    const query = event.target.value.trim();
    if (query.length < 2) {
      renderIssueBlockerCandidates([]);
      qs('#issue-blocker-search-status').textContent = 'Enter at least 2 characters.';
      return;
    }
    qs('#issue-blocker-search-status').textContent = 'Searching open issues…';
    issueBlockerSearchTimer = setTimeout(async () => {
      try {
        const candidates = selectedIssueOffline ? workSession.items() :
          (await api('api/v1/search?q=' + encodeURIComponent(query) + '&limit=10')).items;
        const existing = selectedIssueDetail?.dependencies || [];
        const normalizedQuery = query.toLowerCase();
        const items = (candidates || []).filter(result =>
          result.kind === 'issue' && result.state === 'open' &&
          (!selectedIssueOffline || (String(result.repository || '') + '#' + result.number + ' ' + String(result.title || ''))
            .toLowerCase().includes(normalizedQuery)) &&
          !(result.repository === selectedIssue?.repository && result.number === selectedIssue?.number) &&
          !existing.some(blocker => blocker.repository === result.repository && blocker.number === result.number)
        );
        renderIssueBlockerCandidates(items);
        qs('#issue-blocker-search-status').textContent = items.length ?
          items.length + (items.length === 1 ? ' open issue found.' : ' open issues found.') : 'No eligible open issues found.';
      } catch (error) {
        renderIssueBlockerCandidates([]);
        qs('#issue-blocker-search-status').textContent = error.message + ' Retry your search.';
      }
    }, 250);
  });
  qs('#start-unblocked-issue').addEventListener('click', () => {
    if (selectedIssue) todayReadiness.run('start', workSession.items(), selectedIssue);
  });

  let addPlanPreviewOnReturn = false;
  let addPlanPreviewOverride = false;

  qs('#back-to-plan').addEventListener('click', () => {
    addPlanPreviewOnReturn = false;
    addPlanPreviewOverride = false;
    taskOverlayHistory.close();
  });
  qs('#add-plan-preview').addEventListener('click', () => {
    addPlanPreviewOnReturn = true;
    addPlanPreviewOverride = qs('#add-plan-preview').dataset.planOverride === 'true';
    taskOverlayHistory.close();
  });

  let pendingPlanActualMinutes = null;
  function tomorrowConflictPlanMarkup(value) {
    const ids = value?.ids || [];
    const estimates = value?.estimates || {};
    const estimated = ids.reduce((total, id) => total + (Number(estimates[id]) || 0), 0);
    const capacity = Number(value?.capacity_minutes) || 0;
    const summary = ids.length ? `${ids.length} planned` +
      (estimated && capacity ? ` · ${estimated} of ${capacity} min` : '') : 'Nothing planned';
    const available = [...todayMyWork, ...activeMyWork];
    const items = ids.map(id => {
      const item = available.find(candidate => todayWork.identity(candidate) === id);
      const label = item?.title || item?.key || id;
      const estimate = Number(estimates[id]) || 0;
      return `<li><strong>${escapeHtml(label)}</strong>${estimate ? ` <span>· ${estimate}&nbsp;min</span>` : ''}</li>`;
    }).join('');
    return `<p class="tomorrow-conflict-plan-summary">${summary}</p>` +
      (items ? `<ol class="tomorrow-conflict-plan-list">${items}</ol>` : '<p class="muted">No work selected.</p>');
  }

  function showTomorrowConflict(conflict) {
    qs('#plan-today-title').textContent = 'Resolve Tomorrow conflict';
    qs('#tomorrow-conflict-phone-plan').innerHTML = tomorrowConflictPlanMarkup(conflict.local);
    qs('#tomorrow-conflict-server-plan').innerHTML = tomorrowConflictPlanMarkup(conflict.remote);
    qs('#tomorrow-conflict-status').textContent = '';
    qs('#tomorrow-conflict-review').hidden = false;
    qs('#plan-today-sheet').classList.add('tomorrow-conflict-mode');
    qs('#plan-today-sheet').hidden = false;
    document.body.classList.add('task-overlay-open');
    const keep = qs('#keep-phone-tomorrow');
    keep.focus();
    requestAnimationFrame(() => keep.focus());
  }

  function showWeekConflict(conflict) {
    qs('#plan-today-title').textContent='Resolve Week Ahead conflict';
    const focus=weekWorkflow.renderConflict(conflict);
    qs('#week-conflict-status').textContent='';
    qs('#week-conflict-review').hidden=false;
    qs('#plan-today-sheet').classList.add('week-conflict-mode');
    qs('#plan-today-sheet').hidden=false;
    document.body.classList.add('task-overlay-open');
    focus.focus();requestAnimationFrame(()=>focus.focus());
  }

  function openPlanToday(trigger, navigate = true, actualMinutes = null) {
    if (!planningOwnerLogin && !weekWorkflow.active()) {
      qs('#my-work-action-status').textContent = 'Planning is unavailable until your operator identity is restored.';
      return;
    }
    if (trigger) planTodayTrigger = trigger;
    const weekCopy=weekWorkflow.copy();
    qs('#plan-today-title').textContent = weekCopy ? weekCopy.title : (planningTomorrow ? 'Plan Tomorrow' :
      (pendingProtectToday ? 'Protect Today' : (rolloverReviewPlan ? 'New day review' : 'Plan Today')));
    if (actualMinutes) pendingPlanActualMinutes = actualMinutes;
    if (navigate) {
      taskOverlayHistory.open('plan-today');
      return;
    }
    const conflict = planningTomorrow ? tomorrowPlan.conflict() : null;
    if (conflict) {
      showTomorrowConflict(conflict);
      return;
    }
    const weekConflict=weekWorkflow.active()?weekPlan.conflict():null;
    if(weekConflict){showWeekConflict(weekConflict);return;}
    qs('#tomorrow-conflict-review').hidden = true;
    qs('#plan-today-sheet').classList.remove('tomorrow-conflict-mode');
    qs('#week-conflict-review').hidden=true;
    qs('#plan-today-sheet').classList.remove('week-conflict-mode');
    const recommendations = actualMinutes || pendingPlanActualMinutes || todayRecapView.pendingReplan()?.actual_minutes;
    pendingPlanActualMinutes = null;
    const protectProposal = pendingProtectToday;
    const tomorrow = planningTomorrow ? tomorrowPlan.state() : null;
    const weekDay = weekWorkflow.day();
    const availablePlanningItems = [...todayMyWork, ...activeMyWork].filter((item, index, items) =>
      items.findIndex(candidate => todayWork.identity(candidate) === todayWork.identity(item)) === index
    );
    const selected = (planningTomorrow || weekCopy) ? availablePlanningItems.filter(item =>
      (weekDay || tomorrow).ids.includes(todayWork.identity(item))
    ) : (protectProposal?.selected || todayMyWork);
    planToday.open(selected, activeMyWork, weekDay || (planningTomorrow ? tomorrow : todayWork.planning()), recommendations);
    qs('#today-plan-heading').textContent = weekCopy ? weekCopy.heading : (planningTomorrow ? 'Tomorrow, in order' : 'Today, in order');
    qs('.plan-today-available').firstChild.textContent = weekCopy ? weekCopy.available : (planningTomorrow ? 'Available this day' : 'Available today');
    qs('#build-today-plan').textContent = weekCopy ? weekCopy.build : (planningTomorrow ? 'Build my Tomorrow' : 'Build my Today');
    qs('#save-and-start-today').hidden = planningTomorrow || Boolean(weekCopy);
    pendingProtectToday = null;
    qs('#discard-recap-replan').hidden = !todayRecapView.pendingReplan();
    qs('#plan-today-error').textContent = '';
    qs('#plan-today-sheet').hidden = false;
    document.body.classList.add('task-overlay-open');
    weekWorkflow.renderDates();
    renderPlanToday();
    if (protectProposal) qs('#plan-today-build-status').textContent = protectProposal.summary +
      (protectProposal.displaced.length ? '. Displaced work remains unchanged until you save.' : '. Review estimates and capacity before saving.');
    qs('#cancel-plan-today').focus();
  }

  qs('#protect-today').addEventListener('click', event => {
    const proposal = protectToday.propose({
      agenda:agendaMyWork(activeMyWork), today:todayMyWork,
      identity:item => todayWork.identity(item), limit:todayWork.limit,
    });
    if (!proposal.protected.length) {
      qs('#protect-today-status').textContent = 'No overdue or due-today work needs protection.';
      return;
    }
    pendingProtectToday = proposal;
    openPlanToday(event.currentTarget);
  });

  qs('#discard-recap-replan').addEventListener('click', () => {
    todayRecapView.discardReplan();
    planToday.open(todayMyWork, activeMyWork, todayWork.planning());
    qs('#discard-recap-replan').hidden = true;
    qs('#plan-today-error').textContent = 'Recap feedback discarded. Your saved recap is unchanged.';
    renderPlanToday();
  });

  const detailDefer = createDetailDefer({
    laterWork,
    session: workSession,
    continueSession: item => completeTodayItem(item, {
      successMessage: 'Deferred to Later. Next Today item opened.',
      failureMessage: 'Could not remove this item from Today.',
    }),
    close: () => workRoute.close(),
    refresh: refreshMyWorkView,
    focus: () => qs('[data-work-filter="' + selectedWorkFilter + '"]')?.focus(),
    announce: announceWork,
    formatTime: fmt,
  });
  const laterPickerElement = qs('#later-picker');
  const laterPickerInput = qs('#later-picker-time');
  let searchDefer = null;
  const laterPicker = createLaterPicker({
    history: window.history,
    eventTarget: window,
    onState: state => {
      qs('#later-picker-error').textContent = state.message || '';
      if (state.open) {
        laterPickerInput.value = state.value || laterPickerInput.value;
        qs('#later-picker-timezone').textContent = 'Times use ' +
          (Intl.DateTimeFormat().resolvedOptions().timeZone || 'your device timezone') + '.';
        laterPickerElement.hidden = false;
        if (!laterPickerElement.open) laterPickerElement.showModal();
        laterPickerInput.focus();
      } else {
        if (laterPickerElement.open) laterPickerElement.close();
        laterPickerElement.hidden = true;
      }
    },
    onConfirm: (item, until, context) => {
      if (context === 'search') {
        return () => searchDefer.run(item, until).then(outcome => {
          if (outcome === 'deferred') return next();
        }).catch(error => {
          qs('#search-preview-status').textContent = error.message + ' Retry.';
        });
      }
      if (context === 'detail') {
        const inSession = workSession.active();
        const deferred = detailDefer.deferUntil(item, until, {
          closeSheet:false,
          restoreFocus:false,
        });
        if (!deferred) return false;
        return inSession ? true : () => workRoute.close();
      }
      const result = laterWork.defer(item, until);
      qs('#my-work-action-status').textContent = result === 'deferred' ?
        'Deferred until ' + fmt(until) + '; work stays unread and unchanged in Gitea.' :
        (result === 'invalid' ? 'Choose a valid future time.' : 'Could not save Later on this device.');
      if (result !== 'deferred') return false;
      refreshMyWorkView();
      return true;
    },
  });
  laterPicker.start();
  qs('#later-picker-form').addEventListener('submit', event => {
    event.preventDefault();
    laterPicker.submit(laterPickerInput.value);
  });
  qs('#cancel-later-picker').addEventListener('click', () => laterPicker.close());
  laterPickerElement.addEventListener('cancel', event => {
    event.preventDefault();
    laterPicker.close();
  });
  document.querySelectorAll('[data-detail-defer-preset]').forEach(button => {
    button.addEventListener('click', () => {
      const item = selectedUpdate || selectedReview || selectedIssue || selectedPull;
      button.closest('.detail-defer').open = false;
      detailDefer.defer(item, button.dataset.detailDeferPreset);
    });
  });
  document.querySelectorAll('[data-detail-defer-custom]').forEach(button => {
    button.addEventListener('click', () => {
      const item = selectedUpdate || selectedReview || selectedIssue || selectedPull;
      button.closest('.detail-defer').open = false;
      laterPicker.open(item, button, 'detail');
    });
  });
  document.querySelectorAll('[data-detail-defer-cancel]').forEach(button => {
    button.addEventListener('click', () => {
      const chooser = button.closest('.detail-defer');
      chooser.open = false;
      chooser.querySelector('summary')?.focus();
    });
  });

  function updatePlanningAvailability() {
    document.querySelectorAll('[data-detail-defer-preset], [data-detail-defer-custom]').forEach(button => {
      button.disabled = !planningOwnerLogin;
      button.toggleAttribute('data-planning-disabled', !planningOwnerLogin);
    });
  }

  function setOfflineDetailControls(kind) {
    const selectors = kind === 'issue' ? [
      '#edit-issue-content', '#release-issue', '#load-issue-handoff',
      '#issue-handoff-recipient', '#confirm-issue-handoff', '#issue-due-date',
      '#save-issue-labels', '#save-issue-due-date', '#clear-issue-due-date',
      '#issue-milestone', '#save-issue-milestone', '#load-older-issue-comments',
    ] : createPullSheet.ownershipSelectors().concat([
      '#merge-pull', '#pull-review-retry', '#next-unreviewed-pull-file', '#load-older-pull-comments',
    ]);
    selectors.forEach(selector => {
      const control = qs(selector);
      if (control) control.disabled = true;
    });
    if (kind === 'issue') {
      qs('#issue-planning').inert = true;
      qs('#issue-handoff').inert = true;
    } else {
      qs('#pull-review').inert = true;
      qs('#pull-ownership').inert = true;
    }
  }

  function setOfflineUpdateControls(offline) {
    qs('#mark-update-read-next').disabled = false;
    qs('#mark-update-read-next').textContent = offline ? 'Queue read & next' : 'Mark read & next';
    qs('#acknowledge-update-next').disabled = offline;
    qs('#mute-update-next').disabled = offline;
    qs('#update-ownership-action').disabled = offline;
    qs('#update-ownership-start').disabled = offline;
    qs('#load-older-update-comments').disabled = offline;
    qs('#update-sheet .detail-defer').inert = offline;
  }

  function renderContextSnapshot(data) {
    liveMode = true;
    hasContextSnapshot = true;
    if (lastContextSnapshot && Object.values(workPagination).some(page => page.page > 1)) {
      const merge = (older, latest) => {
        const byId = new Map((older || []).map(item => [item.id, item]));
        (latest || []).forEach(item => {
          const current = byId.get(item.id) || {};
          const reasons = Array.from(new Set(
            (current.work_reasons || []).concat(item.work_reasons || [])
          ));
          byId.set(item.id, {
            ...current, ...item, ...(reasons.length ? { work_reasons: reasons } : {}),
          });
        });
        return Array.from(byId.values());
      };
      data.issues = merge(lastContextSnapshot.issues, data.issues);
      data.pull_requests = merge(lastContextSnapshot.pull_requests, data.pull_requests);
    }
    lastContextSnapshot = data;
    if (data.work_pagination) workPager.reset(data.work_pagination);
    if (data.error && lastMyWork.length) markMyWorkStale();
    else paintMyWork(data);
    openStagedSharedContent();
    qs('#context').innerHTML = '<div class="kv"><div class="label">User</div><div class="value">' + escapeHtml(data.user?.full_name || data.user?.login || '—') + '</div>' +
      '<div class="label">Repos</div><div class="value">' + (data.repos?.length || 0) + '</div>' +
      '<div class="label">Issues</div><div class="value">' + (data.issues?.length || 0) + '</div>' +
      '<div class="label">PRs</div><div class="value">' + (data.pull_requests?.length || 0) + '</div></div>';
    qs('#view-hint').textContent = 'Active view: ' + (data.view || 'dashboard');

    const issuesBox = qs('#issues-content');
    const openIssues = (data.issues || []).filter(i => i.state === 'open').slice(0, 12);
    issuesBox.innerHTML = (openIssues.length ? openIssues.map(i => '<div style="margin:6px 0;"><a href="' + escAttr(i.url) + '" target="_blank">#' + i.number + ' ' + escapeHtml(i.title) + '</a>' +
      '<div class="muted">' + (i.labels || []).map(l => '<span class="pill">' + escapeHtml(String(l)) + '</span>').join(' ') + '</div></div>').join('') : '<div class="muted">No open issues.</div>');

    const prsBox = qs('#prs-content');
    const openPrs = (data.pull_requests || []).slice(0, 12);
    prsBox.innerHTML = (openPrs.length ? openPrs.map(p => '<div style="margin:6px 0;"><a href="' + escAttr(p.url) + '" target="_blank">#' + p.number + ' ' + escapeHtml(p.title) + '</a>' +
      '<div class="muted">' + escapeHtml(p.state) + ' by ' + escapeHtml(String(p.user || '')) + '</div></div>').join('') : '<div class="muted">No PRs.</div>');

    paintDeltas(data.deltas || []);
    qs('#layout-hint').innerHTML = '<div class="kv"><div class="label">Active view</div><div class="value">' + escapeHtml(data.view || 'dashboard') + '</div><div class="label">Deltas</div><div class="value">' + (data.deltas||[]).length + '</div></div>';
    renderRepoMix(qs('#repo-mix'), data);
    setStatus(data.error ? 'Degraded · ' + data.error : 'Live · updated just now');
    setClock();
  }

  async function handleContextError(e) {
    console.error('context failed', e);
    liveMode = false;
    activeFlushLogin = '';
    if (!hasContextSnapshot && await hydrateOfflineWork('outage')) return;
    const timeoutStatus = e.name === 'TimeoutError' ?
      'Update delayed · showing last snapshot' : 'Update failed · showing last snapshot';
    setStatus(hasContextSnapshot ? timeoutStatus : 'Unavailable');
    if (!hasContextSnapshot) {
      qs('#context').innerHTML = '<div class="muted">Context unavailable.</div>';
      qs('#view-hint').textContent = 'Active view unavailable.';
      qs('#issues-content').innerHTML = '<div class="muted">Work items unavailable.</div>';
      qs('#prs-content').innerHTML = '<div class="muted">Work items unavailable.</div>';
      paintDeltas([]);
    }
    markMyWorkStale();
  }

  function paintMyWork(data) {
    lastMyWork = buildMyWork(data);
    refreshMyWorkView();
    void syncCompletedFiledReviews();
  }

  function listDrafts() {
    const unfiled = unfiledCaptures.list().map(item => ({
      id:'unfiled:' + item.id, capture_id:item.id, kind:'unfiled-issue', ...unfiledDraftSummary(item),
      title:unfiledDraftDisplayTitle(item),
      preview:[item.body, item.hasAttachment ? 'Photo evidence attached' : ''].filter(Boolean).join(' · '),
      hasAttachment:item.hasAttachment, copy_text:[item.title, item.body].filter(Boolean).join('\n\n'),
      updated_at:item.savedAt, quarantined:item.quarantined,
      ownership:item.quarantined ? 'Saved by ' + item.ownerLogin +
        (activeFlushLogin ? ' — current account is ' + activeFlushLogin : ' — reconnect to confirm this account') : '',
    }));
    return draftInbox.list().concat(unfiled).sort((left, right) =>
      Number(right.updated_at || 0) - Number(left.updated_at || 0)
    );
  }

  function refreshMyWorkView({ reconcileSession = true } = {}) {
    lastDrafts = listDrafts();
    const actionableMyWork = filedHistoryTabs.prepare(lastMyWork);
    const partitioned = laterWork.partition(actionableMyWork, {
      pruneMissing: !Object.values(workPagination).some(page => page?.has_more),
    });
    activeMyWork = partitioned.active;
    laterMyWork = partitioned.later;
    const authoritativeMyWorkRefresh = liveMode && hasContextSnapshot &&
      !lastContextSnapshot?.error &&
      !Object.values(workPagination).some(page => page?.has_more);
    todayMyWork = todayWork.reconcile(actionableMyWork, {
      pruneMissing: authoritativeMyWorkRefresh,
      onPrune: retiredIds => {
        const queued = retiredIds.map(id => todaySync.enqueue('remove', id)).every(Boolean);
        if (queued) todaySync.flush();
        return queued;
      },
    });
    const counts = countMyWork(activeMyWork);
    const agendaItems = agendaMyWork(activeMyWork);
    counts.agenda = agendaItems.length;
    counts.today = todayMyWork.length;
    counts.later = laterMyWork.length;
    counts.draft = lastDrafts.length;
    counts.delivery = draftInbox.partition(lastDrafts).actionable;
    mobilePreparationItems = {
      delivery:draftInbox.partition(lastDrafts).deliveries,
      agenda:agendaMyWork(activeMyWork),
      attention:activeMyWork.filter(item => item.needs_attention),
      update:activeMyWork.filter(item => item.has_update),
      filed:activeMyWork.filter(item => item.is_filed),
    };
    if (!launchFilterResolved) {
      selectedWorkFilter = mobileLaunch.chooseFilter({
        saved: savedWorkFilter, today: counts.today, attention: counts.attention,
        agenda: counts.agenda,
      });
      launchFilterResolved = true;
      document.querySelectorAll('[data-work-filter]').forEach(item =>
        item.setAttribute('aria-pressed', String(item.dataset.workFilter === selectedWorkFilter))
      );
    }
    Object.entries(counts).forEach(([filter, count]) => {
      const element = qs('[data-work-count="' + filter + '"]');
      if (element) element.textContent = count;
    });
    mobileQueueCounts = counts;
    mobileStartDay.reconcile({
      authoritative:authoritativeMyWorkRefresh,
      authoritativePhases:['delivery'],
    });
    mobileStartDay.render();
    mobileTaskDock.updateQueues(counts);
    mobileFirstTask.refresh();
    mobileTaskDock.updateWork(mobileWorkEntry.mode());
    mobileTaskDock.updateAttention(countMyWork(activeMyWork).attention);
    const activeQueue = qs('[data-work-filter="' + selectedWorkFilter + '"]');
    qs('#active-work-queue').textContent = activeQueue.firstChild.textContent.trim() +
      ' (' + (counts[selectedWorkFilter] || 0) + ')';
    const milestoneSelect = qs('#work-milestone-filter');
    const lanes = milestoneLanes(lastMyWork);
    milestoneSelect.innerHTML = '<option value="all">All milestones</option>' +
      '<option value="unplanned">Unplanned</option>' + lanes.map(lane =>
        '<option value="' + Number(lane.id) + '">' + escapeHtml(lane.title) + '</option>'
      ).join('');
    milestoneSelect.value = selectedWorkMilestone;
    if (milestoneSelect.value !== selectedWorkMilestone) {
      const retained = document.createElement('option');
      retained.value = selectedWorkMilestone;
      retained.textContent = 'Selected milestone';
      milestoneSelect.append(retained);
      milestoneSelect.value = selectedWorkMilestone;
    }
    qs('#my-work').removeAttribute('data-stale');
    qs('#my-work-status').textContent = lastMyWork.length ?
      summarizeMyWork(activeMyWork) + (laterMyWork.length ? ' · ' + laterMyWork.length + ' deferred' : '') :
      'No assigned work, review requests, or unread updates.';
    updateWorkPaginationControls();
    renderMyWork();
    if (selectedWorkFilter === 'agenda' && workPagination.issue?.has_more && !agendaChecking) {
      completeAgendaIssues();
    }
    if (reconcileSession && workSession.active()) workSession.reconcile();
    updateWorkSessionActions();
    if (todayHandoff.pending().length) setTimeout(promptTodayHandoff, 0);
  }

  function activeWorkStreams() {
    if (selectedWorkFilter === 'today') return ['issue', 'pull', 'review'];
    if (selectedWorkFilter === 'agenda') return ['issue'];
    if (selectedWorkFilter === 'attention') return ['issue', 'pull', 'review'];
    if (selectedWorkFilter === 'filed') return ['filed'];
    if (selectedWorkFilter === 'issue') return ['issue'];
    if (selectedWorkFilter === 'pull') return ['pull'];
    if (selectedWorkFilter === 'review') return ['review'];
    if (selectedWorkFilter === 'all') return ['issue', 'filed', 'pull', 'review'];
    return [];
  }

  async function completeAgendaIssues() {
    if (selectedWorkFilter !== 'agenda') return false;
    if (!workPagination.issue?.has_more) return true;
    if (!lastContextSnapshot) return false;
    agendaChecking = true;
    qs('#my-work-action-status').textContent = 'Checking all assigned deadlines…';
    renderMyWork();
    const complete = await workPager.loadAll('issue', () => lastContextSnapshot?.issues || []);
    agendaChecking = false;
    if (selectedWorkFilter !== 'agenda') return false;
    qs('#my-work-action-status').textContent = complete ?
      'All assigned deadlines checked.' :
      'Agenda check paused. Retry to check older assigned deadlines.';
    renderMyWork();
    return complete && !workPagination.issue?.has_more;
  }

  function renderDrafts() {
    const list = qs('#my-work-list');
    const displayedDrafts = findQueueItems(lastDrafts, queueFindQuery);
    const deliveryCenter = draftInbox.partition(displayedDrafts);
    const renderDraftCard = item => {
      const index = lastDrafts.indexOf(item);
      const isOutbox = item.kind === 'issue-outbox' || item.kind === 'authored-outbox';
      const isUnfiled = item.kind === 'unfiled-issue';
      const reviewOutbox = item.outbox_kind === 'pull-review';
      const closureOutbox = item.outbox_kind === 'issue-close';
      const checklistConflict = item.checklist_conflict === true;
      const sendLabel = item.delivery_state === 'uncertain' ? 'Verified not posted — retry' : 'Send now';
      const outboxActions = item.quarantined ?
        '<button class="draft-copy" data-draft-index="' + index + '" type="button">Copy content</button>' +
        '<button class="draft-discard" data-draft-index="' + index + '" type="button">Discard</button>' :
        item.continuation ?
        '<button class="draft-continue" data-draft-index="' + index + '" type="button">Continue created work</button>' +
        '<button class="draft-discard" data-draft-index="' + index + '" type="button">Dismiss</button>' :
        item.kind === 'issue-outbox' ?
        '<button class="draft-edit" data-draft-index="' + index + '" type="button">Edit</button>' +
        '<button class="draft-send" data-draft-index="' + index + '" type="button">' + sendLabel + '</button>' +
        '<button class="draft-discard" data-draft-index="' + index + '" type="button">Discard</button>' :
        reviewOutbox && item.status === 'authorization' ?
        '<button class="draft-resume" data-draft-index="' + index + '" type="button">Open review</button>' +
        '<button class="draft-authorize" data-draft-index="' + index + '" type="button">Authorize &amp; send review</button>' +
        '<button class="draft-discard" data-draft-index="' + index + '" type="button">Discard queued review</button>' :
        reviewOutbox && item.status === 'attention' ?
        '<button class="draft-resume" data-draft-index="' + index + '" type="button">Open current review</button>' +
        '<button class="draft-copy" data-draft-index="' + index + '" type="button">Copy feedback</button>' +
        '<button class="draft-discard" data-draft-index="' + index + '" type="button">Discard queued review</button>' :
        item.kind === 'authored-outbox' && checklistConflict ?
        '<button class="draft-review-checklist" data-draft-index="' + index + '" type="button">Review changes</button>' +
        '<button class="draft-discard" data-draft-index="' + index + '" type="button">Discard</button>' :
        item.kind === 'authored-outbox' && closureOutbox ?
        '<button class="draft-resume" data-draft-index="' + index + '" type="button">Open issue</button>' +
        '<button class="draft-authorize" data-draft-index="' + index + '" type="button">Authorize &amp; close</button>' +
        '<button class="draft-discard" data-draft-index="' + index + '" type="button">Discard</button>' :
        item.kind === 'authored-outbox' && !reviewOutbox ?
        '<button class="draft-resume" data-draft-index="' + index + '" type="button">Open message</button>' +
        '<button class="draft-send" data-draft-index="' + index + '" type="button">' + sendLabel + '</button>' +
        '<button class="draft-discard" data-draft-index="' + index + '" type="button">Discard</button>' :
        reviewOutbox ?
        '<button class="draft-resume" data-draft-index="' + index + '" type="button">Open review</button>' +
        '<button class="draft-discard" data-draft-index="' + index + '" type="button">Discard queued review</button>' :
        '<button class="draft-resume" data-draft-index="' + index + '" type="button">' +
          (isUnfiled ? item.action : 'Resume draft') + '</button>' +
        '<button class="draft-discard" data-draft-index="' + index + '" type="button">Discard draft</button>';
      const state = isOutbox ?
        '<span class="pill">' + draftInbox.deliveryLabel(item) + '</span>' +
        (item.ownership ? '<div class="small">' + escapeHtml(item.ownership) + '</div>' : '') : '';
      const attempt = item.last_attempt_error ? '<span class="delivery-attempt small">Last attempt ' +
        escapeHtml(fmt(item.last_attempt_at)) + ' · ' + escapeHtml(item.last_attempt_error) + '</span>' : '';
      const captureTarget = isUnfiled ? ' tabindex="-1" data-capture-id="' + escapeHtml(item.capture_id) + '"' : '';
      return '<article class="my-work-card draft-card"' + captureTarget + '>' +
        '<span class="small">' + escapeHtml([item.label, item.repository, item.details].filter(Boolean).join(' · ')) + '</span>' +
        '<span class="my-work-card-title">' + escapeHtml(item.title) + '</span>' +
        '<span class="draft-preview">' + escapeHtml(item.preview || 'Unfinished draft') + '</span>' + state + attempt +
        '<span class="small">Saved ' + escapeHtml(fmt(item.updated_at)) + '</span>' +
        '<div class="draft-actions">' + outboxActions + '</div></article>';
    };
    const deliverySummary = '<section class="delivery-center" aria-labelledby="delivery-center-title">' +
      '<div><h3 id="delivery-center-title" tabindex="-1">Delivery center</h3>' +
      '<p class="small">Waiting <strong data-delivery-count="waiting">' + deliveryCenter.counts.waiting + '</strong> · ' +
      'Sending <strong data-delivery-count="sending">' + deliveryCenter.counts.sending + '</strong> · ' +
      'Needs attention <strong data-delivery-count="attention">' + deliveryCenter.counts.attention + '</strong> · ' +
      'Authorize <strong data-delivery-count="authorization">' + deliveryCenter.counts.authorization + '</strong></p></div>' +
      '<button id="retry-waiting-deliveries" type="button"' +
        (deliveryCenter.retryable.length && activeFlushLogin ? '' : ' disabled') + '>Retry waiting</button></section>';
    const deliveryCards = deliveryCenter.deliveries.length ? deliveryCenter.deliveries.map(renderDraftCard).join('') :
      '<div class="muted">No queued deliveries.</div>';
    const draftCards = deliveryCenter.drafts.length ? deliveryCenter.drafts.map(renderDraftCard).join('') :
      '<div class="muted">No unfinished drafts.</div>';
    list.innerHTML = deliverySummary + '<section class="draft-section" aria-label="Queued deliveries">' +
      '<h3>Queued deliveries</h3>' + deliveryCards + '</section>' +
      '<section class="draft-section" aria-label="Unfinished drafts"><h3>Unfinished drafts</h3>' + draftCards + '</section>';
    updateQueueFinder(displayedDrafts.length, lastDrafts.length, false);
    qs('#retry-waiting-deliveries').addEventListener('click', async event => {
      const button = event.currentTarget;
      if (!activeFlushLogin || !deliveryCenter.retryable.length) return;
      button.disabled = true;
      qs('#my-work-action-status').textContent = 'Retrying waiting deliveries…';
      const [issueResult, authoredResult] = await Promise.all([issueOutbox.flush(activeFlushLogin), authoredOutbox.flush(activeFlushLogin)]);
      applyOutboxResult(issueResult);
      applyAuthoredOutboxResult(authoredResult);
      qs('#my-work-action-status').textContent = 'Waiting deliveries retried; attention stayed queued.';
    });
    list.querySelectorAll('.draft-resume').forEach(button => {
      button.onclick=async()=>{
        const item = lastDrafts[Number(button.dataset.draftIndex)];
        if (!item) return;
        if (item.kind === 'unfiled-issue') {
          try {
            await dFS.open(item.capture_id, item.ready ? button : null);
          } catch (error) { qs('#my-work-action-status').textContent = error.message; }
        } else if (item.kind === 'new-issue') openCreateIssueSheet();
        else if (item.route) workRoute.open(item.route);
      };
    });
    list.querySelectorAll('.draft-continue').forEach(button => {
      button.addEventListener('click', () => {
        const item = lastDrafts[Number(button.dataset.draftIndex)];
        const completion = issueOutbox.pendingCompletions(activeFlushLogin)
          .find(candidate => candidate.id === item?.outbox_id);
        if (completion) applyOutboxResult({
          confirmed: [completion.issue], completions: [completion], remaining: issueOutbox.list(),
        });
      });
    });
    list.querySelectorAll('.draft-edit').forEach(button => {
      button.addEventListener('click', async () => {
        const item = lastDrafts[Number(button.dataset.draftIndex)];
        const queued = issueOutbox.list().find(candidate => candidate.id === item?.outbox_id);
        if (!queued) return;
        button.disabled = true;
        try {
          const hydrated = await issueOutbox.hydrateForEdit(queued.id);
          if (!hydrated) return;
          editingOutboxId = hydrated.id;
          issueCapture.saveDraft(hydrated);
          openCreateIssueSheet();
          if (hydrated.attachments || hydrated.attachment) {
            createIssueAttachmentController.restore(hydrated.attachments || hydrated.attachment);
          }
          else createIssueAttachmentController.clear();
          qs('#create-issue-status').textContent = 'Edit this queued issue, then send again.';
        } catch (error) {
          qs('#my-work-action-status').textContent = String(error?.message ||
            'The saved screenshot could not be loaded. Retry before editing this issue.');
        } finally {
          button.disabled = false;
        }
      });
    });
    list.querySelectorAll('.draft-send').forEach(button => {
      button.addEventListener('click', async () => {
        const item = lastDrafts[Number(button.dataset.draftIndex)];
        if (!item?.outbox_id) return;
        button.disabled = true;
        if (item.kind === 'authored-outbox') applyAuthoredOutboxResult(await authoredOutbox.retry(item.outbox_id, activeFlushLogin));
        else applyOutboxResult(await issueOutbox.retry(item.outbox_id, activeFlushLogin));
      });
    });
    list.querySelectorAll('.draft-review-checklist').forEach(button => {
      button.onclick=async()=>{
        const item = lastDrafts[Number(button.dataset.draftIndex)];
        const queued = authoredOutbox.list().find(candidate => candidate.id === item?.outbox_id);
        if (!item?.checklist_conflict || !queued || !activeFlushLogin) return;
        button.disabled = true;
        qs('#my-work-action-status').textContent = 'Loading the latest checklist for review…';
        try {
          const latest = await issueController.load({
            repository:item.repository, number:item.number,
          });
          const preview = mergeChecklistConflict({
            baseBody:queued.baseBody, localBody:queued.body, remoteBody:latest.body,
          });
          if (preview.conflicts.length) {
            qs('#my-work-action-status').textContent = 'Checklist changes for ' +
              preview.conflicts.map(conflict => conflict.label).join(', ') +
              ' could not be matched safely. Open the issue to compare renamed or deleted tasks.';
            return;
          }
          if (!window.confirm('Apply ' + preview.changes.length + ' checklist change' +
              (preview.changes.length === 1 ? '' : 's') + ' to the latest issue? Remote prose and other tasks will stay unchanged.')) return;
          const result = await authoredOutbox.resolveIssueContentConflict(item.outbox_id, latest, activeFlushLogin);
          if (result.conflicts.length) return;
          const delivery = await authoredOutbox.retry(item.outbox_id, activeFlushLogin);
          applyAuthoredOutboxResult(delivery);
          qs('#my-work-action-status').textContent = delivery.confirmed?.length ?
            'Checklist changes applied to the latest issue.' :
            'The issue changed again. Review the checklist conflict against the new version.';
        } catch (error) {
          qs('#my-work-action-status').textContent = String(error?.message || 'Checklist review could not be loaded. Retry when online.');
        } finally {
          button.disabled = false;
        }
      };
    });
    list.querySelectorAll('.draft-authorize').forEach(button => {
      button.addEventListener('click', async () => {
        const item = lastDrafts[Number(button.dataset.draftIndex)];
        if (!item?.outbox_id || !activeFlushLogin) return;
        button.disabled = true;
        const reviewAuthorization = item.outbox_kind === 'pull-review';
        qs('#my-work-action-status').textContent = reviewAuthorization ?
          'Fresh authorization required for this exact review decision and head.' :
          'Fresh authorization required for this exact issue.';
        const result = await authoredOutbox.retry(item.outbox_id, activeFlushLogin);
        applyAuthoredOutboxResult(result);
        qs('#my-work-action-status').textContent = result.confirmed?.length ?
          (reviewAuthorization ? 'Review submitted and queued intent cleared.' :
            'Issue closed and queued intent cleared.') :
          (reviewAuthorization ? 'Review was not confirmed. The queued review and feedback are still safe.' :
            'Issue closure was not confirmed. The queued intent is still safe.');
      });
    });
    list.querySelectorAll('.draft-copy').forEach(button => {
      button.onclick=async()=>{
        const item = lastDrafts[Number(button.dataset.draftIndex)];
        if (!item?.copy_text) return;
        await navigator.clipboard.writeText(item.copy_text);
        qs('#my-work-action-status').textContent = 'Queued content copied without sending it.';
      };
    });
    list.querySelectorAll('.draft-discard').forEach(button => {
      button.addEventListener('click', async () => {
        if (!window.confirm('Discard this unfinished draft?')) return;
        const item = lastDrafts[Number(button.dataset.draftIndex)];
        if (item?.kind === 'unfiled-issue') {
          await unfiledCaptures.discard(item.capture_id);
        }
        else if (item?.kind === 'issue-outbox') issueOutbox.discard(item.outbox_id);
        else if (item?.kind === 'authored-outbox') authoredOutbox.discard(item.outbox_id);
        else if (item) draftInbox.discard(item.id);
        lastDrafts = listDrafts();
        const count = qs('[data-work-count="draft"]');
        if (count) count.textContent = lastDrafts.length;
        renderDrafts();
        qs('#my-work-action-status').textContent = 'Draft discarded.';
      });
    });
    mobileDeliveryRecovery.render();
  }

  function updateWorkPaginationControls() {
    const labels = { issue: 'issues', filed: 'filed issues', pull: 'pull requests', review: 'review requests' };
    const streams = activeWorkStreams();
    const incomplete = streams.filter(stream => workPagination[stream]?.has_more);
    const summaries = streams.flatMap(stream => {
      const page = workPagination[stream];
      return page && page.total ?
        [Math.min(page.total, page.page * 50) + ' of ' + page.total + ' ' + labels[stream]] : [];
    });
    qs('#work-page-status').textContent = summaries.join(' · ');
    qs('#load-more-work').hidden = incomplete.length === 0;
    qs('#load-more-work').textContent = incomplete.length ?
      'Load older ' + labels[incomplete[0]] : 'Load older work';
  }

  function renderMyWork() {
    lastDrafts = listDrafts();
    const draftCount = qs('[data-work-count="draft"]');
    if (draftCount) draftCount.textContent = lastDrafts.length;
    if (selectedWorkFilter === 'draft') {
      renderDrafts();
      qs('#bulk-mark-read-bar').hidden = true;
      qs('#load-more-notifications').hidden = true;
      qs('#filed-history-tabs').hidden = true;
      return;
    }
    const filedItems = filedHistoryTabs.render(selectedFiledView, selectedWorkFilter === 'filed');
    const queueItems = selectedWorkFilter === 'filed' ? filedItems : selectedWorkFilter === 'today' ?
      filterMyWork(todayMyWork, 'all', selectedWorkMilestone) : selectedWorkFilter === 'later' ?
      filterMyWork(laterMyWork, 'all', selectedWorkMilestone) : selectedWorkFilter === 'agenda' ?
      agendaMyWork(activeMyWork) :
      filterMyWork(activeMyWork, selectedWorkFilter, selectedWorkMilestone);
    const overdue = queueItems.filter(item => item.agenda_group === 'Overdue');
    const urgentAgenda = selectedWorkFilter === 'agenda' ? queueItems.filter(item =>
      item.agenda_group === 'Overdue' || item.agenda_group === 'Today') : [];
    const protectPanel = qs('#protect-today-panel');
    protectPanel.hidden = selectedWorkFilter !== 'agenda' || urgentAgenda.length === 0;
    qs('#protect-today-status').textContent = urgentAgenda.length ?
      urgentAgenda.length + ' urgent ' + (urgentAgenda.length === 1 ? 'deadline is' : 'deadlines are') + ' ready to reconcile with Today.' : '';
    const replanPanel = qs('#agenda-replan');
    replanPanel.hidden = selectedWorkFilter !== 'agenda' || overdue.length === 0;
    if (!agendaReplan?.snapshot().active) {
      qs('#start-agenda-replan').textContent = 'Replan overdue (' + overdue.length + ')';
      qs('#agenda-replan-controls').hidden = true;
    }
    const agendaExport = qs('#agenda-export');
    const agendaExportButton = qs('#open-agenda-export');
    agendaExport.hidden = selectedWorkFilter !== 'agenda';
    agendaExportButton.disabled = queueItems.length === 0;
    qs('#agenda-export-empty').textContent = queueItems.length ?
      'Review ' + queueItems.length + (queueItems.length === 1 ? ' deadline' : ' deadlines') +
        ' before sharing a calendar snapshot.' :
      'No deadlines are available to export from this Agenda.';
    const incomplete = activeWorkStreams().some(stream => workPagination[stream]?.has_more);
    const visible = findQueueItems(queueItems, queueFindQuery);
    const emptyWorkStart = qs('#empty-work-start');
    const showEmptyStart = selectedWorkFilter === 'all' && !queueFindQuery &&
      !queueItems.length && !incomplete && hasContextSnapshot;
    emptyWorkStart.hidden = !showEmptyStart;
    updateQueueFinder(visible.length, queueItems.length, incomplete);
    const selection = notificationSelection.snapshot();
    const selectedIds = new Set(selection.ids);
    const workSelectionState = workSelection.snapshot();
    const selectedWorkIds = new Set(workSelectionState.ids);
    qs('#my-work-list').innerHTML = visible.length ? visible.map(item => {
      const index = lastMyWork.findIndex(candidate => candidate.key === item.key && candidate.kind === item.kind);
      const routeItem = routedWorkItem(item);
      const routeHref = createWorkRoute.serialize(routeItem);
      const contents =
      '<span class="small">' + escapeHtml(item.key) + ' · ' + escapeHtml(item.kind === 'pull' ? 'PR' : (item.kind === 'update' ? 'Update' : 'Issue')) + '</span>' +
      '<span class="my-work-card-title">' + escapeHtml(item.title) + '</span>' +
      (item.agenda_group ? '<span class="pill agenda-badge" data-agenda-group="' + escAttr(item.agenda_group) + '">' + escapeHtml(item.agenda_group) + '</span>' : '') +
      '<span class="pill">' + escapeHtml(item.reason) + '</span>' +
      (item.milestone?.title ? ' <span class="pill milestone-badge">' + escapeHtml(item.milestone.title) + '</span>' : '') +
      (item.due_label ? ' <span class="pill due-badge">' + escapeHtml(item.due_label) + '</span>' : '') +
      (item.has_update ? ' <span class="pill">Unread update</span>' : '') +
      (item.deferred_until ? '<span class="small">Deferred until ' + escapeHtml(fmt(item.deferred_until)) + '</span>' : '') +
      (item.updated_at ? '<span class="small"> · Updated ' + escapeHtml(fmt(item.updated_at)) + '</span>' : '');
      const selectable = selectedWorkFilter === 'update' && selection.active &&
        item.has_update && Number.isInteger(item.notification_id);
      const workSelectable = workSelectionState.active;
      const workId = workSelection.identity(item);
      const selector = workSelectable ?
        '<label class="work-selector"><input type="checkbox" data-select-work-id="' + escAttr(workId) + '" data-work-index="' + index + '" aria-label="Select work ' + escAttr(item.key + ' ' + item.title) + '"' + (selectedWorkIds.has(workId) ? ' checked' : '') + '> Select</label>' : (selectable ?
        '<label class="update-selector"><input type="checkbox" data-select-notification-id="' + item.notification_id + '" aria-label="Select update ' + escAttr(item.key + ' ' + item.title) + '"' + (selectedIds.has(item.notification_id) ? ' checked' : '') + '> Select</label>' : '');
      const cardClasses = 'my-work-card' + ((selectable || workSelectable) ? ' selection-active' : '') +
        ((selectedIds.has(item.notification_id) || selectedWorkIds.has(workId)) ? ' selected' : '');
      const markRead = item.has_update && Number.isInteger(item.notification_id) && !selection.active ?
        '<button class="mark-update-read" data-notification-id="' + item.notification_id + '">Mark read</button>' : '';
      const readUpdate = item.has_update && Number.isInteger(item.notification_id) ?
        '<a class="read-update" href="' + escAttr(createWorkRoute.serialize({ kind:'update', notification_id:item.notification_id })) + '" data-update-index="' + index + '">Read update</a>' : '';
      const planningDisabled = planningOwnerLogin ? '' : ' disabled data-planning-disabled';
      const laterActions = selectedWorkFilter === 'later' ?
        '<div class="later-actions" aria-label="Deferred work actions"><button type="button" data-later-start data-work-index="' + index + '"' + planningDisabled + '>Start now</button><button type="button" data-later-restore data-work-index="' + index + '">Bring back now</button></div>' :
        '<div class="later-actions" aria-label="Defer this work"><button type="button" data-later-preset="today" data-work-index="' + index + '"' + planningDisabled + '>Later today</button><button type="button" data-later-preset="tomorrow" data-work-index="' + index + '"' + planningDisabled + '>Tomorrow</button><button type="button" data-later-custom data-work-index="' + index + '"' + planningDisabled + '>Choose date &amp; time</button></div>';
      const alreadyToday = todayWork.contains(item);
      const todayPosition = todayWork.position(item);
      const todayActions = selectedWorkFilter === 'today' ?
        '<div class="today-actions" aria-label="Reorder Today"><button type="button" data-today-move="up" data-work-index="' + index + '"' + (todayPosition.can_up ? '' : ' disabled') + '>Move up</button><button type="button" data-today-move="down" data-work-index="' + index + '"' + (todayPosition.can_down ? '' : ' disabled') + '>Move down</button><button type="button" data-today-remove data-work-index="' + index + '">Remove from Today</button></div>' :
        '<div class="today-actions"><button type="button" data-today-add data-work-index="' + index + '"' + (alreadyToday ? ' disabled' : planningDisabled) + '>' + (alreadyToday ? 'Added to Today' : 'Add to Today') + '</button></div>';
      const planningActions = selectedWorkFilter === 'later' ? laterActions :
        '<details class="card-planning" data-card-planning><summary aria-expanded="false">Plan or defer</summary><div class="card-planning-actions">' + todayActions + laterActions + '</div></details>';
      if (item.is_review) {
        return '<article class="' + cardClasses + '">' + selector + '<a class="my-work-card-main review-trigger" href="' + escAttr(routeHref) + '" data-review-index="' + index + '">' + contents + '</a>' + readUpdate + markRead + planningActions + '</article>';
      }
      if (item.kind === 'issue') {
        return '<article class="' + cardClasses + '">' + selector + '<a class="my-work-card-main issue-trigger" href="' + escAttr(routeHref) + '" data-issue-index="' + index + '">' + contents + '</a>' + readUpdate + markRead + planningActions + '</article>';
      }
      if (item.kind === 'pull') {
        return '<article class="' + cardClasses + '">' + selector + '<a class="my-work-card-main pull-trigger" href="' + escAttr(routeHref) + '" data-pull-index="' + index + '">' + contents + '</a>' + readUpdate + markRead + planningActions + '</article>';
      }
      return '<article class="' + cardClasses + '">' + selector + '<a class="my-work-card-main update-trigger" href="' + escAttr(routeHref) + '" data-update-index="' + index + '">' + contents + '</a>' + markRead + planningActions + '</article>';
    }).join('') : (showEmptyStart ? '' : '<div class="muted">' +
      (selectedWorkFilter === 'agenda' && workPagination.issue?.has_more ?
        (agendaChecking ? 'Checking all assigned deadlines…' :
          'Older assigned deadlines remain unchecked. Retry the Agenda check.') : (incomplete ?
      'More work is available. Load the next page.' : (selectedWorkFilter === 'filed' && selectedFiledView === 'reviewed' ?
      'No reviewed outcomes yet' :
      'No ' + (selectedWorkFilter === 'attention' ? 'items need attention' : (selectedWorkFilter === 'review' ? 'reviews' : (selectedWorkFilter === 'update' ? 'unread updates' : (selectedWorkFilter === 'later' ? 'deferred work' : (selectedWorkFilter === 'all' ? 'work' : selectedWorkFilter + ' items'))))) + '.'))) + '</div>');
    cardPlanning.wire();
    document.querySelectorAll('[data-select-notification-id]').forEach(input => {
      input.addEventListener('change', () => {
        const notificationId = Number(input.dataset.selectNotificationId);
        const result = input.checked ? notificationSelection.select(notificationId) :
          notificationSelection.toggle(notificationId);
        if (result === 'limit') {
          input.checked = false;
          qs('#my-work-action-status').textContent = 'Select up to 50 updates per batch.';
        }
      });
    });
    document.querySelectorAll('[data-select-work-id]').forEach(input => {
      input.addEventListener('change', () => {
        const item = lastMyWork[Number(input.dataset.workIndex)];
        const result = input.checked ? workSelection.select(item) : workSelection.toggle(item);
        if (result === 'limit') {
          input.checked = false;
          qs('#my-work-action-status').textContent = 'Select up to 50 work items per batch.';
        }
      });
    });
    document.querySelectorAll('[data-review-index]').forEach(button => {
      button.addEventListener('click', event => { event.preventDefault(); openRoutedWork(lastMyWork[Number(button.dataset.reviewIndex)], button); });
    });
    document.querySelectorAll('[data-issue-index]').forEach(button => {
      button.addEventListener('click', event => { event.preventDefault(); openRoutedWork(lastMyWork[Number(button.dataset.issueIndex)], button); });
    });
    document.querySelectorAll('[data-pull-index]').forEach(button => {
      button.addEventListener('click', event => { event.preventDefault(); openRoutedWork(lastMyWork[Number(button.dataset.pullIndex)], button); });
    });
    document.querySelectorAll('[data-update-index]').forEach(button => {
      button.addEventListener('click', event => {
        event.preventDefault();
        const item = lastMyWork[Number(button.dataset.updateIndex)];
        if (!item) return;
        updateTrigger = button;
        openRoutedWork(item, button);
      });
    });
    document.querySelectorAll('[data-notification-id]').forEach(button => {
      button.addEventListener('click', async () => {
        const notificationId = Number(button.dataset.notificationId);
        button.disabled = true;
        const acknowledged = await notificationAcknowledger.acknowledge(lastMyWork, notificationId);
        if (acknowledged) {
          lastNotifications = lastNotifications.filter(item => item.id !== notificationId);
          (document.querySelector('[data-notification-id]') || qs('[data-work-filter="update"]'))?.focus();
        } else {
          document.querySelector('[data-notification-id="' + notificationId + '"]')?.focus();
        }
      });
    });
    document.querySelectorAll('[data-later-preset]').forEach(button => {
      button.addEventListener('click', () => {
        const item = lastMyWork[Number(button.dataset.workIndex)];
        if (!item) return;
        if (!planningOwnerLogin) {
          qs('#my-work-action-status').textContent = 'Planning is unavailable until your operator identity is restored.';
          return;
        }
        const until = laterWork.presetUntil(button.dataset.laterPreset);
        const result = laterWork.defer(item, until);
        qs('#my-work-action-status').textContent = result === 'deferred' ?
          'Deferred until ' + fmt(until) + '; work stays unread and unchanged in Gitea.' :
          (result === 'invalid' ? 'Choose a valid future time.' : 'Could not save Later on this device.');
        if (result !== 'deferred') return;
        refreshMyWorkView();
      });
    });
    document.querySelectorAll('[data-later-custom]').forEach(button => {
      button.addEventListener('click', () => {
        const item = lastMyWork[Number(button.dataset.workIndex)];
        if (!item) return;
        if (!planningOwnerLogin) {
          qs('#my-work-action-status').textContent = 'Planning is unavailable until your operator identity is restored.';
          return;
        }
        laterPicker.open(item, button, 'card');
      });
    });
    document.querySelectorAll('[data-later-restore]').forEach(button => {
      button.addEventListener('click', () => {
        const item = lastMyWork[Number(button.dataset.workIndex)];
        if (!item || !laterWork.restore(item)) return;
        qs('#my-work-action-status').textContent = 'Work returned to its priority position.';
        refreshMyWorkView();
      });
    });
    document.querySelectorAll('[data-later-start]').forEach(button => {
      button.addEventListener('click', async () => {
        const item = lastMyWork[Number(button.dataset.workIndex)];
        if (!item) return;
        button.disabled = true;
        await laterAndStart.start(item);
        if (button.isConnected) button.disabled = false;
      });
    });
    document.querySelectorAll('[data-today-add]').forEach(button => {
      button.addEventListener('click', () => {
        if (!planningOwnerLogin) {
          qs('#my-work-action-status').textContent = 'Planning is unavailable until your operator identity is restored.';
          return;
        }
        const result = todayWork.add(lastMyWork[Number(button.dataset.workIndex)]);
        qs('#my-work-action-status').textContent = result === 'full' ?
          'Today is limited to 5 items. Remove one before adding more.' :
          (result === 'added' ? 'Added to Today without changing Gitea.' :
            (result === 'exists' ? 'This item is already in Today.' : 'Could not save Today on this device.'));
        refreshMyWorkView();
        if (result === 'added') {
          const item = lastMyWork[Number(button.dataset.workIndex)];
          todaySync.enqueue('add', todayWork.identity(item));
          todaySync.flush();
          warmTodayOffline();
        }
      });
    });
    document.querySelectorAll('[data-today-remove]').forEach(button => {
      button.addEventListener('click', () => {
        const item = lastMyWork[Number(button.dataset.workIndex)];
        if (todayWork.remove(item)) {
          todaySync.enqueue('remove', todayWork.identity(item));
          todaySync.flush();
        }
        qs('#my-work-action-status').textContent = 'Removed from Today without changing Gitea.';
        refreshMyWorkView();
      });
    });
    document.querySelectorAll('[data-today-move]').forEach(button => {
      button.addEventListener('click', () => {
        const item = lastMyWork[Number(button.dataset.workIndex)];
        if (todayWork.move(item, button.dataset.todayMove)) {
          todaySync.enqueue('move', todayWork.identity(item), button.dataset.todayMove);
          todaySync.flush();
        }
        refreshMyWorkView();
        document.querySelector('[data-today-move="' + button.dataset.todayMove + '"][data-work-index="' + button.dataset.workIndex + '"]')?.focus();
      });
    });
    const bulkBar = qs('#bulk-mark-read-bar');
    const bulkButton = qs('#bulk-mark-read');

    const updateIds = notificationIds(visible);
    const selectionControls = qs('#update-selection-controls');
    const planningQueue = !['today', 'later', 'draft'].includes(selectedWorkFilter) && visible.length > 0;
    selectionControls.hidden = !planningQueue && (selectedWorkFilter !== 'update' || updateIds.length === 0);
    qs('#select-work').hidden = !planningQueue || workSelectionState.active || selection.active;
    qs('#cancel-work-selection').hidden = !workSelectionState.active;
    const selectionScopeActions = qs('#selection-scope-actions');
    selectionScopeActions.hidden = !workSelectionState.active;
    qs('#select-matching-work').disabled = visible.length === 0 || workSelectionState.count >= workSelection.limit;
    qs('#clear-work-selection').disabled = workSelectionState.count === 0;
    qs('#select-matching-work').onclick = () => {
      const result = workSelection.selectMany(visible);
      qs('#my-work-action-status').textContent = result.status === 'limit' ?
        result.count + ' matches selected. Selection is capped at ' + result.limit + ' items.' :
        result.count + ' matches selected from the current queue and search.';
    };
    qs('#clear-work-selection').onclick = () => {
      workSelection.clear();
      qs('#my-work-action-status').textContent = 'Selection cleared. Choose new matches or individual work.';
      qs('#select-matching-work').focus();
    };
    qs('#select-updates').hidden = selectedWorkFilter !== 'update' || selection.active || workSelectionState.active;
    qs('#cancel-update-selection').hidden = !selection.active;
    qs('#update-selection-status').textContent = workSelectionState.active ?
      workSelectionState.count + ' selected' : (selection.active ?
        selection.count + ' of 50 selected' : 'Choose work to plan together or specific updates to mark read.');
    bulkBar.hidden = !workSelectionState.active && (selectedWorkFilter !== 'update' || !selection.active);
    qs('#load-more-notifications').hidden =
      selectedWorkFilter !== 'update' || !notificationPagination.has_more;
    bulkButton.disabled = bulkMarkPending || selection.count === 0;
    document.querySelectorAll('[data-defer-selected]').forEach(button => {
      button.hidden = workSelectionState.active;
      button.disabled = bulkMarkPending || selection.count === 0 || !planningOwnerLogin;
    });
    qs('#batch-add-today').hidden = !workSelectionState.active;
    qs('#batch-add-today').disabled = workSelectionState.count === 0 || !planningOwnerLogin;
    document.querySelectorAll('[data-batch-defer]').forEach(button => {
      button.hidden = !workSelectionState.active;
      button.disabled = workSelectionState.count === 0 || !planningOwnerLogin;
    });
    bulkButton.hidden = workSelectionState.active;
    bulkButton.textContent = bulkConfirmationPending ?
      'Confirm marking ' + selection.count + ' selected read' :
      'Mark ' + selection.count + ' selected read';
    workRoute.setItems(lastMyWork);
  }

  function reviewFileElement(filename) {
    return Array.from(document.querySelectorAll('.review-file')).find(
      element => element.dataset.reviewFilename === filename
    );
  }

  function applyReviewWrap(snapshot = wrapPreference.snapshot()) {
    const reviewFilesElement = qs('#review-files');
    const button = qs('#review-wrap-lines');
    reviewFilesElement.classList.toggle('wrap-lines', snapshot.wrapped);
    button.setAttribute('aria-pressed', String(snapshot.wrapped));
    button.textContent = snapshot.wrapped ? 'Lines wrapped' : 'Wrap lines';
  }

  function showReviewProgress(snapshot) {
    const complete = snapshot.total > 0 && snapshot.reviewedCount === snapshot.total;
    qs('#review-progress').textContent = complete ?
      'All files reviewed — finish in Gitea' :
      (snapshot.newHead ? 'New commits detected · ' : '') + snapshot.reviewedCount + ' of ' + snapshot.total + ' files reviewed';
    qs('#next-unreviewed-review').disabled = !snapshot.nextFilename;
    document.querySelectorAll('.review-mark').forEach(button => {
      const reviewed = snapshot.reviewed.includes(button.dataset.reviewFilename);
      button.setAttribute('aria-pressed', String(reviewed));
      button.textContent = reviewed ? 'Reviewed' : 'Mark reviewed';
      button.closest('.review-file')?.classList.toggle('reviewed', reviewed);
    });
  }

  function openNextUnreviewed(snapshot) {
    if (!snapshot?.nextFilename) return;
    const file = reviewFileElement(snapshot.nextFilename);
    if (!file) return;
    const toggle = file.querySelector('.review-file-toggle');
    const panel = toggle && document.getElementById(toggle.getAttribute('aria-controls'));
    if (toggle && panel && toggle.getAttribute('aria-expanded') !== 'true') {
      createReviewController.toggleDiff(toggle, panel);
    }
    file.scrollIntoView({ behavior: 'smooth', block: 'center' });
    toggle?.focus();
  }

  function renderIssueComment(comment, controller = commentActions) {
    const actions = controller?.actionHtml?.(comment) || '';
    return '<div class="issue-comment" data-comment-id="' + Number(comment.id || 0) + '"><div class="small">' +
      escapeHtml(comment.author || 'Unknown author') +
      (comment.created_at ? ' · ' + escapeHtml(fmt(comment.created_at)) : '') +
      '</div>' + actions + '<div class="issue-sheet-content markdown-content">' +
      renderMarkdown(comment.body || 'No comment body provided.') + '</div></div>';
  }

  function paintIssueConversation(state, controller) {
    const comments = state?.comments || [];
    qs('#issue-comments').innerHTML = comments.length ?
      comments.map(comment => renderIssueComment(comment, controller)).join('') : '<div class="muted">No comments yet.</div>';
    qs('#load-older-issue-comments').hidden = !Number.isInteger(state?.older_page);
    qs('#issue-conversation-status').textContent = comments.length ?
      comments.length + ' of ' + Math.max(state.total || 0, comments.length) + ' messages loaded.' : 'No comments yet.';
  }

  function paintUpdateConversation(state, controller) {
    const comments = state?.comments || [];
    qs('#update-comments').innerHTML = comments.length ?
      comments.map(comment => renderIssueComment(comment, controller)).join('') : '<div class="muted">No comments yet.</div>';
    qs('#load-older-update-comments').hidden = !Number.isInteger(state?.older_page);
    qs('#update-conversation-status').textContent = comments.length ?
      comments.length + ' of ' + Math.max(state.total || 0, comments.length) + ' messages loaded.' : 'No comments yet.';
    const newest = qs('#update-comments .issue-comment:last-child');
    updateReadPosition.ready(String(selectedUpdate?.notification_id || ''), newest);
  }

  function paintPullConversation(state, controller) {
    const comments = state?.comments || [];
    qs('#pull-comments').innerHTML = comments.length ? comments.map(comment =>
      '<div class="pull-comment-card">' + renderIssueComment(comment, controller) + '</div>'
    ).join('') : '<div class="muted">No comments yet.</div>';
    qs('#load-older-pull-comments').hidden = !Number.isInteger(state?.older_page);
    qs('#pull-conversation-status').textContent = comments.length ?
      comments.length + ' of ' + Math.max(state.total || 0, comments.length) + ' messages loaded.' : 'No comments yet.';
  }

  function commentSurface(selector) {
    if (selector === '#issue-comments') return {
      context:{kind:'issue',item:selectedIssue}, pager:issueConversation,
      render:renderIssueConversation, status:qs('#issue-sheet-status'),
    };
    if (selector === '#pull-comments') return {
      context:{kind:'pull',item:selectedPull}, pager:pullConversation,
      render:renderPullConversation, status:qs('#pull-sheet-status'),
    };
    return {
      context:{kind:'update',item:selectedUpdate}, pager:notificationReader.commentPager(),
      render:renderUpdateConversation, status:qs('#update-sheet-status'),
    };
  }

  function wireCommentActions(selector, controller = commentActions) {
    controller.wire({
      root:qs(selector), getSurface:()=>commentSurface(selector),
      isOffline:()=>offlineWorkMode || navigator.onLine === false, escapeHtml,
    });
  }

  const conversationActionSurfaces = {
    issue: { selector:'#issue-comments', paint:paintIssueConversation },
    pull: { selector:'#pull-comments', paint:paintPullConversation },
    update: { selector:'#update-comments', paint:paintUpdateConversation },
  };
  const latestConversationStates = {};

  function wireConversationActions(kind) {
    if (kind === 'issue') wireCommentActions('#issue-comments');
    if (kind === 'pull') wireCommentActions('#pull-comments');
    if (kind === 'update') wireCommentActions('#update-comments');
  }

  function showConversationWithActions(kind, state) {
    const surface = conversationActionSurfaces[kind];
    latestConversationStates[kind] = state;
    return actionHydrator.show({
      root:qs(surface.selector), state, paint:surface.paint,
      retry:qs('#retry-' + kind + '-comment-actions'),
      wire:controller => wireConversationActions(kind, controller),
    });
  }

  function renderIssueConversation(state) { void showConversationWithActions('issue', state); }
  function renderPullConversation(state) { void showConversationWithActions('pull', state); }
  function renderUpdateConversation(state) { void showConversationWithActions('update', state); }

  function retryConversationActions(kind) {
    const state = latestConversationStates[kind];
    if (state) void showConversationWithActions(kind, state);
  }
  qs('#retry-issue-comment-actions').addEventListener('click', () => retryConversationActions('issue'));
  qs('#retry-pull-comment-actions').addEventListener('click', () => retryConversationActions('pull'));
  qs('#retry-update-comment-actions').addEventListener('click', () => retryConversationActions('update'));

  function renderIssueLabelEditor(item, confirmedNames, labels) {
    const list = qs('#issue-label-list');
    const status = qs('#issue-label-status');
    list.textContent = '';
    const draftIds = issueController.loadLabelDraft(item);
    const selectedIds = draftIds.length ? new Set(draftIds) : new Set(
      labels.filter(label => confirmedNames.includes(label.name)).map(label => Number(label.id))
    );
    list.innerHTML = labels.map(label =>
      '<label class="issue-label-option"><input type="checkbox" name="issue-label" value="' +
      Number(label.id) + '"' + (selectedIds.has(Number(label.id)) ? ' checked' : '') + '><span>' +
      escapeHtml(label.name) + '</span></label>'
    ).join('');
    status.textContent = labels.length ? 'Choose labels, then save.' : 'This repository has no labels.';
    qs('#save-issue-labels').disabled = false;
  }

  function selectedEditIssueLabelIds() {
    return Array.from(document.querySelectorAll('input[name="issue-label"]:checked'))
      .map(input => Number(input.value)).filter(Number.isInteger);
  }


  async function loadIssuePlanning() {
    const item = selectedIssue;
    const detail = selectedIssueDetail;
    if (!item || !detail) return;
    qs('#retry-issue-planning').hidden = true;
    qs('#issue-label-status').textContent = 'Loading labels…';
    qs('#issue-milestone-status').textContent = 'Loading milestones…';
    try {
      const planning = await planningLoader.open(selectedIssue);
      if (selectedIssue !== item) return;
      renderIssueLabelEditor(item, detail.labels || [], planning.labels);
      issueController.renderMilestoneEditor(item, detail.milestone, planning.milestones);
    } catch (_error) {
      if (selectedIssue !== item) return;
      qs('#issue-label-status').textContent = 'Labels could not be loaded.';
      qs('#issue-milestone-status').textContent = 'Milestones could not be loaded.';
      qs('#retry-issue-planning').hidden = false;
    }
  }

  function renderChecklistCompletion(detail) {
    const interactive = !issueController.readOnly(selectedIssue) && detail?.state === 'open' && detail?.updated_at;
    const completion = issueController.checklistCompletion(qs('#issue-sheet-body'), {
      interactive, today:workSession.active(), offline:selectedIssueOffline,
      dismissed:dismissedChecklistBody === detail?.body,
    });
    const bar = qs('#checklist-completion');
    bar.hidden = !completion.visible;
    qs('#checklist-completion-status').textContent = completion.status;
    qs('#complete-checklist-issue').textContent = completion.label;
  }

  function renderIssueBody(detail) {
    const interactive = !issueController.readOnly(selectedIssue) && detail.state === 'open' && detail.updated_at;
    issueController.renderTasks(qs('#issue-sheet-body'), detail, interactive);
    qs('#open-add-checklist-step').disabled = !interactive;
    renderChecklistCompletion(detail);
  }

  function applyIssueContent(editing, detail, confirmed) {
    const merged = issueController.mergeContent(
      lastContextSnapshot, editing, detail, confirmed, buildMyWork.replaceIssueContent
    );
    lastContextSnapshot = merged.snapshot;
    selectedIssue = merged.item;
    selectedIssueDetail = merged.detail;
    qs('#issue-sheet-title').textContent = confirmed.title;
    renderIssueBody(selectedIssueDetail);
    if (lastContextSnapshot) paintMyWork(lastContextSnapshot);
  }

  async function openIssueSheet(item, trigger, offlineDetail = null) {
    if (!item) return;
    const readOnly = issueController.readOnly(item);
    const withdrawable = item.is_filed && !item.is_assigned && !item.is_completed && item.state === 'open';
    const reassignable = item.is_filed && !item.is_completed && item.state === 'open' &&
      Array.isArray(item.assignees) && item.assignees.length > 0;
    qs('#issue-sheet').classList.toggle('read-only', readOnly);
    qs('#issue-sheet').classList.toggle('filed-reassignable', reassignable);
    issueDetailPosition.open(workDetailIdentity('issue', item));
    qs('#issue-planning').inert = false;
    qs('#issue-handoff').inert = false;
    selectedIssue = item;
    void conversationPhotoDrafts.switchTo('issue',
      { kind:'issue', repository:item.repository, number:item.number }, () => selectedIssue === item);
    void issueVoiceReply.open(conversationVoiceTarget('issue', item));
    dismissedChecklistBody = null;
    issueMentions.dismiss();
    selectedIssueOffline = Boolean(offlineDetail);
    selectedIssueDetail = null;
    delegatedParentReview = null;
    issueConversation = null;
    issueTrigger = trigger;
    qs('#issue-sheet').classList.add('open');
    qs('#issue-sheet-key').textContent = item.key || '';
    qs('#issue-sheet-title').textContent = item.title || 'Assigned issue';
    qs('#issue-sheet-status').textContent = 'Loading issue…';
    const completedItems = lastMyWork.filter(candidate => candidate?.is_completed && candidate?.is_filed);
    const completedPosition = completedItems.findIndex(candidate =>
      candidate.repository === item.repository && candidate.number === item.number
    );
    qs('#completed-filed-actions').hidden = !item.is_completed;
    qs('#complete-parent-and-acknowledge').hidden = true;
    qs('#complete-parent-and-acknowledge').disabled = true;
    qs('#filed-claim-actions').hidden = true;
    qs('#queue-filed-issue').disabled = true;
    qs('#start-filed-issue').disabled = true;
    qs('#completed-filed-progress').textContent = item.is_completed ?
      'Completed Filed issue ' + (completedPosition + 1) + ' of ' + completedItems.length : '';
    qs('#issue-sheet-body').textContent = '';
    checklistStepManagement.reset();
    qs('#checklist-step-label').value = '';
    qs('#open-add-checklist-step').disabled = true;
    qs('#add-checklist-step-form').hidden = true;
    qs('#add-checklist-step').value = '';
    qs('#add-checklist-step-status').textContent = '';
    qs('#checklist-completion').hidden = true;
    qs('#issue-labels').textContent = '';
    qs('#issue-assignees').textContent = '';
    qs('#issue-comments').textContent = '';
    qs('#load-older-issue-comments').hidden = true;
    qs('#issue-conversation-status').textContent = 'Loading newest messages…';
    qs('#issue-comment').value = issueController.loadDraft(item);
    qs('#issue-comment-title').textContent = readOnly ? 'Add follow-up' : 'Add comment';
    qs('#issue-comment-status').textContent = '';
    qs('#issue-handoff').open = false;
    qs('#issue-handoff-summary').textContent = reassignable ? 'Change delegate' : 'Hand off to teammate';
    qs('#issue-handoff-recipient').innerHTML = '<option value="">Select a teammate</option>';
    qs('#issue-handoff-recipient').disabled = true;
    qs('#confirm-issue-handoff').disabled = true;
    qs('#confirm-issue-handoff').textContent = reassignable ? 'Confirm change' :
      (workSession.checkpointed(item) ? 'Hand off & next' : 'Confirm handoff');
    qs('#load-issue-handoff').disabled = false;
    qs('#issue-handoff-status').textContent = reassignable ?
      'Load teammates to change the current delegate.' : 'Load teammates to transfer ownership.';
    qs('#issue-planning').open = false;
    qs('#retry-issue-planning').hidden = true;
    qs('#issue-label-list').textContent = '';
    qs('#issue-label-status').textContent = 'Expand planning controls to load labels.';
    qs('#save-issue-labels').disabled = true;
    qs('#issue-due-date').value = '';
    qs('#issue-due-date').disabled = true;
    qs('#save-issue-due-date').disabled = true;
    qs('#clear-issue-due-date').disabled = true;
    qs('#issue-due-status').textContent = 'Loading due date…';
    qs('#issue-milestone').innerHTML = '<option value="">No milestone</option>';
    qs('#issue-milestone').disabled = true;
    qs('#save-issue-milestone').disabled = true;
    qs('#issue-milestone-status').textContent = 'Expand planning controls to load milestones.';
    qs('#retry-issue-load').hidden = true;
    qs('#open-issue-gitea').href = item.url || '#';
    qs('#send-issue-comment').disabled = false;
    setCommentNextVisibility('issue');
    qs('#edit-issue-content').disabled = true;
    qs('#issue-edit-form').hidden = true;
    qs('#issue-edit-status').textContent = '';
    qs('#close-issue').disabled = false;
    qs('#close-issue').hidden = readOnly && !withdrawable;
    qs('#close-issue').textContent = withdrawable ? 'Withdraw issue' : offlineDetail ?
      (workSession.active() ? 'Queue close & next' : 'Queue issue closure') :
      (workSession.active() ? 'Close & next' : 'Close issue');
    qs('#release-issue').textContent = workSession.checkpointed(item) ? 'Release & next' : 'Release assignment';
    qs('#close-issue-sheet').focus();
    try {
      const loadedDetail = offlineDetail || await issueController.load(item);
      if (selectedIssue !== item) return;
      const detail = issueController.pendingTask(
        item, loadedDetail, authoredOutbox.list(), confirmedOwnerLogin
      );
      selectedIssueDetail = detail;
      renderPlanIssueDependencies(detail);
      issueConversation = issueController.conversation(item, detail.conversation);
      qs('#issue-sheet-title').textContent = detail.title || 'Assigned issue';
      renderIssueBody(detail);
      qs('#issue-labels').innerHTML = (detail.labels || []).map(label =>
        '<span class="pill">' + escapeHtml(label) + '</span>'
      ).join(' ');
      qs('#issue-assignees').textContent = (detail.assignees || []).length ?
        'Assigned to ' + detail.assignees.join(', ') : 'No assignee reported';
      const claimableFiling = !offlineDetail && filedClaimEligible(item, detail);
      qs('#filed-claim-actions').hidden = !claimableFiling;
      qs('#queue-filed-issue').disabled = !claimableFiling;
      qs('#start-filed-issue').disabled = !claimableFiling;
      if (readOnly) paintIssueConversation(issueConversation.snapshot(), null);
      else renderIssueConversation(issueConversation.snapshot());
      qs('#open-issue-gitea').href = detail.url || item.url || '#';
      qs('#issue-sheet-status').textContent = item.is_completed ?
        'Completed Filed outcome ready · review the conversation' : readOnly ? 'Filed issue ready · follow-up enabled' :
        'Issue ready · ' + (detail.state || 'open');
      const parentReference = item.is_completed && !offlineDetail ?
        issueController.delegatedParentReference(detail) : null;
      if (parentReference) {
        try {
          const parentItem = { ...parentReference, key:parentReference.repository + '#' + parentReference.number };
          const parentDetail = await issueController.load(parentItem);
          if (selectedIssue !== item) return;
          const relationship = issueController.resolveDelegatedParent(item, detail, parentDetail);
          if (relationship && parentDetail.state === 'open' && parentDetail.updated_at) {
            delegatedParentReview = { parentItem, parentDetail, relationship };
            const button = qs('#complete-parent-and-acknowledge');
            button.hidden = false;
            button.disabled = false;
            button.textContent = relationship.checklistComplete ?
              'Complete & close parent · acknowledge' : relationship.alreadyCompleted ?
                'Parent complete · acknowledge' : 'Complete parent step & acknowledge';
            qs('#completed-filed-progress').textContent = relationship.checklistComplete ?
              'Delegated outcome completes the parent checklist. Confirm to close the parent.' :
              relationship.alreadyCompleted ? 'Parent checklist already reflects this outcome.' :
                'Delegated outcome ready · complete its parent checklist step.';
          }
        } catch (_error) {
          if (selectedIssue !== item) return;
          delegatedParentReview = null;
        }
      }
      const revisableFiling = item.is_filed && !item.is_completed && detail.state === 'open';
      qs('#edit-issue-content').textContent = revisableFiling ? 'Revise filing' : 'Edit issue';
      qs('#edit-issue-content').disabled = readOnly && !revisableFiling;
      const dueDraft = issueController.loadDueDateDraft(item);
      qs('#issue-due-date').value = String(dueDraft || detail.due_date || '').slice(0, 10);
      qs('#issue-due-date').disabled = false;
      qs('#save-issue-due-date').disabled = false;
      qs('#clear-issue-due-date').disabled = !detail.due_date;
      qs('#issue-due-status').textContent = detail.due_date ?
        'Due ' + formatCalendarDueDate(detail.due_date) : 'No due date set.';
      if (qs('#issue-planning').open && !offlineDetail) loadIssuePlanning();
      if (offlineDetail) {
        setOfflineDetailControls('issue');
        qs('#issue-sheet-status').textContent = 'Offline copy · saved ' + fmt(detail.saved_at) +
          ' · comments queue for sync';
      } else if (offlineWorkStore.enabled() && confirmedOwnerLogin && todayWork.contains(item)) {
        await offlineWorkStore.saveDetail(confirmedOwnerLogin, item, detail);
      }
    } catch (error) {
      if (selectedIssue !== item) return;
      qs('#issue-sheet-status').textContent = error.message + ' Retry here or open it in Gitea.';
      qs('#retry-issue-load').hidden = false;
      qs('#retry-issue-load').focus();
    }
  }

  function closeIssueSheet(navigate = true) {
    if (navigate && issueEditHistoryActive) {
      history.back();
      return;
    }
    if (navigate && createWorkRoute.parse(window.location.hash)) {
      workRoute.close();
      return;
    }
    mobileComposerViewport.close(qs('#issue-sheet .issue-sheet-panel'));
    issueVoiceReply.cancel();
    void conversationPhotoDrafts.leave('issue');
    qs('#issue-sheet').classList.remove('open');
    selectedIssue = null;
    selectedIssueOffline = false;
    selectedIssueDetail = null;
    issueConversation = null;
    if (issueTrigger?.isConnected) issueTrigger.focus();
  }

  function closeIssueEditorFromHistory() {
    if (!issueEditHistoryActive) return;
    issueEditHistoryActive = false;
    qs('#issue-edit-form').hidden = true;
    if (selectedIssue) qs('#edit-issue-content').focus();
  }
  window.addEventListener('popstate', closeIssueEditorFromHistory);

  function acknowledgeCompletedFiled() {
    if (!selectedIssue?.is_completed) return;
    if (!completedFiledReview.acknowledge(selectedIssue)) {
      qs('#issue-sheet-status').textContent = 'Could not save this acknowledgement on this device. Retry.';
      return;
    }
    const acknowledged = selectedIssue;
    closeIssueSheet(false);
    refreshMyWorkView();
    const target = filedFollowUpTarget(completedFiledReview.visible(lastMyWork));
    qs('#my-work-action-status').textContent = 'Reviewed ' + acknowledged.key + '.' +
      (target ? ' Opening the next Filed item. Acknowledgement sync pending.' :
        ' Filed review is complete. Acknowledgement sync pending.');
    void syncCompletedFiledReviews();
    if (target) {
      const index = lastMyWork.indexOf(target.item);
      const trigger = qs('#my-work-list [data-' + target.kind + '-index="' + index + '"]');
      openRoutedWork(target.kind === 'update' ? { ...target.item, kind:'update' } : target.item, trigger);
    } else {
      if (mobileStartDay.completePhase('filed')) return;
      window.location.hash = '#/my-work/filed';
      qs('#my-work').focus();
    }
  }

  qs('#acknowledge-completed-filed').addEventListener('click', acknowledgeCompletedFiled);

  qs('#complete-parent-and-acknowledge').addEventListener('click', async () => {
    if (!selectedIssue?.is_completed || !delegatedParentReview) return;
    const button = qs('#complete-parent-and-acknowledge');
    const { parentItem, parentDetail, relationship } = delegatedParentReview;
    if (relationship.checklistComplete && !window.confirm(
      'Complete the final checklist step and close ' + parentItem.key + '?'
    )) return;
    button.disabled = true;
    try {
      await issueController.finishDelegatedParentReview({
        relationship, parentItem, parentDetail, childUrl:selectedIssue.url,
        updateContent:(item, payload) => issueController.updateContent(item, payload),
        closeParent:item => issueController.close(item),
      });
      acknowledgeCompletedFiled();
    } catch (error) {
      if (!selectedIssue) return;
      button.disabled = false;
      qs('#issue-sheet-status').textContent =
        'Parent review action did not finish. Reload the parent relationship and retry. ' + error.message;
      button.focus();
    }
  });

  function renderCheckSection(prefix, detail, offline = false) {
    const rendered = createReviewController.renderChecks(detail?.checks, escapeHtml, { offline });
    qs('#' + prefix + '-checks-summary').textContent = rendered.summary;
    qs('#' + prefix + '-check-list').innerHTML = rendered.html || '<div class="muted">No individual checks were reported.</div>';
    qs('#' + prefix + '-checks').open = rendered.expanded;
  }

  function renderPullReview(detail, focusFilename = null) {
    renderCheckSection('pull', detail);
    pullReviewState = pullController.reviewState(selectedPull, detail);
    qs('#pull-review-progress').textContent = pullReviewState.total ?
      pullReviewState.reviewed.length + ' of ' + pullReviewState.total + ' files reviewed' : 'No changed files to review';
    qs('#next-unreviewed-pull-file').disabled = pullReviewState.complete;
    const eligibility = createPullSheet.mergeEligibility(detail, pullReviewState);
    qs('#pull-merge-state').textContent = eligibility.reason;
    qs('#merge-pull').disabled = !eligibility.allowed;
    qs('#pull-files').innerHTML = (detail.files || []).length ? detail.files.map((file, index) =>
      createPullSheet.renderFile(file, index, pullReviewState.reviewed.includes(file.filename), escapeHtml)
    ).join('') : '<div class="muted">No changed files reported.</div>';
    qs('#pull-files').querySelectorAll('.pull-file-toggle').forEach(button => {
      button.addEventListener('click', () => {
        const panel = document.getElementById(button.getAttribute('aria-controls'));
        const expanded = button.getAttribute('aria-expanded') === 'true';
        button.setAttribute('aria-expanded', String(!expanded));
        if (panel) panel.hidden = expanded;
      });
    });
    qs('#pull-files').querySelectorAll('.pull-review-file').forEach(button => {
      button.addEventListener('click', () => {
        const filename = button.dataset.pullReviewFile;
        pullReviewState = pullController.toggleReviewed(selectedPull, detail, filename);
        renderPullReview(detail, filename);
      });
    });
    if (focusFilename) {
      Array.from(qs('#pull-files').querySelectorAll('.pull-review-file'))
        .find(button => button.dataset.pullReviewFile === focusFilename)?.focus();
    }
  }

  function renderPullCheckStatus(status) {
    qs('#pull-ci-state').textContent = 'CI ' + (status.ci_state || 'unknown');
    renderCheckSection('pull', status);
    if (status.head_sha !== selectedPullDetail?.head_sha) {
      qs('#pull-review-status').textContent = 'New commits detected. Reload review data before merging.';
      qs('#pull-merge-state').textContent = 'Review data is stale';
      qs('#merge-pull').disabled = true;
      return;
    }
    selectedPullDetail = { ...selectedPullDetail, ...status };
    const eligibility = createPullSheet.mergeEligibility(selectedPullDetail, pullReviewState);
    qs('#pull-merge-state').textContent = eligibility.reason;
    qs('#merge-pull').disabled = !eligibility.allowed;
    qs('#pull-review-status').textContent = 'Checks refreshed for the current head.';
  }

  async function loadPullReview({ refresh = false } = {}) {
    if (!selectedPull || !selectedPullDetail?.head_sha) return;
    const item = selectedPull;
    const readDetail = selectedPullDetail;
    qs('#pull-review-status').textContent = 'Loading changed files and merge readiness…';
    qs('#pull-review-retry').hidden = true;
    qs('#merge-pull').disabled = true;
    try {
      const review = await pullController.loadReview(item, readDetail.head_sha, { refresh });
      if (selectedPull !== item) return;
      selectedPullDetail = { ...readDetail, ...review };
      qs('#pull-ci-state').textContent = 'CI ' + (review.ci_state || 'unknown');
      renderPullReview(selectedPullDetail);
      qs('#pull-review-status').textContent = review.head_sha === readDetail.head_sha ?
        'Review data ready for the current head.' : 'New commits detected. Review progress restarted for the latest head.';
    } catch (error) {
      if (selectedPull !== item) return;
      qs('#pull-review-status').textContent = error.message + ' Reading and replies remain available; retry here.';
      qs('#pull-review-retry').hidden = false;
      qs('#pull-merge-state').textContent = 'Review data unavailable';
      qs('#merge-pull').disabled = true;
    }
  }

  async function openPullSheet(item, trigger, offlineDetail = null) {
    if (!item) return;
    if (!await ensurePullWorkflow(trigger)) return;
    pullDetailPosition.open(workDetailIdentity('pull', item));
    qs('#pull-review').inert = false;
    qs('#pull-ownership').inert = false;
    selectedPull = item;
    void conversationPhotoDrafts.switchTo('pull',
      { kind:'pull', repository:item.repository, number:item.number }, () => selectedPull === item);
    void pullVoiceReply.open(conversationVoiceTarget('pull', item));
    pullMentions.dismiss();
    pullTrigger = trigger;
    selectedPullDetail = null;
    pullConversation = null;
    pullReviewState = null;
    qs('#pull-sheet').classList.add('open');
    qs('#pull-sheet-key').textContent = item.key || '';
    qs('#pull-sheet-title').textContent = item.title || 'Assigned pull request';
    qs('#pull-sheet-status').textContent = 'Loading pull request…';
    qs('#pull-sheet-body').textContent = '';
    qs('#pull-files').textContent = '';
    qs('#pull-review').open = false;
    qs('#pull-review-status').textContent = 'Expand to load changed files and merge readiness.';
    qs('#pull-review-retry').hidden = true;
    qs('#pull-review-progress').textContent = 'Review progress unavailable.';
    qs('#next-unreviewed-pull-file').disabled = true;
    qs('#pull-comments').textContent = '';
    qs('#load-older-pull-comments').hidden = true;
    qs('#pull-conversation-status').textContent = 'Loading newest messages…';
    qs('#pull-comment').value = pullController.loadDraft(item);
    qs('#pull-comment-status').textContent = '';
    qs('#pull-ci-state').textContent = 'CI unknown';
    qs('#pull-checks-summary').textContent = 'Not loaded';
    qs('#pull-check-list').textContent = '';
    qs('#pull-checks').open = false;
    qs('#pull-merge-state').textContent = 'Review data not loaded';
    qs('#merge-pull').disabled = true;
    qs('#merge-pull').textContent = workSession.active() ? 'Merge & next' : 'Merge';
    createPullSheet.resetOwnershipControls(document, item, candidate => workSession.checkpointed(candidate));
    qs('#retry-pull-load').hidden = true;
    qs('#open-pull-gitea').href = item.url || '#';
    setCommentNextVisibility('pull');
    qs('#close-pull-sheet').focus();
    try {
      const detail = offlineDetail || await pullController.load(item);
      if (selectedPull !== item) return;
      selectedPullDetail = detail;
      pullConversation = pullController.conversation(item, detail.conversation);
      qs('#pull-sheet-title').textContent = detail.title || 'Assigned pull request';
      qs('#pull-sheet-body').innerHTML = renderMarkdown(detail.body || 'No description provided.');
      renderPullConversation(pullConversation.snapshot());
      qs('#open-pull-gitea').href = detail.url || item.url || '#';
      qs('#pull-sheet-status').textContent = 'Pull request ready · by ' + (detail.author || 'unknown author');
      if (offlineDetail) {
        setOfflineDetailControls('pull');
        qs('#pull-sheet-status').textContent = 'Offline copy · saved ' + fmt(detail.saved_at) +
          ' · comments queue for sync';
      } else if (offlineWorkStore.enabled() && confirmedOwnerLogin && todayWork.contains(item)) {
        await offlineWorkStore.saveDetail(confirmedOwnerLogin, item, detail);
      }
    } catch (error) {
      if (selectedPull !== item) return;
      qs('#pull-sheet-status').textContent = error.message + ' Retry here or open it in Gitea.';
      qs('#retry-pull-load').hidden = false;
      qs('#retry-pull-load').focus();
    }
  }

  function closePullSheet(navigate = true) {
    if (navigate && createWorkRoute.parse(window.location.hash)) {
      workRoute.close();
      return;
    }
    mobileComposerViewport.close(qs('#pull-sheet .pull-sheet-panel'));
    pullVoiceReply.cancel();
    void conversationPhotoDrafts.leave('pull');
    qs('#pull-sheet').classList.remove('open');
    selectedPull = null;
    selectedPullDetail = null;
    pullConversation = null;
    pullReviewState = null;
    if (pullTrigger?.isConnected) pullTrigger.focus();
  }

  function selectedIssueLabelIds() {
    return Array.from(document.querySelectorAll('input[name="create-issue-label"]:checked'))
      .map(input => Number(input.value)).filter(Number.isInteger);
  }

  function selectedIssueLabelNames() {
    return Array.from(document.querySelectorAll('input[name="create-issue-label"]:checked'))
      .map(input => input.closest('label')?.querySelector('span')?.textContent?.trim()).filter(Boolean);
  }

  function renderAvailableIssues(items) {
    const list = qs('#find-work-list');
    const selection = findWorkController.selection();
    list.innerHTML = items.length ? items.map((item, index) => {
      const expanded = findWorkController.isPreviewed(item);
      const selected = findWorkController.isSelected(item);
      const detailId = 'find-work-detail-' + index;
      const detail = '<div id="' + detailId + '" class="find-work-detail"' + (expanded ? '' : ' hidden') +
        '><div class="find-work-description markdown-content">' + renderMarkdown(item.body || 'No description provided.') + '</div>' +
        (item.url ? '<a href="' + escapeHtml(item.url) + '" target="_blank" rel="noopener noreferrer">Open in Gitea</a>' : '') +
        '</div>';
      return '<article class="find-work-card' + (selected ? ' selected' : '') + '">' +
      (selection.active ? '<label class="find-work-select"><input type="checkbox" data-find-work-select="' + index +
        '"' + (selected ? ' checked' : '') + ' /> Select ' + escapeHtml(item.title || 'Untitled issue') + '</label>' : '') +
      '<div class="small">' + escapeHtml(item.repository) + '#' +
      Number(item.number) + '</div><strong>' + escapeHtml(item.title || 'Untitled issue') + '</strong>' +
      '<div>' + (item.labels || []).map(label => '<span class="pill">' + escapeHtml(label) + '</span>').join(' ') +
      '</div><button type="button" data-preview-index="' + index + '" aria-expanded="' + expanded +
      '" aria-controls="' + detailId + '">' + (expanded ? 'Hide details' : 'View details') + '</button>' +
      detail + '<div class="find-work-claim-actions"' + (selection.active ? ' hidden' : '') + '><button type="button" data-claim-index="' + index +
      '">Assign</button><button type="button" data-claim-queue-index="' + index +
      '">Queue Today</button><button type="button" data-claim-start-index="' + index +
      '">Start now</button></div></article>';
    }).join('') : '<div class="muted">No unassigned issues are available on this page.</div>';
    list.querySelectorAll('[data-find-work-select]').forEach(input => {
      input.addEventListener('change', () => {
        const item = findWorkController.items()[Number(input.dataset.findWorkSelect)];
        if (item) findWorkController.toggleSelection(item);
      });
    });
    list.querySelectorAll('[data-preview-index]').forEach(button => {
      button.addEventListener('click', () => {
        const item = findWorkController.items()[Number(button.dataset.previewIndex)];
        if (!item) return;
        const expanded = findWorkController.togglePreview(item);
        const detail = document.getElementById(button.getAttribute('aria-controls'));
        button.setAttribute('aria-expanded', String(expanded));
        button.textContent = expanded ? 'Hide details' : 'View details';
        if (detail) detail.hidden = !expanded;
      });
    });
    list.querySelectorAll('[data-claim-index]').forEach(button => {
      button.addEventListener('click', async () => {
        const item = findWorkController.items()[Number(button.dataset.claimIndex)];
        if (!item) return;
        button.disabled = true;
        try {
          const confirmed = await findWorkController.claim(item);
          const claimed = acceptClaimedIssue(confirmed);
          taskOverlayHistory.leave();
          refreshMyWorkView();
          qs('#my-work-action-status').textContent = confirmed.repository + '#' + confirmed.number + ' assigned to you.';
          openRoutedWork(claimed, qs('#find-work'));
        } catch (error) {
          qs('#find-work-status').textContent = error.message + ' Refresh and retry.';
          button.disabled = false;
          button.focus();
        }
      });
    });
    list.querySelectorAll('[data-claim-queue-index]').forEach(button => {
      button.addEventListener('click', async () => {
        const item = findWorkController.items()[Number(button.dataset.claimQueueIndex)];
        if (!item) return;
        const claimButtons = button.closest('.find-work-card')
          .querySelectorAll('[data-claim-index], [data-claim-queue-index], [data-claim-start-index]');
        claimButtons.forEach(action => { action.disabled = true; });
        try {
          const outcome = await assignAndStart.run(item, { destination:'queue' });
          if (outcome === 'queued') {
            (qs('[data-claim-queue-index]') || qs('#close-find-work')).focus();
          }
        } catch (error) {
          qs('#find-work-status').textContent = error.message + ' Nothing was added to Today; retry assignment.';
          claimButtons.forEach(action => { action.disabled = false; });
          button.focus();
        }
      });
    });
    list.querySelectorAll('[data-claim-start-index]').forEach(button => {
      button.addEventListener('click', async () => {
        const item = findWorkController.items()[Number(button.dataset.claimStartIndex)];
        if (!item) return;
        const claimButtons = button.closest('.find-work-card')
          .querySelectorAll('[data-claim-index], [data-claim-queue-index], [data-claim-start-index]');
        claimButtons.forEach(action => { action.disabled = true; });
        try {
          await assignAndStart.run(item);
        } catch (error) {
          qs('#find-work-status').textContent = error.message + ' Nothing was added to Today; retry assignment.';
          claimButtons.forEach(action => { action.disabled = false; });
          button.focus();
        }
      });
    });
  }

  async function openFindWorkSheet(navigate = true) {
    if (navigate) {
      taskOverlayHistory.open('find');
      return;
    }
    findingWork = true;
    qs('#find-work-sheet').classList.add('open');
    findWorkNavigation.open(batchFindWork.pending() > 0);
    const retainedItems = findWorkController.items();
    if (retainedItems.length) renderAvailableIssues(retainedItems);
    else qs('#find-work-list').textContent = '';
    qs('#find-work-status').textContent = retainedItems.length ?
      'Refreshing available issues…' : 'Loading available issues…';
    qs('#load-more-available').hidden = true;
    qs('#close-find-work').focus();
    try {
      const result = await findWorkController.load();
      if (!result?.stale) {
        qs('#find-work-status').textContent = findWorkController.items().length ?
          findWorkController.items().length + ' of ' + availablePagination.total + ' available issues loaded.' :
          'No unassigned issues are available.';
      }
    } catch (error) {
      qs('#find-work-status').textContent = error.message + ' Close and retry.';
    }
  }

  function closeFindWorkSheet(navigate = true) {
    if (navigate && taskOverlayHistory.current() === 'find') {
      taskOverlayHistory.close();
      return;
    }
    findingWork = false;
    qs('#find-work-sheet').classList.remove('open');
    qs('#find-work').focus();
  }

  let issueCaptureBlockers = [];

  function saveIssueCaptureDraft() {
    if (issueCapture) issueCapture.saveDraft(currentIssueCaptureDraft(false));
  }

  function currentIssueCaptureDraft(trim = true) {
    return withFilingEstimate(issueTemplatePicker.fields(
      issueOwnerPicker.draft(selectedIssueLabelIds(), issueCaptureBlockers, trim)
    ), qs('#create-issue-estimate').value);
  }

  let issueCaptureRepositories = [];
  let nextIssueRepositoryPage = 2;
  let moreIssueRepositoriesAvailable = false;
  let issueRepositorySearchTimer = null;
  let captureBlockerSearchTimer = null;

  function appendIssueRepositories(items) {
    const select = qs('#create-issue-repository');
    const selected = select.value;
    const known = new Set(issueCaptureRepositories);
    (Array.isArray(items) ? items : []).forEach(item => {
      const repository = String(item?.full_name || '').trim();
      if (!repository || known.has(repository)) return;
      known.add(repository);
      issueCaptureRepositories.push(repository);
      const option = document.createElement('option');
      option.value = repository;
      option.textContent = repository;
      select.appendChild(option);
    });
    if (selected) select.value = selected;
  }

  function updateIssueCreateActions() {
    issueOwnerPicker.updateActions(Boolean(qs('#create-issue-repository').value),
      issueCaptureBlockers.length > 0, createAndStart.available());
  }

  function renderIssueCaptureBlockers(blockers) {
    issueCaptureBlockers = Array.isArray(blockers) ? blockers.slice(0, 5) : [];
    const selected = qs('#create-issue-blocker-selected');
    selected.replaceChildren(...issueCaptureBlockers.map((blocker, index) => {
      const item = document.createElement('li');
      item.className = 'create-issue-blocker-selected';
      const text = document.createElement('span');
      text.textContent = blocker.repository + ' #' + blocker.number + ' — ' + blocker.title;
      const remove = document.createElement('button');
      remove.type = 'button';
      remove.textContent = 'Remove';
      remove.setAttribute('aria-label', 'Remove blocker ' + blocker.repository + ' #' + blocker.number);
      remove.addEventListener('click', () => {
        renderIssueCaptureBlockers(issueCaptureBlockers.filter((_value, position) => position !== index));
        saveIssueCaptureDraft();
      });
      item.append(text, remove);
      return item;
    }));
    qs('#create-issue-blocker-status').textContent = issueCaptureBlockers.length ?
      issueCaptureBlockers.length + ' blocker' + (issueCaptureBlockers.length === 1 ? '' : 's') +
        ' selected. Blocked work will be created without starting.' : 'No blockers selected.';
    updateIssueCreateActions();
  }

  function renderIssueCaptureBlockerResults(items) {
    const results = qs('#create-issue-blocker-results');
    results.replaceChildren();
    (Array.isArray(items) ? items : []).filter(candidate => !issueCaptureBlockers.some(blocker =>
      blocker.repository === candidate.repository && blocker.number === Number(candidate.number))).forEach(candidate => {
      const button = document.createElement('button');
      button.type = 'button';
      button.className = 'create-issue-blocker-result';
      button.setAttribute('role', 'option');
      button.textContent = candidate.repository + ' #' + candidate.number + ' — ' + candidate.title;
      button.addEventListener('click', () => {
        renderIssueCaptureBlockers([...issueCaptureBlockers, {
          repository:candidate.repository, number:Number(candidate.number), title:candidate.title,
        }]);
        results.hidden = true;
        qs('#create-issue-blocker-search').value = '';
        saveIssueCaptureDraft();
      });
      results.appendChild(button);
    });
    results.hidden = !results.childElementCount;
  }

  function renderIssueRepositoryResults(items) {
    const results = qs('#create-issue-repository-results');
    results.replaceChildren();
    (Array.isArray(items) ? items : []).forEach(item => {
      const repository = String(item?.full_name || '').trim();
      if (!repository) return;
      const button = document.createElement('button');
      button.type = 'button';
      button.className = 'create-issue-repository-result';
      button.setAttribute('role', 'option');
      button.textContent = repository;
      button.addEventListener('click', () => selectIssueCaptureRepository(repository));
      results.appendChild(button);
    });
    results.hidden = !results.childElementCount;
  }

  function selectIssueCaptureRepository(repository) {
    appendIssueRepositories([{full_name: repository}]);
    qs('#create-issue-repository').value = repository;
    qs('#create-issue-repository-search').value = repository;
    qs('#create-issue-repository-results').hidden = true;
    qs('#create-issue-repository-status').textContent = 'Selected ' + repository + '.';
    issueOwnerPicker.reset(repository);
    loadIssueFilingMetadata(repository);
    saveIssueCaptureDraft();
    scheduleIssueDuplicateCheck();
    updateIssueCreateActions();
    qs('#create-issue-title').focus();
  }

  let duplicateCheckTimer = null;
  function renderIssueDuplicates(state) {
    if (state.status === 'stale') return;
    const panel = qs('#create-issue-duplicates');
    const list = qs('#create-issue-duplicate-list');
    const status = qs('#create-issue-duplicate-status');
    const anyway = qs('#create-issue-anyway');
    list.replaceChildren();
    anyway.hidden = true;
    if (state.status === 'idle') {
      panel.hidden = true;
      return;
    }
    panel.hidden = false;
    if (state.status === 'failed') {
      status.textContent = 'Could not check for existing issues. You can still create this issue.';
      return;
    }
    if (!state.candidates.length) {
      status.textContent = 'No similar open issues found in this repository.';
      return;
    }
    status.textContent = (state.partial ? 'Search was incomplete. ' : '') + state.candidates.length +
      ' similar open issue' + (state.candidates.length === 1 ? '' : 's') +
      ' found. ' + (state.partial ? 'You can continue without waiting.' : 'Review before creating another.');
    state.candidates.forEach(item => {
      const card = document.createElement('article');
      card.className = 'create-issue-duplicate-card';
      const key = document.createElement('span');
      key.className = 'small';
      key.textContent = item.repository + ' #' + item.number;
      const link = document.createElement('a');
      link.textContent = item.title || 'Review existing issue';
      link.href = safeSearchUrl(item.url) || '#';
      link.target = '_blank';
      link.rel = 'noopener noreferrer';
      link.addEventListener('click', saveIssueCaptureDraft);
      card.append(key, link);
      list.appendChild(card);
    });
  }

  function scheduleIssueDuplicateCheck() {
    clearTimeout(duplicateCheckTimer);
    const draft = currentIssueCaptureDraft();
    duplicateCheckTimer = setTimeout(async () => {
      renderIssueDuplicates(await issueCapture.findDuplicates(draft));
    }, 350);
  }

  async function loadIssueFilingMetadata(repository, selected = {}) {
    return issueFilingMetadata.load(repository, selected);
  }

  function clearSharedLaunchUrl() {
    const cleanUrl = location.pathname + location.hash;
    history.replaceState(history.state || {}, '', cleanUrl);
  }

  function openStagedSharedContent() {
    if (!sharedLaunchState || sharedLaunchState.status === 'shown') return;
    openCreateIssueSheet();
    if (sharedLaunchState.status === 'conflict') {
      qs('#shared-content-conflict').hidden = false;
      qs('#create-issue-status').textContent = 'Choose which draft to continue.';
      qs('#resume-issue-draft').focus();
      sharedLaunchState = {status: 'shown'};
      return;
    }
    clearSharedLaunchUrl();
    sharedLaunchState = null;
  }

  let createIssueModalLifecycle = null;
  let createIssueLauncher = null;
  function issueCaptureModal() {
    if (createIssueModalLifecycle) return createIssueModalLifecycle;
    const root = qs('#create-issue-sheet');
    const background = Array.from(document.body.children).filter(element =>
      element !== root && element.tagName !== 'SCRIPT' && element.getAttribute('role') !== 'dialog'
    );
    createIssueModalLifecycle = createIssueCapture.createModalLifecycle({
      root, background, document, requestClose:() => closeCreateIssueSheet(),
    });
    return createIssueModalLifecycle;
  }

  async function openCreateIssueSheet(navigate = true) {
    const root = qs('#create-issue-sheet');
    if (!root.classList.contains('open') && document.activeElement && !root.contains(document.activeElement)) {
      createIssueLauncher = document.activeElement;
    }
    if (!issueCapture && !await ensureIssueCapture()) return;
    if (navigate) {
      taskOverlayHistory.open('new');
      return;
    }
    if (!sharedImageHandled && sharedImageMarker === 'bundle') {
      sharedImageHandled = true;
      if (createIssueAttachmentController.state()) {
        qs('#create-issue-attachment-status').textContent = 'Remove the current screenshot before adding the shared screenshots.';
      } else {
        await sharedImageCapture.consume({
          marker:sharedImageMarker,
          store:unfiledAttachmentStore,
          restore:value=>createIssueAttachmentController.restore(value),
          restoreContent:content=>{
            sharedLaunchState = issueCapture.stageSharedContent(content);
            sharedLaunchHandled = true;
          },
          status:message=>{ qs('#create-issue-attachment-status').textContent = message; },
        });
      }
      clearSharedLaunchUrl();
    }
    const captureDraft = issueCapture.loadDraft();
    issueTemplatePicker.reset(captureDraft);
    const initialRepositories = (lastContextSnapshot?.repos || []).map(repository => repository.full_name).filter(Boolean);
    if (!issueCaptureRepositories.length) issueCaptureRepositories = initialRepositories.slice();
    if (captureDraft.repository && !issueCaptureRepositories.includes(captureDraft.repository)) {
      issueCaptureRepositories.unshift(captureDraft.repository);
    }
    qs('#create-issue-repository').innerHTML = '<option value="">Choose repository</option>' + issueCaptureRepositories.map(repository =>
      '<option value="' + escAttr(repository) + '">' + escapeHtml(repository) + '</option>'
    ).join('');
    if (nextIssueRepositoryPage === 2) {
      moreIssueRepositoriesAvailable = lastContextSnapshot?.repository_pagination?.has_more === true;
    }
    qs('#load-more-issue-repositories').hidden = !moreIssueRepositoriesAvailable;
    if (captureDraft.repository) qs('#create-issue-repository').value = captureDraft.repository;
    else qs('#create-issue-repository').value = '';
    qs('#create-issue-repository-search').value = captureDraft.repository || '';
    qs('#create-issue-repository-results').hidden = true;
    qs('#create-issue-title').value = captureDraft.title;
    qs('#create-issue-body').value = captureDraft.body;
    setIssueFilingMode(Boolean(captureDraft.repository));
    qs('#create-issue-capture-status').textContent = '';
    qs('#create-issue-due-date').value = captureDraft.dueDate || '';
    qs('#create-issue-estimate').value = captureDraft.estimateMinutes || '';
    issueOwnerPicker.reset(captureDraft.repository, captureDraft);
    renderIssueCaptureBlockers(captureDraft.blockers || []);
    qs('#create-issue-blocker-search').value = '';
    qs('#create-issue-blocker-results').hidden = true;
    loadIssueFilingMetadata(qs('#create-issue-repository').value, captureDraft);
    scheduleIssueDuplicateCheck();
    qs('#create-issue-status').textContent = issueCaptureRepositories.length ? '' : 'No accessible repositories are available.';
    qs('#create-follow-up-next').hidden = !updateFollowUp?.source();
    updateIssueCreateActions();
    qs('#create-issue-sheet').classList.add('open');
    creatingIssue = true;
    issueCaptureModal().open(createIssueLauncher);
    if (!sharedImageHandled && sharedImageMarker) {
      sharedImageHandled = true;
      if (createIssueAttachmentController.state()) {
        qs('#create-issue-attachment-status').textContent = 'Remove the current screenshot before adding the shared screenshot.';
      } else {
        await sharedImageCapture.consume({
          marker:sharedImageMarker,
          store:unfiledAttachmentStore,
          restore:value=>createIssueAttachmentController.restore(value),
          status:message=>{ qs('#create-issue-attachment-status').textContent = message; },
        });
      }
      clearSharedLaunchUrl();
    }
    const mobileCapture = window.matchMedia?.('(max-width: 600px)').matches === true;
    const continuingCapture = Boolean(rUC || captureDraft.title || captureDraft.body || captureDraft.repository);
    if (unfiledShouldFocusTitle({mobile:mobileCapture, continuing:continuingCapture})) {
      qs('#create-issue-title').focus();
    }
  }

  function setIssueFilingMode(enabled) {
    applyIssueFilingMode(qs, enabled);
  }

  let suppressCreateDraftOnHistoryClose = false;
  async function startChecklistPromotion(context) {
    if (!issueCapture && !await ensureIssueCapture()) throw new Error('Issue capture is unavailable.');
    checklistPromotion.start(context);
    await openCreateIssueSheet();
  }
  const issueFilingReceipt = createIssueFilingReceipt({
    root:qs('#issue-filing-receipt'), heading:qs('#issue-filing-receipt-heading'),
    key:qs('#issue-filing-receipt-key'), title:qs('#issue-filing-receipt-title'),
    ownership:qs('#issue-filing-receipt-ownership'), openLink:qs('#issue-filing-receipt-open'),
    filedButton:qs('#issue-filing-receipt-filed'),
    shareButton:qs('#issue-filing-receipt-share'), relatedButton:qs('#issue-filing-receipt-related'),
    fileAnotherButton:qs('#issue-filing-receipt-another'),
    doneButton:qs('#issue-filing-receipt-done'), status:qs('#issue-filing-receipt-status'),
    navigator,
    onFileRelated:plan => {
      issueCapture.saveDraft(plan);
      createIssueAttachmentController.clear();
      qs('#new-issue').click();
    },
    onFileAnother:() => qs('#new-issue').click(),
    onViewFiled:issue => {
      selectMobileQueue('filed');
      openRoutedWork({
        ...issue, kind:'issue', is_filed:true, is_assigned:(issue.assignees || []).includes(confirmedOwnerLogin),
      });
    },
  });
  function closeCreateIssueSheet(navigate = true, preserveDraft = true) {
    if (navigate && taskOverlayHistory.current() === 'new') {
      suppressCreateDraftOnHistoryClose = !preserveDraft;
      taskOverlayHistory.leave();
      return;
    }
    qs('#create-issue-sheet').classList.remove('open');
    voiceIssueCapture.cancel();
    mobileComposerViewport.close(qs('.create-issue-panel'));
    clearTimeout(duplicateCheckTimer);
    qs('#create-issue-duplicates').hidden = true;
    creatingIssue = false;
    issueCaptureModal().close({restore:!followUpSourceUpdate});
    createIssueLauncher = null;
    if (createAndStartRequested) timerView.transferCapture();
    else timerView.finishCapture();
    if (followUpSourceUpdate) {
      const source = followUpSourceUpdate;
      followUpSourceUpdate = null;
      notificationReader.open(source.item, source.detail);
      return;
    }
  }

  function applyOutboxResult(result, openCreated = false, startCreated = false) {
    if (result.lease_skipped) { refreshMyWorkView(); return; }
    (result.confirmed || []).forEach(confirmed => {
      confirmed.work_reasons = ['created_by_me'];
      if (lastContextSnapshot) lastContextSnapshot.issues = [confirmed].concat(lastContextSnapshot.issues || []);
    });
    if (lastContextSnapshot) lastMyWork = buildMyWork(lastContextSnapshot);
    refreshMyWorkView();
    const startedCompletions = new Set();
    (result.completions || []).forEach(completion => {
      if (completion.ownerLogin !== activeFlushLogin || completion.intent !== 'create-and-start') return;
      const created = lastMyWork.find(item => item.kind === 'issue' &&
        item.repository === completion.issue?.repository && item.number === completion.issue?.number);
      if (!created) return;
      const outcome = createAndStart.complete(created, completion.estimateMinutes);
      if (outcome === 'started' || outcome === 'exists') {
        issueOutbox.completeIntent(completion.id, activeFlushLogin);
        startedCompletions.add(created.repository + '#' + created.number);
      }
    });
    if (result.confirmed?.length) {
      const keys = result.confirmed.map(issue => issue.repository + '#' + issue.number).join(', ');
      qs('#my-work-action-status').textContent = keys + ' created and assigned to you.';
      const confirmed = result.confirmed[result.confirmed.length - 1];
      (result.filings || []).filter(filing => filing.relatedDraft?.checklistPromotion).forEach(filing => {
        void checklistPromotion?.finish(filing.issue, filing.relatedDraft.checklistPromotion);
      });
      const created = lastMyWork.find(item =>
        item.kind === 'issue' && item.repository === confirmed.repository && item.number === confirmed.number
      );
      const completionHandled = startedCompletions.has(confirmed.repository + '#' + confirmed.number);
      if (!(confirmed.assignees || []).includes(activeFlushLogin)) {
        const filing = (result.filings || []).find(candidate => candidate.issue?.repository === confirmed.repository &&
          candidate.issue?.number === confirmed.number);
        issueFilingReceipt.show(confirmed, qs('#new-issue'), filing?.relatedDraft);
      }
      if (startCreated && !(result.completions || []).length && created) {
        const outcome = createAndStart.complete(created);
        if (outcome !== 'started' && openCreated) openRoutedWork(created, qs('#new-issue'));
      } else if (openCreated && created && !completionHandled) openRoutedWork(created, qs('#new-issue'));
    } else if ((result.remaining || []).some(item => item.status === 'attention')) {
      qs('#my-work-action-status').textContent = 'Needs attention · edit the queued issue before sending again.';
    } else {
      qs('#my-work-action-status').textContent = 'Queued for sync when the connection returns.';
    }
  }

  async function flushIssueOutbox() {
    if (!navigator.onLine || !activeFlushLogin || !issueOutbox.list().length) return;
    applyOutboxResult(await issueOutbox.flush(activeFlushLogin));
  }

  function applyAuthoredOutboxResult(result) {
    if (result.lease_skipped) { refreshMyWorkView(); return; }
    refreshMyWorkView();
    const attention = (result.remaining || []).some(item => item.status === 'attention');
    qs('#my-work-action-status').textContent = result.confirmed?.length ?
      result.confirmed.length + ' queued message' + (result.confirmed.length === 1 ? '' : 's') + ' sent.' :
      attention ? 'A queued message needs attention. Open Drafts to edit or discard it.' :
      'Message queued for sync when the connection returns.';
  }

  async function flushAuthoredOutbox() {
    if (!navigator.onLine || !activeFlushLogin || !authoredOutbox.list().length) return;
    applyAuthoredOutboxResult(await authoredOutbox.flush(activeFlushLogin));
  }

  async function flushNotificationReadOutbox() {
    if (!navigator.onLine || !activeFlushLogin || !notificationReadOutbox.list().length) return;
    const result = await notificationReadOutbox.flush(activeFlushLogin);
    if (result.confirmed?.length) {
      qs('#my-work-action-status').textContent = result.confirmed.length +
        ' queued update' + (result.confirmed.length === 1 ? '' : 's') + ' marked read.';
    }
  }

  function canQueueMessage(error) {
    const status = Number(error?.status || 0);
    return !status || status >= 500;
  }

  function inlineAnchor(target) {
    return {
      path: target.dataset.reviewFilename,
      ...(target.dataset.newPosition ? { new_position: Number(target.dataset.newPosition) } : {}),
      ...(target.dataset.oldPosition ? { old_position: Number(target.dataset.oldPosition) } : {}),
    };
  }

  function sameInlineAnchor(comment, anchor) {
    return comment.path === anchor.path && comment.new_position === anchor.new_position &&
      comment.old_position === anchor.old_position;
  }

  function closeInlineComposer() {
    mobileComposerViewport.close(qs('#review-sheet .review-sheet-panel'));
    qs('#review-inline-composer').hidden = true;
    qs('#review-inline-body').value = '';
    activeInlineTarget = null;
  }

  function openInlineComposer(target) {
    if (!draft) return;
    activeInlineTarget = target;
    const anchor = inlineAnchor(target);
    const existing = draft.snapshot().comments.find(comment => sameInlineAnchor(comment, anchor));
    qs('#review-inline-location').textContent = anchor.path + ' · line ' +
      (anchor.new_position || anchor.old_position) + (anchor.new_position ? ' (new)' : ' (old)');
    qs('#review-inline-body').value = existing?.body || '';
    qs('#delete-inline-comment').disabled = !existing;
    qs('#review-inline-composer').hidden = false;
    qs('#review-inline-body').focus();
  }

  async function openReviewSheet(item, trigger, cachedDetail = null) {
    if (!item || !await ensurePullWorkflow(trigger)) return;
    reviewDetailPosition.open(workDetailIdentity('review', item));
    mobileReviewDetailNavigation.reset();
    selectedReview = item;
    reviewTrigger = trigger;
    offlineReview = Boolean(cachedDetail);
    qs('#review-sheet').classList.add('open');
    qs('#review-sheet-key').textContent = item.key;
    qs('#review-sheet-title').textContent = item.title;
    qs('#review-sheet-status').textContent = 'Loading review details…';
    qs('#retry-review-load').hidden = true;
    qs('#review-sheet-body').textContent = '';
    qs('#review-files').textContent = '';
    applyReviewWrap();
    qs('#review-progress').textContent = '0 of 0 files reviewed';
    qs('#next-unreviewed-review').disabled = true;
    qs('#review-history').textContent = '';
    qs('#open-review-gitea').href = item.url;
    qs('#review-decision').value = 'comment';
    qs('#review-summary').value = '';
    qs('#review-copy-fallback').hidden = true;
    qs('#review-copy-fallback').value = '';
    qs('#review-handoff-link').hidden = true;
    qs('#review-handoff-link').href = item.url;
    qs('#review-handoff-status').textContent = '';
    qs('#review-submit-status').textContent = '';
    qs('#continue-review-to-merge').hidden = true;
    qs('#review-ci-state').textContent = 'CI unknown';
    qs('#review-checks-summary').textContent = cachedDetail ? 'Last known · loading' : 'Loading';
    qs('#review-check-list').textContent = '';
    qs('#review-checks').open = false;
    qs('#refresh-review-checks').disabled = offlineReview;
    qs('#submit-review').disabled = true;
    qs('#submit-review').textContent = offlineReview && reviewingActiveTodayItem() ? 'Queue review & next' :
      (offlineReview ? 'Queue review for reconnect' : 'Submit review');
    closeInlineComposer();
    draft = null;
    reviewFiles = [];
    selectedReviewHead = '';
    qs('#close-review-sheet').focus();
    try {
      const detail = cachedDetail || await reviewController.load(selectedReview);
      if (selectedReview !== item) return;
      qs('#review-sheet-body').innerHTML = renderMarkdown(detail.body || 'No description provided.');
      qs('#review-ci-state').textContent = 'CI ' + (detail.ci_state || 'unknown');
      renderCheckSection('review', detail, offlineReview);
      qs('#review-files').innerHTML = (detail.files || []).length ? detail.files.map((file, index) =>
        createReviewController.renderDiffFile(file, index, escapeHtml)
      ).join('') : '<div>No changed files reported.</div>';
      document.querySelectorAll('.review-file-toggle').forEach(button => {
        button.addEventListener('click', () => {
          const panel = document.getElementById(button.getAttribute('aria-controls'));
          if (panel) createReviewController.toggleDiff(button, panel);
        });
      });
      progress = createReviewController.createProgress({
        storage: localStorage,
        repository: item.repository,
        number: item.number,
        headSha: detail.head_sha || 'unknown',
        files: detail.files || [],
      });
      reviewFiles = detail.files || [];
      selectedReviewHead = detail.head_sha || '';
      draft = createReviewController.createDraft({
        storage: localStorage,
        repository: item.repository,
        number: item.number,
        headSha: detail.head_sha || 'unknown',
        files: reviewFiles,
      });
      const draftSnapshot = draft.snapshot();
      qs('#review-decision').value = draftSnapshot.decision;
      qs('#review-summary').value = draftSnapshot.summary;
      document.querySelectorAll('.review-note').forEach(note => {
        note.value = draftSnapshot.notes[note.dataset.reviewFilename] || '';
        note.addEventListener('input', () => draft.setNote(note.dataset.reviewFilename, note.value));
      });
      document.querySelectorAll('.review-inline-target').forEach(target => {
        const anchor = inlineAnchor(target);
        target.classList.toggle('has-draft', draftSnapshot.comments.some(comment =>
          sameInlineAnchor(comment, anchor)
        ));
        target.addEventListener('click', () => openInlineComposer(target));
      });
      document.querySelectorAll('.review-mark').forEach(button => {
        button.addEventListener('click', () => {
          const snapshot = progress.markReviewed(button.dataset.reviewFilename);
          showReviewProgress(snapshot);
          openNextUnreviewed(snapshot);
        });
      });
      const progressSnapshot = progress.snapshot();
      showReviewProgress(progressSnapshot);
      openNextUnreviewed(progressSnapshot);
      qs('#review-history').innerHTML = (detail.reviews || []).length ? detail.reviews.map(review =>
        '<div class="review-history"><strong>' + escapeHtml(review.user?.login || 'Reviewer') + '</strong> · ' +
        escapeHtml(review.state || 'commented') + (review.body ? '<div class="small markdown-content">' + renderMarkdown(review.body) + '</div>' : '') + '</div>'
      ).join('') : '<div>No prior reviews.</div>';
      qs('#review-sheet-status').textContent = offlineReview ?
        'Offline review · saved ' + fmt(detail.saved_at) + ' · draft feedback stays on this device.' :
        'Ready to review · by ' + (detail.author || 'unknown author');
      qs('#submit-review').disabled = false;
    } catch (error) {
      if (selectedReview !== item) return;
      qs('#review-sheet-status').textContent = error.message + ' Retry here or use Open in Gitea.';
      qs('#retry-review-load').hidden = false;
      qs('#retry-review-load').focus();
    }
  }

  function closeReviewSheet(navigate = true) {
    if (updateReviewHandoff.active()) {
      updateReviewHandoff.cancel();
      return;
    }
    if (navigate && createWorkRoute.parse(window.location.hash)) {
      workRoute.close();
      return;
    }
    mobileComposerViewport.close(qs('#review-sheet .review-sheet-panel'));
    qs('#review-sheet').classList.remove('open');
    selectedReview = null;
    offlineReview = false;
    progress = null;
    draft = null;
    reviewFiles = [];
    selectedReviewHead = '';
    closeInlineComposer();
    if (reviewTrigger?.isConnected) reviewTrigger.focus();
  }

  function closeUpdateSheet(restoreTrigger = true, navigate = true) {
    if (navigate && createWorkRoute.parse(window.location.hash)) {
      workRoute.close();
      return;
    }
    mobileComposerViewport.close(qs('#update-sheet .update-sheet-panel'));
    updateVoiceReply.cancel();
    void conversationPhotoDrafts.leave('update');
    qs('#update-sheet').classList.remove('open');
    selectedUpdate = null;
    selectedUpdateDetail = null;
    if (restoreTrigger && updateTrigger?.isConnected) updateTrigger.focus();
    else qs('[data-work-filter="update"]')?.focus();
  }

  function markMyWorkStale() {
    qs('#my-work').setAttribute('data-stale', 'true');
    qs('#my-work-status').textContent = lastMyWork.length ?
      'Update failed · showing last known work' : 'Work inbox unavailable.';
  }

  function markNotificationsStale() {
    qs('#my-work').setAttribute('data-stale', 'true');
    qs('#my-work-status').textContent = lastNotifications.length ?
      'Unread updates unavailable · showing last known updates' :
      'Unread updates unavailable · assigned work is fresh';
  }

  function paintDeltas(deltas) {
    const el = qs('#ai');
    el.innerHTML = deltas.length ? deltas.map(d => '<div class="suggestion ' + d.priority + '"><span class="pill">' + escapeHtml(d.priority) + '</span> <strong>' + escapeHtml(d.action) + '</strong> ' + escapeHtml(d.target || '') + '<div class="muted">' + escapeHtml(d.panel) + '</div></div>').join('') : '<div class="muted">No suggestions yet.</div>';
  }

  function paintEventStream(events) {
    const el = qs('#gitea-events');
    el.innerHTML = events.length ? events.slice(0, 12).map(event =>
      '<div class="event"><strong>' + escapeHtml(event.actor?.login || 'Gitea') + '</strong> ' +
      escapeHtml(event.type || 'activity') +
      '<div class="small">' + escapeHtml(event.repo?.full_name || '') +
      (event.created_at ? ' · ' + escapeHtml(fmt(event.created_at)) : '') + '</div></div>'
    ).join('') : '<div class="muted">No recent Gitea activity.</div>';
  }

  function setEventStreamStatus(message) {
    qs('#gitea-events-status').textContent = message;
  }

  async function renderLiveSnapshot(snapshot, changedSections = ['context', 'events', 'notifications']) {
    setOfflineWorkMode(false);
    offlineStatus.hidden = true;
    const contextFreshness = snapshot.freshness?.sections?.context;
    const eventsFreshness = snapshot.freshness?.sections?.events;
    const notificationFreshness = snapshot.freshness?.sections?.notifications;
    const contextChanged = changedSections.includes('context');
    const notificationsChanged = changedSections.includes('notifications');
    const eventsChanged = changedSections.includes('events');
    const workChanged = contextChanged || notificationsChanged;
    const hasNotifications = Array.isArray(snapshot.notifications);
    const notificationsFresh = hasNotifications && !notificationFreshness?.stale;
    if (notificationsChanged && hasNotifications) {
      if (notificationPagination.page > 1) {
        const byId = new Map(lastNotifications.map(item => [item.id, item]));
        snapshot.notifications.forEach(item => byId.set(item.id, item));
        lastNotifications = Array.from(byId.values());
      } else {
        lastNotifications = snapshot.notifications;
      }
      if (snapshot.notification_pagination) {
        const page = notificationPagination.page > 1 ? notificationPagination.page :
          snapshot.notification_pagination.page;
        notificationPager.reset({
          page,
          total: snapshot.notification_pagination.total,
          has_more: page * 50 < snapshot.notification_pagination.total,
        });
      }
    }
    if (snapshot.context && workChanged) {
      setOfflineWorkMode(false);
      const retainedPlanningLogin = !snapshot.context.error ?
        String(snapshot.context.user?.login || '').trim() : '';
      planningOwnerLogin = retainedPlanningLogin;
      updatePlanningAvailability();
      if (planningOwnerLogin) {
        syncPendingTomorrow();
        todaySync.migrate(todayWork.read());
        todaySync.flush();
        laterSync.migrate(laterWork.read());
        laterSync.flush();
      }
      const contextIdentityFresh = !snapshot.context.error && !contextFreshness?.stale &&
        !contextFreshness?.degraded && !contextFreshness?.revalidating;
      activeFlushLogin = contextIdentityFresh ? String(snapshot.context.user?.login || '').trim() : '';
      if (activeFlushLogin) {
        confirmedOwnerLogin = activeFlushLogin;
        timerView.render();
        restoreReleaseReceipt();
        updateDeliveryReceiptControls();
        interruptionPrompt.restore();
      }
      snapshot.context.notifications = lastNotifications;
      renderContextSnapshot(snapshot.context);
      if (contextFreshness?.stale) markMyWorkStale();
      else if (!notificationsFresh) markNotificationsStale();
      if (!contextFreshness?.stale && notificationsFresh) {
        const admitted = await offlineWorkStore.save({
          ...snapshot.context,
          notifications: snapshot.notifications,
          notification_pagination: snapshot.notification_pagination,
        });
        await updateOfflineWorkControls(admitted === false ?
          'Offline saving unavailable · retry after reconnect.' : undefined);
        warmTodayOffline();
      }
      flushIssueOutbox();
      flushAuthoredOutbox();
      flushNotificationReadOutbox();
    } else if (!snapshot.context) handleContextError(new Error('Context section unavailable'));
    if (eventsChanged && Array.isArray(snapshot.events)) paintEventStream(snapshot.events);
    if (eventsFreshness?.revalidating) {
      setEventStreamStatus('Refreshing activity · showing last activity');
    } else if (eventsFreshness?.stale || eventsFreshness?.degraded) {
      const retrySeconds = Number(eventsFreshness.retry_in_seconds) || 0;
      setEventStreamStatus('Activity refresh failed · showing last activity' +
        (retrySeconds > 0 ? ' · retrying in ' + retrySeconds + 's' : ''));
    } else if (Array.isArray(snapshot.events)) {
      setEventStreamStatus('Updated ' + fmt(new Date()));
    } else {
      setEventStreamStatus('Update failed · showing last activity');
    }
    if (!eventsFreshness && snapshot.freshness?.degraded && !snapshot.freshness.revalidating) {
      const retrySeconds = Number(snapshot.freshness.retry_in_seconds) || 0;
      setEventStreamStatus('Refresh failed · showing last known data' +
        (retrySeconds > 0 ? ' · retrying in ' + retrySeconds + 's' : ''));
    } else if (!eventsFreshness && snapshot.freshness?.revalidating) {
      setEventStreamStatus('Refreshing · showing recent snapshot');
    }
    renderLiveDataStatus(snapshot.freshness || {});
  }


  function escapeHtml(s) { return String(s || '').replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c])); }
  function escAttr(s) { return escapeHtml(s); }
  function openModal(id) { qs('#' + id).classList.add('open'); }
  function closeModal(id) { qs('#' + id).classList.remove('open'); }

  (function bg(){
    const c=qs('#bg'),ctx=c.getContext('2d');
    let w,h,time=0;
    const resize=()=>{ w=c.width=innerWidth; h=c.height=innerHeight; };
    resize(); addEventListener('resize', resize);
    const draw=()=>{
      time+=0.012;
      ctx.clearRect(0,0,w,h);
      ctx.strokeStyle='#1f3a5f'; ctx.lineWidth=1;
      const step=60;
      for(let x=0;x<w;x+=step){ ctx.beginPath(); ctx.moveTo(x,0); ctx.lineTo(x,h); ctx.stroke(); }
      for(let y=0;y<h;y+=step){ ctx.beginPath(); ctx.moveTo(0,y); ctx.lineTo(w,y); ctx.stroke(); }
      const cx=w/2+Math.sin(time*0.31)*90, cy=h/2+Math.cos(time*0.37)*70;
      const grad=ctx.createRadialGradient(cx,cy,20,cx,cy,260);
      grad.addColorStop(0,'rgba(96,165,250,.28)'); grad.addColorStop(1,'rgba(96,165,250,0)');
      ctx.fillStyle=grad; ctx.fillRect(0,0,w,h);
      requestAnimationFrame(draw);
    };
    draw();
  })();

  function initWhiteboard() {
    const canvas = qs('#wb'), ctx = canvas.getContext('2d');
    let drawing = false;
    function resize() { const dpr = window.devicePixelRatio||1; const r=canvas.getBoundingClientRect(); canvas.width=r.width*dpr; canvas.height=r.height*dpr; ctx.setTransform(dpr,0,0,dpr,0,0); ctx.lineCap='round'; ctx.lineJoin='round'; ctx.strokeStyle='#e5e7eb'; ctx.lineWidth=2; }
    resize(); addEventListener('resize', resize);
    const p = (e) => ({ x: e.clientX - canvas.getBoundingClientRect().left, y: e.clientY - canvas.getBoundingClientRect().top });
    canvas.addEventListener('pointerdown', (e)=>{ drawing=true; const pos=p(e); ctx.beginPath(); ctx.moveTo(pos.x, pos.y); });
    canvas.addEventListener('pointermove', (e)=>{ if (!drawing) return; const pos=p(e); ctx.lineTo(pos.x, pos.y); ctx.stroke(); });
    canvas.addEventListener('pointerup', () => drawing=false);
    canvas.addEventListener('pointerleave', () => drawing=false);
    qs('#wb-clear').addEventListener('click', () => { const r=canvas.getBoundingClientRect(); ctx.clearRect(0,0,r.width,r.height); });
    qs('#wb-save').addEventListener('click', () => { const a=document.createElement('a'); a.href=canvas.toDataURL(); a.download='whiteboard.png'; a.click(); });
  }

  qs('#md-input').addEventListener('input', renderMD);
  function renderMD() {
    const raw = qs('#md-input').value || '';
    qs('#md-preview').innerHTML = '<pre>' + escapeHtml(raw) + '</pre><div style="margin-top:8px;">' + renderMarkdown(raw) + '</div>';
  }

  const commands = [
    { name: 'Whiteboard', run: () => { openModal('whiteboard-modal'); initWhiteboard(); } },
    { name: 'Markdown', run: () => { qs('#md-input').focus(); } },
    { name: 'Refresh', run: load },
  ];
  let commandSearchState = { status:'idle', query:'', items:[] };
  let commandItems = [];
  let commandSelection = -1;
  let searchBatchPlanning = null;
  async function searchGlobalWork(query, signal, page = 1, scope = {kind:'all', state:'all'}, continuation) {
    const response = await fetch(filterCommands.searchUrl(query, page, scope, continuation), {
      headers: { Accept:'application/json' },
      signal,
    });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) throw new Error(payload.error || 'Search is temporarily unavailable.');
    return payload;
  }
  const commandSearch = filterCommands.createGlobalSearchController({
    search: searchGlobalWork,
    onState: state => {
      commandSearchState = state;
      renderCommands(state.query);
    },
  });
  function currentSearchScope() {
    return { kind:qs('#cmd-search-kind').value, state:qs('#cmd-search-state').value,
      repository:qs('#cmd-search-repository').value.trim() };
  }
  function applySearchScope(scope = {kind:'all', state:'all'}) {
    qs('#cmd-search-kind').value = scope.kind;
    qs('#cmd-search-state').value = scope.state;
    qs('#cmd-search-repository').value = scope.repository || '';
    commandSearch.setScope(scope);
  }
  let searchPreviewDetail = null;
  const renderSearchConversation = conversation =>
    renderSearchPreviewConversation(conversation, document, escapeHtml, fmt, renderMarkdown);
  function renderSearchPreview(state) {
    const sheet = qs('#search-preview');
    const status = qs('#search-preview-status');
    const claimButton = qs('#claim-search-result');
    const deferButton = qs('#defer-search-result');
    const queueButton = qs('#queue-search-result');
    const startButton = qs('#start-search-result');
    const shareButton = qs('#share-search-result');

    qs('#close-search-preview').textContent = searchPreviewReturnKind === 'today-readiness'
      ? 'Back to blockers' : 'Back to search';
    if (state.status === 'closed') {
      searchVoiceReply.cancel();
      sheet.classList.remove('open');
      return;
    }
    sheet.classList.add('open');
    claimButton.hidden = true;
    claimButton.disabled = false;
    deferButton.hidden = true;
    deferButton.disabled = false;
    queueButton.hidden = true;
    startButton.hidden = true;
    startButton.disabled = false;
    shareButton.disabled = true;
    renderSearchPreviewReply(state, null, searchPreview, document);

    if (state.status === 'loading') {
      searchReplyAttachmentTarget = { ...state.item };
      restoreSearchReplyPhotos(searchReplyAttachmentTarget);
      searchVoiceReply.open(searchConversationVoiceTarget(state.item));
      searchPreviewDetail = null;
      qs('#search-preview-key').textContent = state.item.repository + ' #' + state.item.number;
      qs('#search-preview-title').textContent = state.item.title || 'Work preview';
      qs('#search-preview-meta').textContent = '';
      qs('#search-preview-body').textContent = '';
      renderSearchConversation(null);
      qs('#open-search-result-gitea').href = safeSearchUrl(state.item.url) || '#';
      status.textContent = 'Loading preview…';
      return;
    }
    if (state.status === 'error') {
      status.textContent = state.error?.message || 'Preview unavailable. Open this result in Gitea or retry.';
      return;
    }
    const detail = state.detail;
    if (!detail) return;
    searchPreviewDetail = detail;
    shareButton.disabled = state.status === 'sharing';
    qs('#search-preview-key').textContent = detail.repository + ' #' + detail.number;
    qs('#search-preview-title').textContent = detail.title || 'Untitled work item';
    qs('#search-preview-meta').textContent =
      (detail.kind === 'pull' ? 'Pull request' : 'Issue') + ' · ' + (detail.state || 'unknown') +
      (detail.author ? ' · by ' + detail.author : '') +
      (detail.labels?.length ? ' · ' + detail.labels.join(', ') : '') +
      (detail.assignees?.length ? ' · assigned to ' + detail.assignees.join(', ') : '');
    qs('#search-preview-body').innerHTML = renderMarkdown(detail.body || 'No description provided.');
    renderSearchConversation(state.conversation);
    renderSearchPreviewReply(state, detail, searchPreview, document);
    qs('#open-search-result-gitea').href = safeSearchUrl(detail.url) || '#';
    claimButton.hidden = !(detail.claimable || detail.assigned_to_me);
    claimButton.textContent = detail.assigned_to_me ? 'Open in My Work' : 'Assign to me';
    claimButton.disabled = state.status === 'claiming';
    deferButton.hidden = !(detail.kind === 'issue' && detail.state === 'open' &&
      (detail.claimable || detail.assigned_to_me));
    deferButton.textContent = detail.assigned_to_me ? 'Defer' : 'Assign & defer';
    deferButton.disabled = state.status === 'claiming' || searchDefer?.pending();
    queueButton.hidden = !(detail.kind === 'issue' && detail.state === 'open' &&
      (detail.claimable || detail.assigned_to_me));
    queueButton.textContent = detail.assigned_to_me ? 'Add to Today' : 'Assign & add to Today';
    startButton.hidden = !(detail.reviewable || (detail.kind === 'issue' &&
      (detail.reopenable || (detail.state === 'open' && (detail.claimable || detail.assigned_to_me)))));
    startButton.textContent = detail.reviewable ? 'Review now' : detail.reopenable ? 'Reopen & resume' :
      (detail.assigned_to_me ? 'Start in Today' : 'Assign & start');
    startButton.disabled = state.status === 'claiming' || state.status === 'reopening';
    const shareStatus = {
      sharing:'Opening share options…', shared:'Search result shared.', copied:'Search result link copied.',
      'share-canceled':'Share canceled.', 'share-error':'Could not share this result. Try again.',
    };
    if (shareStatus[state.status]) status.textContent = shareStatus[state.status];
    else if (state.status === 'reopening') status.textContent = 'Reopening…';
    else if (state.status === 'claiming') status.textContent = 'Assigning this issue to you…';
    else if (state.status === 'claimed') status.textContent = 'Assigned. Opening My Work…';
    else if (detail.claimable) status.textContent = 'Open and unassigned.';
    else if (detail.assigned_to_me) status.textContent = 'Already in My Work.';
    else if (detail.reopenable) status.textContent = 'Closed—reopen to resume.';
    else status.textContent = 'Ready.';
  }
  const searchPreview = createSearchPreview({
    fetchJson: item => fetchReviewJson(searchPreviewPath(item), { headers:{ Accept:'application/json' } }),
    fetchConversation:(item,page)=>fetchReviewJson(searchPreviewConversationPath(item,page),{
      headers:{Accept:'application/json'},
    }),
    mutate: (detail, action) => fetchReviewJson(
      'api/v1/repos/' + detail.repository.split('/').map(encodeURIComponent).join('/') +
      '/issues/' + encodeURIComponent(detail.number) + '/' + action,
      { method:'PATCH', headers:{ Accept:'application/json' } }
    ),
    ...searchPreviewReplyOptions(fetchReviewJson, localStorage, globalThis.crypto),
    queueReply:async (item,body,operationId) => {
      searchReplyAttachmentTarget = item;
      const serialized = await searchReplyAttachmentController.serialize();
      const attachments = (Array.isArray(serialized) ? serialized : [serialized]).filter(Boolean);
      const admitted = await authoredOutbox.enqueueDurably({
        kind:'search-reply',targetKind:item.kind,repository:item.repository,number:item.number,
        body,operationId,...(attachments.length ? {attachments} : {}),
      });
      renderOutbox();
      return { id:admitted.item.id, queued:true };
    },
    prepareReply:(item,body) => {
      searchReplyAttachmentTarget = item;
      return searchReplyAttachmentController.prepareComment(item, body);
    },
    afterReply:item => {
      if (!searchReplyDraftStore) return null;
      return searchReplyDraftStore.remove(item);
    },
    hasAttachments:() => Boolean(searchReplyAttachmentController.state()),
    clearAttachments:() => {
      searchReplyAttachmentTarget = null;
      searchReplyAttachmentController.clear();
    },
    share: url => createWorkRoute.share(url, navigator, navigator.clipboard),
    session:[()=>commandSearchState, commandSearch, item=>taskOverlayHistory.update({preview:item})],
    onState: renderSearchPreview,
  });
  searchBatchPlanning = mountSearchBatchPlanning(
    document, createBatchFindWork, todayWork, ()=>planningOwnerLogin, fetchReviewJson,
    searchPreviewPath, queueToday, todaySync, acceptClaimedIssue, i=>commandItems[i]?.result,
    ()=>renderCommands(qs('#cmd-input').value), escapeHtml, escAttr, laterWork, laterPicker
  );
  searchDefer = createSearchDefer({
    claim: detail => searchPreview.claim(detail),
    accept: confirmed => acceptClaimedIssue(confirmed),
    defer: (item, until) => laterWork.defer(item, until),
    refresh: refreshMyWorkView,
    announce: message => {
      qs('#search-preview-status').textContent = message;
      qs('#cmd-search-action-status').textContent = message;
      qs('#my-work-action-status').textContent = message;
    },
    formatTime: fmt,
  });
  const canonicalSearchPreviewUrl = () => searchPreviewUrl(
    taskOverlayHistory.currentState(), currentSearchScope(), window.location
  );
  function createSearchStart(claim) {
    return createAssignAndStart({
      available: createAndStart.available,
      claim,
      start: confirmed => {
        const item = acceptClaimedIssue(confirmed);
        taskOverlayHistory.leave();
        refreshMyWorkView();
        return createAndStart.complete(item);
      },
      queue: confirmed => queueToday(acceptClaimedIssue(confirmed)),
      recover: confirmed => {
        const item = acceptClaimedIssue(confirmed);
        taskOverlayHistory.leave();
        refreshMyWorkView();
        openRoutedWork(item, qs('#open-palette'));
      },
      announce: message => {
        qs('#search-preview-status').textContent = message;
        qs('#cmd-search-action-status').textContent = message;
        qs('#my-work-action-status').textContent = message;
      },
    });
  }
  const searchAssignAndStart = createSearchStart(detail => searchPreview.claim(detail));
  const searchReopenAndStart = createSearchStart(detail => searchPreview.reopen(detail));
  const mobileSearchViewport = createMobileSearchViewport({
    palette: qs('#cmd-palette'),
    results: qs('#cmd-results'),
    viewport: window.visualViewport,
    mediaQuery: window.matchMedia('(max-width: 600px)'),
    schedule: callback => requestAnimationFrame(callback),
  });
  function closeSearchPreview(navigate = true) {
    if (navigate && taskOverlayHistory.current() === 'search-preview') {
      taskOverlayHistory.close();
      return;
    }
    searchPreview.close();
    qs('#cmd-palette').classList.add('open');
    qs('#cmd-input').setAttribute('aria-expanded', 'true');
    renderCommands(qs('#cmd-input').value);
    qs('#cmd-input').focus();
  }
  const next = searchPreview.next;
  async function openPreviewWorkInMyWork(detail) {
    await load();
    const item = lastMyWork.find(candidate =>
      candidate.kind === detail.kind && candidate.key === detail.repository + '#' + detail.number
    );
    if (!item) return false;
    taskOverlayHistory.leave();
    openRoutedWork(item, qs('#find-work'));
    return true;
  }
  function runCommandItem(item) {
    if (item.command) {
      taskOverlayHistory.leave();
      item.command.run();
      qs('#cmd-input').value = '';
    } else {
      mobileSearchViewport.rememberScroll();
      searchPreviewReturnKind = 'search';
      searchPreview.open(item.result).catch(() => {});
      taskOverlayHistory.open('search-preview', {
        query:qs('#cmd-input').value, scope:currentSearchScope(), preview:item.result,
      });
    }
    qs('#cmd-palette').classList.remove('open');
    qs('#cmd-input').setAttribute('aria-expanded', 'false');
  }
  function renderCommands(filter) {
    const el = qs('#cmd-results');
    const loadMore = qs('#cmd-load-more');
    const selecting = searchBatchPlanning?.plan.snapshot().active === true;
    const local = selecting ? [] : filterCommands(commands, filter).map(command => ({ command }));
    const remote = commandSearchState.query === String(filter || '').trim()
      ? commandSearchState.items.map(result => ({ result })) : [];
    commandItems = local.concat(remote);
    if (commandSelection >= commandItems.length) commandSelection = -1;
    let html = local.length ? '<div class="cmd-group">Commands</div>' : '';
    html += local.map((item, idx) => '<div class="cmd-item' + (idx === commandSelection ? ' selected' : '') + '" role="option" aria-selected="' + (idx === commandSelection) + '" data-idx="' + idx + '"><span>' + escapeHtml(item.command.name) + '</span><span class="cmd-meta">Command</span></div>').join('');
    if (remote.length) html += '<div class="cmd-group">Issues and pull requests</div>';
    html += remote.map((item, remoteIdx) => {
      const idx = local.length + remoteIdx;
      const result = item.result;
      if (selecting) return searchBatchPlanning.resultHtml(result, idx);
      return '<div class="cmd-item' + (idx === commandSelection ? ' selected' : '') + '" role="option" aria-selected="' + (idx === commandSelection) + '" data-idx="' + idx + '"><span>' + escapeHtml(result.title) + '</span><span class="cmd-meta">' + escapeHtml(result.repository) + ' #' + escapeHtml(result.number) + ' · ' + escapeHtml(result.kind === 'pull' ? 'Pull request' : 'Issue') + ' · ' + escapeHtml(result.state) + '</span></div>';
    }).join('');
    if (commandSearchState.status === 'loading') html += '<div class="cmd-status">Searching accessible work…</div>';
    else if (commandSearchState.status === 'error') html += '<div class="cmd-status">Search unavailable. Keep typing or retry.</div>';
    else if (commandSearchState.partial) html += '<div class="cmd-status">Some results are temporarily unavailable.</div>';
    else if (String(filter || '').trim().length >= 2 && !remote.length) html += '<div class="cmd-status">No matching issues or pull requests.</div>';
    el.innerHTML = html;
    loadMore.hidden = !commandSearchState.more;
    loadMore.textContent = commandSearchState.partial ? 'Retry missing results' : 'More results';
    el.querySelectorAll('.cmd-item').forEach((item) => {
      item.addEventListener('click', () => runCommandItem(commandItems[Number(item.dataset.idx)]));
    });

  }
  function openCommandPalette(navigate = true) {
    if (navigate) {
      taskOverlayHistory.open('search', { scope:currentSearchScope() });
      return;
    }
    qs('#cmd-palette').classList.add('open');
    mobileSearchViewport.open();
    mobileSearchViewport.restoreScroll();
    qs('#cmd-input').setAttribute('aria-expanded', 'true');
    qs('#cmd-input').focus();
    commandSelection = -1;
    renderCommands(qs('#cmd-input').value);
  }
  const taskOverlayHistory = createTaskOverlayHistory({
    history: window.history,
    eventTarget: window,
    onChange(kind, previous, detail) {
      if (previous === 'new' && kind !== 'new') {
        if (!suppressCreateDraftOnHistoryClose) saveIssueCaptureDraft();
        suppressCreateDraftOnHistoryClose = false;
        closeCreateIssueSheet(false);
      }
      if (previous === 'find' && kind !== 'find') closeFindWorkSheet(false);
      if (previous === 'search-preview' && kind !== 'search-preview') {
        if (kind === 'search') closeSearchPreview(false);
        else {
          searchPreview.close();
          mobileSearchViewport.close();
        }
        searchPreviewReturnKind = null;
      }
      if (previous === 'search' && kind !== 'search' && kind !== 'search-preview') {
        qs('#cmd-palette').classList.remove('open');
        qs('#cmd-input').setAttribute('aria-expanded', 'false');
        mobileSearchViewport.close();
        qs('#open-palette').focus();
      }
      if (previous === 'plan-today-preview' && kind !== 'plan-today-preview') {
        if (addPlanPreviewOnReturn && addPlanPreviewOverride) planTodayPreview.close({ add:true, override:true });
        else if (addPlanPreviewOnReturn) planTodayPreview.close({ add:true });
        else planTodayPreview.close();
        addPlanPreviewOnReturn = false;
        addPlanPreviewOverride = false;
      }
      if (previous === 'plan-today' && kind !== 'plan-today' && kind !== 'plan-today-preview') closePlanToday(false);
      if (previous === 'today-readiness' && kind !== 'today-readiness') {
        if (kind === 'search-preview') suspendTodayReadiness();
        else closeTodayReadiness(false);
      }
      if (kind === 'new' && previous !== 'new') openCreateIssueSheet(false);
      if (kind === 'find' && previous !== 'find') openFindWorkSheet(false);
      if (kind === 'search' && previous !== 'search-preview') {
        if (detail?.scope) applySearchScope(detail.scope);
        if (detail?.query !== undefined) {
          qs('#cmd-input').value = detail.query;
          commandSearch.setQuery(detail.query);
        }
        openCommandPalette(false);
      }
      if (kind === 'search-preview' && detail?.preview && previous !== 'search') {
        if (detail?.scope) applySearchScope(detail.scope);
        if (detail?.query !== undefined) qs('#cmd-input').value = detail.query;
        searchPreviewReturnKind = 'search';
        searchPreview.open(detail.preview).catch(() => taskOverlayHistory.close());
      }
      if (kind === 'plan-today' && previous !== 'plan-today' && previous !== 'plan-today-preview') openPlanToday(planTodayTrigger, false);
      if (kind === 'today-readiness' && previous !== 'today-readiness') renderTodayReadiness(todayReadiness.snapshot());
    },
  });
  taskOverlayHistory.start();
  createSavedSearches.mount(
    document, fetch, commandSearch, applySearchScope, taskOverlayHistory
  ).load();
  qs('#open-palette').addEventListener('click', openCommandPalette);
  qs('#close-command-palette').addEventListener('click', () => taskOverlayHistory.close());
  qs('#cmd-load-more').addEventListener('click', () => commandSearch.loadMore());

  function changeSearchScope() {
    const scope = currentSearchScope();
    commandSelection = -1;
    taskOverlayHistory.update({ scope });
    commandSearch.setScope(scope);
  }
  qs('#cmd-search-kind').addEventListener('change', changeSearchScope);
  qs('#cmd-search-state').addEventListener('change', changeSearchScope);
  let repositoryLookupController = null;
  let repositoryLookupTimer = null;
  async function suggestSearchRepositories() {
    const input = qs('#cmd-search-repository');
    const query = input.value.trim();
    const status = qs('#cmd-repository-status');
    if (repositoryLookupTimer !== null) clearTimeout(repositoryLookupTimer);
    if (repositoryLookupController) repositoryLookupController.abort();
    repositoryLookupController = null;
    if (!query) {
      qs('#cmd-search-repositories').innerHTML = '';
      status.textContent = 'Searching all accessible repositories.';
      changeSearchScope();
      return;
    }
    if (/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(query)) changeSearchScope();
    if (query.length < 2) {
      status.textContent = 'Enter at least 2 characters to find a repository.';
      return;
    }
    status.textContent = 'Finding accessible repositories…';
    repositoryLookupTimer = setTimeout(async () => {
      const controller = new AbortController();
      repositoryLookupController = controller;
      try {
        const response = await fetch('api/v1/repositories/search?q=' + encodeURIComponent(query) + '&limit=20', {
          headers:{ Accept:'application/json' }, signal:controller.signal,
        });
        const payload = await response.json().catch(() => ({}));
        if (!response.ok) throw new Error(payload.error || 'Repository lookup unavailable.');
        if (repositoryLookupController !== controller || input.value.trim() !== query) return;
        const items = Array.isArray(payload.items) ? payload.items : [];
        qs('#cmd-search-repositories').innerHTML = items.map(item =>
          '<option value="' + escapeHtml(item.full_name) + '"></option>'
        ).join('');
        status.textContent = items.length ? 'Choose an accessible repository.' : 'No accessible repositories found.';
      } catch (error) {
        if (error?.name !== 'AbortError') status.textContent = 'Repository lookup unavailable; global Search still works.';
      } finally {
        if (repositoryLookupController === controller) repositoryLookupController = null;
      }
    }, 200);
  }
  qs('#cmd-search-repository').addEventListener('input', suggestSearchRepositories);
  qs('#cmd-search-repository').addEventListener('change', changeSearchScope);
  qs('#cmd-search-repository').addEventListener('search', suggestSearchRepositories);
  qs('#cmd-input').addEventListener('input', (e) => {
    commandSelection = -1;
    taskOverlayHistory.update({ query:e.target.value });
    renderCommands(e.target.value);
    commandSearch.setQuery(e.target.value);
  });
  qs('#cmd-input').addEventListener('keydown', event => {
    if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
      event.preventDefault();
      commandSelection = filterCommands.nextSelection(commandSelection, event.key, commandItems.length);
      renderCommands(event.currentTarget.value);
      const selected = qs('#cmd-results .selected');
      if (selected) selected.scrollIntoView({ block:'nearest' });
    } else if (event.key === 'Enter' && commandSelection >= 0) {
      event.preventDefault();
      runCommandItem(commandItems[commandSelection]);
    }
  });
  document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape' && qs('#cmd-palette').classList.contains('open')) {
      e.preventDefault();
      taskOverlayHistory.close();
      return;
    }
    if (e.key === 'Escape' && qs('#search-preview').classList.contains('open')) {
      e.preventDefault();
      closeSearchPreview();
      return;
    }
    if (e.key === 'Escape' && findingWork) {
      e.preventDefault();
      closeFindWorkSheet();
      return;
    }
    if (e.key === 'Escape' && creatingIssue) {
      e.preventDefault();
      saveIssueCaptureDraft();
      closeCreateIssueSheet();
      return;
    }
    if (e.key === 'Escape' && selectedIssue) {
      e.preventDefault();
      if (!qs('#issue-edit-form').hidden) {
        history.back();
        return;
      }
      closeIssueSheet();
      return;
    }
    if (e.key === 'Escape' && selectedPull) {
      e.preventDefault();
      closePullSheet();
      return;
    }
    if (e.key === 'Escape' && selectedReview) {
      e.preventDefault();
      closeReviewSheet();
      return;
    }
    if (e.key === 'Escape' && selectedUpdate) {
      e.preventDefault();
      closeUpdateSheet();
      return;
    }
    if ((e.metaKey||e.ctrlKey) && e.key==='k') {
      e.preventDefault();
      if (qs('#cmd-palette').classList.contains('open')) {
        taskOverlayHistory.close();
      } else openCommandPalette();
    }
  });
  qs('#close-search-preview').addEventListener('click', closeSearchPreview);
  qs('#share-search-result').addEventListener('click', () => {
    searchPreview.share(canonicalSearchPreviewUrl()).catch(() => {});
  });
  document.querySelectorAll('.share-work-route').forEach(button => {
    button.addEventListener('click', async () => {
      const status = qs('#work-route-share-status');
      try {
        const result = await createWorkRoute.share(window.location.href, navigator, navigator.clipboard);
        status.textContent = result === 'shared' ? 'Work link shared.' : 'Work link copied.';
      } catch (error) {
        status.textContent = error?.name === 'AbortError' ? 'Share canceled.' : 'Could not share this work link.';
      }
    });
  });
  qs('#claim-search-result').addEventListener('click', async () => {
    if (!searchPreviewDetail || (!searchPreviewDetail.claimable && !searchPreviewDetail.assigned_to_me)) return;
    try {
      const claimed = searchPreviewDetail;
      if (claimed.claimable) await searchPreview.claim(claimed);
      const opened = await openPreviewWorkInMyWork(claimed);
      if (!opened) {
        qs('#search-preview-status').textContent = 'Refresh My Work to open this item.';
      }
    } catch (error) {
      qs('#search-preview-status').textContent = error.message + ' Retry assignment.';
    }
  });
  qs('#defer-search-result').addEventListener('click', event => {
    const detail = searchPreviewDetail;
    if (!detail || detail.kind !== 'issue' || detail.state !== 'open' ||
        (!detail.claimable && !detail.assigned_to_me) || searchDefer.pending()) return;
    laterPicker.open(detail, event.currentTarget, 'search');
  });
  qs('#queue-search-result').addEventListener('click', async () => {
    const detail = searchPreviewDetail;
    if (!detail || detail.kind !== 'issue' || detail.state !== 'open' ||
        (!detail.claimable && !detail.assigned_to_me)) return;
    try {
      if (todayWork.contains(detail)) {
        qs('#cmd-search-action-status').textContent = 'Already in Today.';
        await next();
        return;
      }
      const outcome = await searchAssignAndStart.run(detail, {
        alreadyOwned: detail.assigned_to_me,
        destination: 'queue',
      });
      if (outcome === 'queued') await next();
    } catch (error) {
      qs('#search-preview-status').textContent = error.message + ' Retry.';
    }
  });
  qs('#start-search-result').addEventListener('click', async () => {
    const detail = searchPreviewDetail;
    if (detail?.reviewable) {
      taskOverlayHistory.leave();
      detail.kind = 'review';
      return openRoutedWork(detail, null, { replace:true });
    }
    if (!detail || detail.kind !== 'issue') return;
    try {
      if (detail.reopenable) await searchReopenAndStart.run(detail);
      else if (detail.state === 'open' && (detail.claimable || detail.assigned_to_me)) {
        await searchAssignAndStart.run(detail, { alreadyOwned: detail.assigned_to_me });
      }
    } catch (error) {
      qs('#search-preview-status').textContent = error.message + ' Retry.';
    }
  });
  qs('#close-whiteboard').addEventListener('click', () => closeModal('whiteboard-modal'));
  qs('#find-work').addEventListener('click', openFindWorkSheet);

  qs('#fill-find-work-today').addEventListener('click', () => {
    const remainingSlots = todayWork.limit - todayWork.read().length;
    const outcome = findWorkController.fillSelection(remainingSlots);
    qs('#find-work-status').textContent = remainingSlots < 1 ? 'Today is full.' :
      outcome.selected ? outcome.selected + ' ranked work selected.' : 'No matching work.';
    if (outcome.selected) findWorkNavigation.go('review');
  });
  qs('#find-work-search-form').addEventListener('submit', event => event.preventDefault());
  qs('#find-work-search').addEventListener('input', event => {
    const value = event.currentTarget.value;
    qs('#clear-find-work-search').hidden = !value;
    clearTimeout(findWorkSearchTimer);
    findWorkSearchTimer = setTimeout(async () => {
      qs('#find-work-status').textContent = value.trim() ?
        'Searching available issues…' : 'Loading available issues…';
      try {
        await findWorkController.search(value);
        updateFindWorkMatchStatus();
        qs('#find-work-status').textContent = availablePagination.total ?
          'Available work loaded.' : 'No matching unassigned issues.';
      } catch (error) {
        qs('#find-work-status').textContent = error.message + ' Retry search.';
      }
    }, 250);
  });
  qs('#clear-find-work-search').addEventListener('click', () => {
    const input = qs('#find-work-search');
    input.value = '';
    input.dispatchEvent(new Event('input', { bubbles:true }));
    input.focus();
  });

  qs('#confirm-find-work-estimates').addEventListener('click', async event => {
    const button = event.currentTarget;
    button.disabled = true;
    const outcome = await batchFindWork.run(findWorkController.selectedItems(), findWorkEstimateValues());
    button.disabled = false;
    if (outcome.status === 'estimates-required') {
      const first = outcome.invalid[0];
      document.querySelector('[data-find-work-estimate="' + CSS.escape(first) + '"]')?.focus();
      return;
    }
    if (outcome.status !== 'complete') return;
    const assignedOnly = outcome.failed.filter(item => item.assigned).length;
    const unavailable = outcome.failed.length - assignedOnly;
    qs('#find-work-status').textContent = outcome.queued.length + ' queued' +
      (unavailable ? ' · ' + unavailable + ' unavailable' : '') +
      (assignedOnly ? ' · ' + assignedOnly + ' assigned but not queued' : '') + '.';
    if (!outcome.failed.length) {
      findWorkNavigation.complete();
      findWorkController.cancelSelection();
    } else {
      renderAvailableIssues(findWorkController.items());
      findWorkNavigation.sync({ selectedCount:findWorkController.selection().count, recovery:true });
    }
    refreshMyWorkView();
  });
  qs('#load-more-available').addEventListener('click', async event => {
    event.currentTarget.disabled = true;
    qs('#find-work-status').textContent = 'Loading more available issues…';
    try {
      await findWorkController.loadMore();
      qs('#find-work-status').textContent = findWorkController.items().length + ' of ' +
        availablePagination.total + ' available issues loaded.';
    } catch (error) {
      qs('#find-work-status').textContent = error.message + ' Retry loading more.';
    } finally {
      event.currentTarget.disabled = false;
    }
  });
  qs('#create-update-follow-up').addEventListener('click', async () => {
    if (!selectedUpdate || !selectedUpdateDetail || !await ensureIssueCapture()) return;
    const source = {item: selectedUpdate, detail: selectedUpdateDetail};
    const state = issueCapture.stageFollowUp(updateFollowUp.draft(selectedUpdateDetail));
    updateFollowUp.stageSource(source.item);
    followUpSourceUpdate = source;
    closeUpdateSheet(false, false);
    await openCreateIssueSheet(false);
    if (state.status === 'conflict') {
      qs('#shared-content-conflict').hidden = false;
      qs('#create-issue-status').textContent = 'Choose which draft to continue.';
      qs('#resume-issue-draft').focus();
    } else {
      qs('#create-issue-status').textContent = 'Follow-up context added. Review, save to Drafts, or create it.';
    }
    qs('#create-follow-up-next').hidden = false;
  });
  dFS.bind();
  qs('#file-new-issue').addEventListener('click', () => {
    if (!qs('#create-issue-title').value.trim()) {
      qs('#create-issue-capture-status').textContent = 'Add a title before filing.';
      qs('#create-issue-title').focus();
      return;
    }
    saveIssueCaptureDraft();
    setIssueFilingMode(true);
    qs('#create-issue-capture-status').textContent = '';
    qs('#create-issue-repository-search').focus();
  });
  qs('#save-unfiled-issue').addEventListener('click', async () => {
    try {
      const evidence = await createIssueAttachmentController.serialize();
      const captureDraft = currentIssueCaptureDraft();
      Object.assign(captureDraft, Array.isArray(evidence) ? {attachments:evidence} : {attachment:evidence});
      if (showDraftCapacityDialog(unfiledCaptures, qs)) return;
      const savedCapture = await unfiledCaptures.save(captureDraft);
      if (rUC) {
        await unfiledCaptures.completeResume(rUC);
        rUC = '';
      }
      const capture = timerView.finishCapture();
      issueCapture.clearDraft();
      qs('#create-issue-title').value = '';
      qs('#create-issue-body').value = '';
      createIssueAttachmentController.clear();
      closeCreateIssueSheet(true, false);
      if (!capture) {
        qs('[data-work-filter="draft"]').click();
        mobileTaskDock.select('queues');
      }
      refreshMyWorkView();
      const savedCard = qs('[data-capture-id="' + CSS.escape(savedCapture.id) + '"]');
      if (!capture) requestAnimationFrame(() => {
        savedCard?.scrollIntoView({block:'nearest'});
        savedCard?.focus({preventScroll:true});
      });
      qs('#my-work-action-status').textContent = unfiledSavedMessage(captureDraft);
    } catch (error) {
      qs('#create-issue-capture-status').textContent = error.message;
      qs('#create-issue-title').focus();
    }
  });
  bindDraftCapacityDialog({
    qs, saveIssueCaptureDraft, closeCreateIssueSheet, mobileTaskDock, refreshMyWorkView,
    unfiledCaptures, currentIssueCaptureDraft, createIssueAttachmentController, issueCapture,
  });
  qs('#use-shared-content').addEventListener('click', () => {
    if (issueCapture.pendingFollowUp()) issueCapture.acceptFollowUp();
    else issueCapture.acceptSharedContent();
    qs('#shared-content-conflict').hidden = true;
    sharedLaunchState = null;
    clearSharedLaunchUrl();
    openCreateIssueSheet();
    qs('#create-issue-status').textContent = 'Shared content added. Choose a repository and finish planning.';
  });
  qs('#resume-issue-draft').addEventListener('click', () => {
    issueCapture.discardSharedContent();
    issueCapture.discardFollowUp();
    updateFollowUp.discardSource();
    qs('#shared-content-conflict').hidden = true;
    sharedLaunchState = null;
    clearSharedLaunchUrl();
    qs('#create-issue-status').textContent = 'Existing draft restored.';
    qs('#create-issue-title').focus();
  });
  qs('#cancel-new-issue').addEventListener('click', () => {
    if (checklistPromotion?.cancel()) {
      closeCreateIssueSheet(true, false);
      return;
    }
    const discardEditedDraft = Boolean(editingOutboxId);
    if (editingOutboxId) {
      issueCapture.clearDraft();
      editingOutboxId = null;
    } else saveIssueCaptureDraft();
    closeCreateIssueSheet(true, !discardEditedDraft);
  });
  ['#create-issue-title', '#create-issue-body', '#create-issue-due-date'].forEach(selector =>
    qs(selector).addEventListener('input', () => {
      saveIssueCaptureDraft();
      if (selector === '#create-issue-title') scheduleIssueDuplicateCheck();
    })
  );
  qs('#create-issue-repository').addEventListener('change', event => {
    issueTemplatePicker.changeRepository(currentIssueCaptureDraft());
    issueOwnerPicker.reset(event.target.value);
    loadIssueFilingMetadata(event.target.value);
    qs('#create-issue-repository-search').value = event.target.value;
    saveIssueCaptureDraft();
    scheduleIssueDuplicateCheck();
    updateIssueCreateActions();
  });
  qs('#create-issue-repository-search').addEventListener('input', event => {
    clearTimeout(issueRepositorySearchTimer);
    const query = event.target.value.trim();
    const results = qs('#create-issue-repository-results');
    const status = qs('#create-issue-repository-status');
    if (query.length < 2) {
      issueCapture.searchRepositories(query);
      results.hidden = true;
      status.textContent = query ? 'Enter at least 2 characters to search.' : 'Search or browse to choose a repository.';
      return;
    }
    status.textContent = 'Searching accessible repositories…';
    issueRepositorySearchTimer = setTimeout(async () => {
      const state = await issueCapture.searchRepositories(query);
      if (state.status === 'stale') return;
      if (state.status === 'failed') {
        results.hidden = true;
        status.textContent = 'Repository search failed. Your draft is safe; retry or browse below.';
        return;
      }
      renderIssueRepositoryResults(state.items);
      status.textContent = state.items.length ? 'Choose a matching repository.' : 'No accessible repositories match.';
    }, 250);
  });
  qs('#create-issue-blocker-search').addEventListener('input', event => {
    clearTimeout(captureBlockerSearchTimer);
    const query = event.target.value.trim();
    const results = qs('#create-issue-blocker-results');
    const status = qs('#create-issue-blocker-status');
    if (query.length < 2) {
      issueCapture.searchBlockers(query);
      results.hidden = true;
      status.textContent = issueCaptureBlockers.length ? issueCaptureBlockers.length + ' blocker(s) selected.' :
        (query ? 'Enter at least 2 characters to search.' : 'No blockers selected.');
      return;
    }
    if (issueCaptureBlockers.length >= 5) {
      results.hidden = true;
      status.textContent = 'Five blockers selected. Remove one to choose another.';
      return;
    }
    status.textContent = 'Searching open issues…';
    captureBlockerSearchTimer = setTimeout(async () => {
      const state = await issueCapture.searchBlockers(query);
      if (state.status === 'stale') return;
      if (state.status === 'failed') {
        results.hidden = true;
        status.textContent = 'Blocker search failed. Your draft is safe; retry.';
        return;
      }
      renderIssueCaptureBlockerResults(state.items);
      status.textContent = state.items.length ? 'Choose an issue that must finish first.' : 'No open issues match.';
    }, 250);
  });
  qs('#load-more-issue-repositories').addEventListener('click', async event => {
    const button = event.currentTarget;
    const status = qs('#create-issue-repository-status');
    saveIssueCaptureDraft();
    button.disabled = true;
    status.textContent = 'Loading more repositories…';
    try {
      const payload = await issueCapture.loadRepositoryPage(nextIssueRepositoryPage);
      appendIssueRepositories(payload.items);
      nextIssueRepositoryPage = payload.page + 1;
      moreIssueRepositoriesAvailable = payload.has_more;
      button.hidden = !moreIssueRepositoriesAvailable;
      status.textContent = payload.items.length ?
        'More repositories are available in the selector.' : 'All accessible repositories are loaded.';
    } catch (_error) {
      status.textContent = 'Repositories could not be loaded. Your draft is safe; retry.';
    } finally {
      button.disabled = false;
    }
  });
  qs('#create-issue-label-list').addEventListener('change', saveIssueCaptureDraft);
  qs('#create-issue-milestone').addEventListener('change', saveIssueCaptureDraft);
  qs('#create-issue-anyway').addEventListener('click', () => {
    const captureDraft = currentIssueCaptureDraft();
    issueCapture.acknowledgeDuplicates(captureDraft);
    qs('#create-issue-anyway').hidden = true;
    qs('#create-issue-form').requestSubmit();
  });
  async function admitReviewedIssue(review) {
    const durableDraft = review.draft;
    const promotion = checklistPromotion?.deliveryContext();
    const deliveryDraft = {
      ...durableDraft, relatedDraft:issueCapture.buildRelatedDraft(durableDraft),
    };
    if (promotion) deliveryDraft.relatedDraft.checklistPromotion = promotion;
    const followUpNextRequested = review.intent === 'follow-up-and-next';
    createAndStartRequested = review.intent === 'create-and-start';
    if (createAndStartRequested && !createAndStart.available()) {
      throw new Error('Today is full now. Go back and remove an item before creating and starting another.');
    }
    const button = qs('#submit-new-issue');
    const startButton = qs('#create-and-start-issue');
    const followUpButton = qs('#create-follow-up-next');
    button.disabled = true;
    startButton.disabled = true;
    followUpButton.disabled = true;
    qs('#create-issue-status').textContent = createAndStartRequested ?
      'Creating issue and adding it to Today…' : 'Saving for background delivery…';
    try {
      const admission = followUpNextRequested ? (await updateFollowUp.complete({
        admit: () => editingOutboxId ? issueOutbox.updateDurably(editingOutboxId, deliveryDraft) :
          issueOutbox.enqueueDurably(deliveryDraft),
        queueRead: notificationId => notificationReadOutbox.enqueueDurably(notificationId),
        advance: source => notificationReader.acceptReadAndNext(lastMyWork, source),
      })).admission : (editingOutboxId ? await issueOutbox.updateDurably(editingOutboxId, deliveryDraft) :
        await issueOutbox.enqueueDurably(deliveryDraft));
      const queued = admission.item;
      pendingIssueFilingIntent = 'create-and-assign';
      const fS = dFS.current();
      if (rUC && ((!durableDraft.attachment && !durableDraft.attachments) || admission.background)) {
        await unfiledCaptures.completeResume(rUC);
        rUC = '';
      }
      if (fS && !rUC && await dFS.advance(fS.id)) {
        refreshMyWorkView();
        return;
      }
      if (!admission.background) {
        editingOutboxId = queued.id;
        refreshMyWorkView();
        qs('#create-issue-status').textContent = 'Saved for next launch; background delivery unavailable.';
        return;
      }
      editingOutboxId = null;
      followUpSourceUpdate = null;
      if (!followUpNextRequested) updateFollowUp.discardSource();
      issueCapture.clearDraft();
      createIssueAttachmentController.clear();
      suppressCreateDraftOnHistoryClose = true;
      taskOverlayHistory.leave();
      refreshMyWorkView();
      qs('#my-work-action-status').textContent = 'Queued for sync.';
      if (navigator.onLine) applyOutboxResult(
        await issueOutbox.retry(queued.id, activeFlushLogin), true, createAndStartRequested
      );
      createAndStartRequested = false;
    } catch (error) {
      qs('#create-issue-status').textContent = error.message + ' Your draft is safe; retry.';
      throw error;
    } finally {
      button.disabled = false;
      startButton.disabled = !createAndStart.available();
      followUpButton.disabled = false;
    }
  }

  qs('#create-issue-form').addEventListener('submit', async event => {
    event.preventDefault();
    if (event.submitter) pendingIssueFilingIntent =
      event.submitter.id === 'create-and-start-issue' ? 'create-and-start' :
        (event.submitter.id === 'create-follow-up-next' ? 'follow-up-and-next' : 'create-and-assign');
    const intent = pendingIssueFilingIntent;
    createAndStartRequested = intent === 'create-and-start';
    const startCapacity = createAndStartRequested
      ? createAndStart.capacity(qs('#create-issue-estimate').value) : null;
    const captureDraft = currentIssueCaptureDraft();
    if (!captureDraft.repository || !captureDraft.title) {
      qs('#create-issue-status').textContent = 'Choose a repository and add a title.';
      qs('#create-issue-title').focus();
      return;
    }
    if (issueCapture.needsDuplicateAcknowledgement(captureDraft)) {
      qs('#create-issue-status').textContent = 'Review the possible existing issues, or choose Create anyway.';
      qs('#create-issue-anyway').hidden = false;
      qs('#create-issue-anyway').focus();
      return;
    }
    if (createAndStartRequested && !createAndStart.available()) {
      qs('#create-issue-status').textContent = 'Today is full. Remove an item before creating and starting another.';
      qs('#create-and-start-issue').focus();
      return;
    }
    if (createAndStartRequested && !startCapacity.valid) {
      qs('#create-issue-status').textContent = startCapacity.reason === 'required'
        ? 'Add a work estimate before creating and starting.'
        : 'Use a whole-number estimate from 5 to 1440 minutes.';
      qs('#create-issue-estimate').focus();
      renderCreateStartCapacity();
      return;
    }
    if (createAndStartRequested && !startCapacity.fits) {
      qs('#create-issue-status').textContent = 'This would put Today ' +
        Math.abs(startCapacity.projectedMinutes) + ' minutes over capacity. Adjust the estimate or Today plan.';
      qs('#create-issue-estimate').focus();
      renderCreateStartCapacity();
      return;
    }
    qs('#create-issue-status').textContent = 'Preparing complete filing review…';
    try {
      const evidence = await createIssueAttachmentController.serialize();
      const milestoneOption = qs('#create-issue-milestone').selectedOptions?.[0];
      const durableDraft = {
        ...captureDraft,
        labels: selectedIssueLabelNames(),
        milestoneTitle: captureDraft.milestoneId ? milestoneOption?.textContent?.trim() : '',
        ...(Array.isArray(evidence) ? {attachments:evidence} : {attachment:evidence}),
        ...(rUC ? { sourceCaptureId: rUC } : {}),
        ...(createAndStartRequested ? {
          completionIntent: 'create-and-start', estimateMinutes: startCapacity.minutes,
          todayCapacity: startCapacity,
        } : {}),
      };
      filingReview.open({draft: durableDraft, intent},
        dFS.takeTrigger() || event.submitter || qs('#submit-new-issue'));
      qs('#create-issue-status').textContent = 'Review the complete payload, then confirm filing.';
    } catch (error) {
      qs('#create-issue-status').textContent = error.message + ' Your draft is safe; retry.';
      qs('#create-issue-title').focus();
    }
  });
  qs('#close-issue-sheet').addEventListener('click', closeIssueSheet);
  function runFiledClaim(destination) {
    const item = selectedIssue;
    if (!item || !selectedIssueDetail || !filedClaimEligible(item, selectedIssueDetail)) return;
    qs('#queue-filed-issue').disabled = true;
    qs('#start-filed-issue').disabled = true;
    const request = destination === 'queue' ?
      filedAssignAndStart.run(item, { destination:'queue' }) : filedAssignAndStart.run(item);
    request.catch(error => {
      if (selectedIssue !== item) return;
      qs('#issue-sheet-status').textContent = 'Claim failed; this issue is still in Filed. ' + error.message + ' Retry.';
    }).finally(() => {
      if (selectedIssue === item && filedClaimEligible(item, selectedIssueDetail)) {
        qs('#queue-filed-issue').disabled = false;
        qs('#start-filed-issue').disabled = false;
      }
    });
  }
  qs('#queue-filed-issue').addEventListener('click', () => runFiledClaim('queue'));
  qs('#start-filed-issue').addEventListener('click', () => runFiledClaim('start'));
  qs('#retry-issue-load').addEventListener('click', () => {
    if (selectedIssue) openIssueSheet(selectedIssue, issueTrigger);
  });
  issueController.bindTaskToggles({
    container:qs('#issue-sheet-body'), status:qs('#issue-sheet-status'), retry:qs('#retry-issue-load'),
    current:()=>({item:selectedIssue,detail:selectedIssueDetail,offline:selectedIssueOffline}),
    confirmed:applyIssueContent,
    restore:renderIssueBody,
  });
  const checklistStepManagement = issueController.bindTaskManagement({
    container:qs('#issue-sheet-body'), editor:qs('#checklist-step-editor'), label:qs('#checklist-step-label'),
    earlier:qs('#move-checklist-step-earlier'), later:qs('#move-checklist-step-later'),
    fileRelated:qs('#file-checklist-step-related'), onFileRelated:startChecklistPromotion,
    remove:qs('#remove-checklist-step'), cancel:qs('#cancel-checklist-step-edit'),
    status:qs('#checklist-step-edit-status'), sheetStatus:qs('#issue-sheet-status'), retry:qs('#retry-issue-load'),
    current:()=>({item:selectedIssue,detail:selectedIssueDetail,offline:selectedIssueOffline}),
    confirmed:applyIssueContent,
  });
  function closeAddChecklistStep() {
    qs('#add-checklist-step-form').hidden = true;
    qs('#add-checklist-step').value = '';
    qs('#open-add-checklist-step').focus();
  }
  qs('#open-add-checklist-step').addEventListener('click', () => {
    qs('#add-checklist-step-form').hidden = false;
    qs('#add-checklist-step-status').textContent = 'Add one required step.';
    qs('#add-checklist-step').focus();
  });
  qs('#cancel-checklist-step').addEventListener('click', closeAddChecklistStep);
  qs('#add-checklist-step-form').addEventListener('submit', async event => {
    event.preventDefault();
    const state = {item:selectedIssue, detail:selectedIssueDetail, offline:selectedIssueOffline};
    if (!state.item || !state.detail?.updated_at) return;
    const submit = qs('#save-checklist-step');
    submit.disabled = true;
    qs('#add-checklist-step-status').textContent = state.offline ? 'Queueing checklist step…' : 'Adding checklist step…';
    try {
      const result = await (selectedIssueOffline ? issueController.queueAddedTask : issueController.addTask).call(
        issueController, state.item, state.detail, qs('#add-checklist-step').value
      );
      if (selectedIssue !== state.item) return;
      applyIssueContent(state.item, state.detail, state.offline ? result.detail : result);
      closeAddChecklistStep();
      qs('#add-checklist-step-status').textContent = state.offline ?
        'Checklist step queued. Pending sync.' : 'Checklist step added.';
    } catch (error) {
      if (selectedIssue === state.item) {
        qs('#add-checklist-step-status').textContent = error.message;
        qs('#add-checklist-step').focus();
      }
    } finally {
      submit.disabled = false;
    }
  });
  qs('#complete-checklist-issue').addEventListener('click', () => {
    qs('#close-issue').click();
  });
  qs('#keep-checklist-issue-open').addEventListener('click', () => {
    dismissedChecklistBody = selectedIssueDetail?.body;
    if (selectedIssueDetail) renderChecklistCompletion(selectedIssueDetail);
    qs('#issue-sheet-body').focus();
  });
  qs('#issue-planning').addEventListener('toggle', event => {
    if (event.currentTarget.open) loadIssuePlanning();
  });
  qs('#retry-issue-planning').addEventListener('click', loadIssuePlanning);
  qs('#edit-issue-content').addEventListener('click', () => {
    if (!selectedIssue || !selectedIssueDetail?.updated_at) return;
    const draft = issueController.loadEditDraft(selectedIssue) || {
      title: selectedIssueDetail.title || '',
      body: selectedIssueDetail.body || '',
      expectedUpdatedAt: selectedIssueDetail.updated_at,
    };
    qs('#issue-edit-title').value = draft.title;
    qs('#issue-edit-body').value = draft.body;
    qs('#issue-edit-form').hidden = false;
    if (!issueEditHistoryActive) {
      history.pushState({ ...history.state, stackchainIssueEdit:true }, '', window.location.href);
      issueEditHistoryActive = true;
    }
    qs('#issue-edit-status').textContent = 'Edit the issue, then save.';
    qs('#issue-edit-title').focus();
  });
  ['#issue-edit-title', '#issue-edit-body'].forEach(selector =>
    qs(selector).addEventListener('input', () => {
      if (!selectedIssue || !selectedIssueDetail?.updated_at) return;
      issueController.saveEditDraft(selectedIssue, {
        title: qs('#issue-edit-title').value,
        body: qs('#issue-edit-body').value,
        expectedUpdatedAt: issueController.loadEditDraft(selectedIssue)?.expectedUpdatedAt || selectedIssueDetail.updated_at,
      });
    })
  );
  qs('#cancel-issue-content').addEventListener('click', () => {
    if (issueEditHistoryActive) history.back();
    else {
      qs('#issue-edit-form').hidden = true;
      qs('#edit-issue-content').focus();
    }
  });
  qs('#issue-edit-form').addEventListener('submit', async event => {
    event.preventDefault();
    if (!selectedIssue || !selectedIssueDetail?.updated_at || !lastContextSnapshot) return;
    const title = qs('#issue-edit-title').value.trim();
    const body = qs('#issue-edit-body').value.trim();
    if (!title) {
      qs('#issue-edit-status').textContent = 'Add a title before saving.';
      qs('#issue-edit-title').focus();
      return;
    }
    const editing = selectedIssue;
    const savedDraft = issueController.loadEditDraft(editing);
    const draft = {
      title,
      body,
      expectedUpdatedAt: savedDraft?.expectedUpdatedAt || selectedIssueDetail.updated_at,
    };
    const button = qs('#save-issue-content');
    button.disabled = true;
    qs('#issue-edit-status').textContent = 'Saving issue…';
    try {
      const confirmed = await issueController.updateContent(editing, draft);
      applyIssueContent(editing, selectedIssueDetail, confirmed);
      if (issueEditHistoryActive) history.back();
      else qs('#issue-edit-form').hidden = true;
      qs('#issue-sheet-status').textContent = 'Issue saved.';
      qs('#edit-issue-content').focus();
    } catch (error) {
      qs('#issue-edit-status').textContent = error.message + ' Your draft is safe; reload latest or open in Gitea.';
      qs('#retry-issue-load').hidden = false;
      qs('#issue-edit-title').focus();
    } finally {
      button.disabled = false;
    }
  });
  qs('#issue-comment').addEventListener('input', event => {
    if (selectedIssue) issueController.saveDraft(selectedIssue, event.target.value);
  });
  qs('#load-older-issue-comments').addEventListener('click', async () => {
    if (!issueConversation) return;
    const button = qs('#load-older-issue-comments');
    const panel = qs('#issue-sheet .issue-sheet-panel');
    const previousHeight = panel.scrollHeight;
    button.disabled = true;
    qs('#issue-conversation-status').textContent = 'Loading older messages…';
    try {
      if (issueController.readOnly(selectedIssue)) {
        paintIssueConversation(await issueConversation.loadOlder(), null);
      } else {
        renderIssueConversation(await issueConversation.loadOlder());
      }
      panel.scrollTop += panel.scrollHeight - previousHeight;
    } catch (error) {
      qs('#issue-conversation-status').textContent = error.message + ' Loaded messages and your draft are safe; retry.';
    } finally {
      button.disabled = false;
    }
  });
  qs('#save-issue-labels').addEventListener('click', async () => {
    if (!selectedIssue || !lastContextSnapshot) return;
    const editing = selectedIssue;
    const button = qs('#save-issue-labels');
    button.disabled = true;
    qs('#issue-label-status').textContent = 'Saving labels…';
    try {
      const confirmed = await issueController.updateLabels(selectedIssue, selectedEditIssueLabelIds());
      lastContextSnapshot = buildMyWork.replaceIssueLabels(
        lastContextSnapshot, editing.repository, editing.number, confirmed.labels
      );
      selectedIssue = { ...editing, labels: confirmed.labels };
      qs('#issue-labels').innerHTML = confirmed.labels.map(label =>
        '<span class="pill">' + escapeHtml(label) + '</span>'
      ).join(' ');
      paintMyWork(lastContextSnapshot);
      qs('#issue-label-status').textContent = 'Labels saved. My Work reprioritized.';
    } catch (error) {
      qs('#issue-label-status').textContent = error.message + ' Your selection is safe; retry.';
    } finally {
      button.disabled = false;
    }
  });

  async function saveSelectedIssueDueDate(dueDate) {
    if (!selectedIssue || !lastContextSnapshot) return;
    const editing = selectedIssue;
    const saveButton = qs('#save-issue-due-date');
    const clearButton = qs('#clear-issue-due-date');
    saveButton.disabled = true;
    clearButton.disabled = true;
    qs('#issue-due-status').textContent = dueDate ? 'Saving due date…' : 'Clearing due date…';
    try {
      const confirmed = await issueController.updateDueDate(editing, dueDate);
      lastContextSnapshot = buildMyWork.replaceIssueDueDate(
        lastContextSnapshot, editing.repository, editing.number, confirmed.due_date
      );
      selectedIssue = { ...editing, due_date: confirmed.due_date };
      selectedIssueDetail = { ...selectedIssueDetail, due_date: confirmed.due_date };
      qs('#issue-due-date').value = String(confirmed.due_date || '').slice(0, 10);
      paintMyWork(lastContextSnapshot);
      qs('#issue-due-status').textContent = confirmed.due_date ?
        'Due date saved. My Work reprioritized.' : 'Due date cleared.';
    } catch (error) {
      qs('#issue-due-status').textContent = error.message + ' Your selection is safe; retry.';
      qs('#issue-due-date').focus();
    } finally {
      saveButton.disabled = false;
      clearButton.disabled = !selectedIssueDetail?.due_date;
    }
  }

  qs('#save-issue-due-date').addEventListener('click', () => {
    const value = qs('#issue-due-date').value;
    if (!value) {
      qs('#issue-due-status').textContent = 'Choose a date or use Clear due date.';
      qs('#issue-due-date').focus();
      return;
    }
    saveSelectedIssueDueDate(value + 'T23:59:59Z');
  });
  qs('#clear-issue-due-date').addEventListener('click', () => saveSelectedIssueDueDate(null));
  qs('#save-issue-milestone').addEventListener('click', async () => {
    if (!selectedIssue || !lastContextSnapshot) return;
    const editing = selectedIssue;
    const button = qs('#save-issue-milestone');
    const raw = qs('#issue-milestone').value;
    const milestoneId = raw ? Number(raw) : null;
    button.disabled = true;
    qs('#issue-milestone').disabled = true;
    qs('#issue-milestone-status').textContent = milestoneId ? 'Saving milestone…' : 'Clearing milestone…';
    try {
      const confirmed = await issueController.updateMilestone(editing, milestoneId);
      lastContextSnapshot = buildMyWork.replaceIssueMilestone(
        lastContextSnapshot, editing.repository, editing.number, confirmed.milestone
      );
      selectedIssue = { ...editing, milestone: confirmed.milestone };
      selectedIssueDetail = { ...selectedIssueDetail, milestone: confirmed.milestone };
      paintMyWork(lastContextSnapshot);
      qs('#issue-milestone-status').textContent = confirmed.milestone ?
        'Planned for ' + confirmed.milestone.title + '. Release lane updated.' : 'Milestone cleared.';
    } catch (error) {
      qs('#issue-milestone-status').textContent = error.message + ' Your selection is safe; retry.';
      qs('#issue-milestone').focus();
    } finally {
      button.disabled = false;
      qs('#issue-milestone').disabled = false;
    }
  });
  async function queueIssueScreenshotComment(item, body, operationId, advance = false) {
    const message = {
      kind: 'issue-comment', repository: item.repository, number: item.number, body,
      operationId: operationId || globalThis.crypto?.randomUUID?.() || String(Date.now()),
      attachment: await issueAttachmentController.serialize(),
    };
    if (advance) return await issueCommentNext.admit(item, message);
    const admission = await authoredOutbox.enqueueDurably(message);
    issueController.saveDraft(item, '');
    if (selectedIssue === item) qs('#issue-comment').value = '';
    return admission;
  }

  async function queuePullScreenshotComment(item, body, operationId, advance = false, deliver = false) {
    const message = {
      kind: 'pull-comment', repository: item.repository, number: item.number, body,
      operationId: operationId || globalThis.crypto?.randomUUID?.() || String(Date.now()),
      attachment: await pullAttachmentController.serialize(),
    };
    if (advance) return await pullCommentNext.admit(item, message);
    const admission = await authoredOutbox.enqueueDurably(message);
    if (deliver) {
      const delivery = await authoredOutbox.retry(admission.item.id, activeFlushLogin);
      return { ...admission, delivered: delivery.confirmed?.[0] || null };
    }
    pullController.saveDraft(item, '');
    if (selectedPull === item) qs('#pull-comment').value = '';
    return admission;
  }

  async function submitCommentAndNext(kind) {
    const item = kind === 'issue' ? selectedIssue : selectedPull;
    if (!item || !workSession.checkpointed(item)) return;
    const textarea = qs('#' + kind + '-comment');
    const status = qs('#' + kind + '-comment-status');
    const body = textarea.value.trim();
    const attachmentController = kind === 'issue' ? issueAttachmentController : pullAttachmentController;
    const queueScreenshot = kind === 'issue' ? queueIssueScreenshotComment : queuePullScreenshotComment;
    if (!body && !attachmentController.state()) {
      status.textContent = 'Write a comment before posting.';
      textarea.focus();
      return;
    }
    const postButton = qs('#send-' + kind + '-comment');
    const nextButton = qs('#send-' + kind + '-comment-next');
    const controller = kind === 'issue' ? issueCommentNext : pullCommentNext;
    const operationId = () => localStorage.getItem('stackchain.' + kind + '-comment.v1:' +
      item.repository + '#' + item.number + ':operation');
    postButton.disabled = true;
    nextButton.disabled = true;
    attachmentController.setBusy(true);
    status.textContent = attachmentController.state() ?
      'Uploading screenshot before opening next…' : 'Posting comment and opening next…';
    try {
      let result;
      if (attachmentController.state() && (kind === 'pull' || navigator.onLine === false)) {
        result = await queueScreenshot(item, body, operationId(), true);
      } else {
        let preparedBody;
        try {
          preparedBody = kind === 'issue' ?
            await issueAttachmentController.prepareComment(item, body) :
            await pullAttachmentController.prepareComment(item, body);
        } catch (error) {
          if (!attachmentController.state() || !canQueueMessage(error)) throw error;
          result = await queueScreenshot(item, body, operationId(), true);
        }
        if (!result) result = await controller.submit(item, preparedBody, operationId);
      }
      const stillOpen = kind === 'issue' ? selectedIssue === item : selectedPull === item;
      if (!stillOpen) return;
      await conversationPhotoDrafts.complete(kind);
      if (!result.completed) status.textContent = 'Comment saved, but Today still needs completion.';
      else if (result.delivery === 'posted') status.textContent = 'Comment posted.';
      else if (result.background) status.textContent = 'Queued for sync when the connection returns.';
      else status.textContent = 'Saved for next launch; background delivery unavailable.';
    } catch (error) {
      status.textContent = error.message + ' Your draft, screenshot, and Today position are safe; retry.';
      textarea.focus();
    } finally {
      attachmentController.setBusy(false);
      postButton.disabled = false;
      nextButton.disabled = false;
    }
  }
  qs('#send-issue-comment-next').addEventListener('click', () => submitCommentAndNext('issue'));
  qs('#send-pull-comment-next').addEventListener('click', () => submitCommentAndNext('pull'));
  qs('#send-issue-comment').addEventListener('click', async () => {
    if (!selectedIssue) return;
    const body = qs('#issue-comment').value.trim();
    if (!body && !issueAttachmentController.state()) {
      qs('#issue-comment-status').textContent = 'Write a comment before posting.';
      qs('#issue-comment').focus();
      return;
    }
    const button = qs('#send-issue-comment');
    button.disabled = true;
    qs('#issue-comment-status').textContent = issueAttachmentController.state() ?
      'Uploading screenshot…' : 'Posting comment…';
    let preparedBody;
    try {
      if (issueAttachmentController.state() && navigator.onLine === false) {
        const operationId = localStorage.getItem('stackchain.issue-comment.v1:' + selectedIssue.repository + '#' + selectedIssue.number + ':operation');
        const admission = await queueIssueScreenshotComment(selectedIssue, body, operationId);
        refreshMyWorkView();
        await conversationPhotoDrafts.complete('issue');
        qs('#issue-comment-status').textContent = admission.background ?
          'Queued with screenshot for sync when the connection returns.' :
          'Saved with screenshot for next launch; background delivery unavailable.';
        button.disabled = false;
        return;
      }
      preparedBody = await issueAttachmentController.prepareComment(selectedIssue, body);
    } catch (error) {
      if (issueAttachmentController.state() && canQueueMessage(error)) {
        try {
          const operationId = localStorage.getItem('stackchain.issue-comment.v1:' + selectedIssue.repository + '#' + selectedIssue.number + ':operation');
          const admission = await queueIssueScreenshotComment(selectedIssue, body, operationId);
          refreshMyWorkView();
          await conversationPhotoDrafts.complete('issue');
          qs('#issue-comment-status').textContent = admission.background ?
            'Queued with screenshot for sync when the connection returns.' :
            'Saved with screenshot for next launch; background delivery unavailable.';
          button.disabled = false;
          return;
        } catch (admissionError) {
          error = admissionError;
        }
      }
      qs('#issue-comment-status').textContent = error.message + ' Your comment and screenshot are safe; retry.';
      qs('#issue-comment').focus();
      button.disabled = false;
      return;
    }
    try {
      const comment = await issueController.comment(selectedIssue, preparedBody);
      if (issueConversation) {
        const conversation = issueConversation.append(comment);
        if (issueController.readOnly(selectedIssue)) paintIssueConversation(conversation, null);
        else renderIssueConversation(conversation);
      }
      qs('#issue-comment').value = '';
      await conversationPhotoDrafts.complete('issue');
      qs('#issue-comment-status').textContent = 'Comment posted.';
    } catch (error) {
      if (canQueueMessage(error)) {
        const operationId = localStorage.getItem('stackchain.issue-comment.v1:' + selectedIssue.repository + '#' + selectedIssue.number + ':operation');
        qs('#issue-comment-status').textContent = 'Saving for background delivery…';
        const admission = await authoredOutbox.enqueueDurably({ kind:'issue-comment', repository:selectedIssue.repository,
          number:selectedIssue.number, body:preparedBody, operationId });
        refreshMyWorkView();
        await conversationPhotoDrafts.complete('issue');
        if (admission.background) {
          qs('#issue-comment').value = '';
          qs('#issue-comment-status').textContent = 'Queued for sync when the connection returns.';
        } else {
          qs('#issue-comment-status').textContent = 'Saved for next launch; background delivery unavailable.';
          qs('#issue-comment').focus();
        }
      } else {
        qs('#issue-comment-status').textContent = error.message + ' Your draft is safe; retry.';
        qs('#issue-comment').focus();
      }
    } finally {
      button.disabled = false;
    }
  });
  qs('#release-issue').addEventListener('click', async () => {
    if (!selectedIssue || !window.confirm('Release ' + selectedIssue.key + ' from your My Work?')) return;
    const releasing = selectedIssue;
    const continuingSession = workSession.checkpointed(releasing);
    const button = qs('#release-issue');
    button.disabled = true;
    qs('#issue-sheet-status').textContent = 'Releasing assignment…';
    try {
      const confirmed = await issueController.release(selectedIssue, lastContextSnapshot?.user?.login);
      lastContextSnapshot = buildMyWork.removeIssue(
        lastContextSnapshot, releasing.repository, releasing.number
      );
      closeIssueSheet();
      if (continuingSession) {
        const transitionResult = await completeOwnershipExitToday(releasing);
        if (transitionResult === 'opened') {
          qs('#my-work-action-status').textContent = releasing.key + ' released. Next work item opened.';
        } else if (transitionResult === 'gated') {
          qs('#my-work-action-status').textContent = releasing.key + ' released. Choose the next ready Today item.';
        } else if (transitionResult === null) {
          qs('#my-work-action-status').textContent = releasing.key + ' released, but Today still needs completion.';
        }
      } else {
        paintMyWork(lastContextSnapshot);
        qs('#my-work-action-status').textContent = releasing.key + ' released.' +
          (confirmed.available ? ' It is available in Find Work.' : ' Other assignees remain.');
      }
    } catch (error) {
      qs('#issue-sheet-status').textContent = error.message + ' The issue remains in My Work; retry.';
      button.disabled = false;
      button.focus();
    }
  });
  qs('#load-issue-handoff').addEventListener('click', async () => {
    if (!selectedIssue) return;
    const button = qs('#load-issue-handoff');
    const select = qs('#issue-handoff-recipient');
    button.disabled = true;
    qs('#issue-handoff-status').textContent = 'Loading eligible teammates…';
    try {
      const candidates = await issueController.loadHandoffCandidates(selectedIssue);
      const currentAssignees = new Set(selectedIssue.is_filed ? (selectedIssue.assignees || []) : []);
      const availableCandidates = candidates.filter(candidate => !currentAssignees.has(candidate.login));
      select.textContent = '';
      const placeholder = document.createElement('option');
      placeholder.value = '';
      placeholder.textContent = availableCandidates.length ? 'Select a teammate' : 'No eligible teammates';
      select.appendChild(placeholder);
      availableCandidates.forEach(candidate => {
        const option = document.createElement('option');
        option.value = candidate.login;
        option.textContent = candidate.name + (candidate.name === candidate.login ? '' : ' (@' + candidate.login + ')');
        select.appendChild(option);
      });
      select.disabled = !availableCandidates.length;
      qs('#confirm-issue-handoff').disabled = true;
      qs('#issue-handoff-status').textContent = availableCandidates.length ?
        'Choose who should own this issue next.' : 'No other eligible assignees were found.';
      if (availableCandidates.length) select.focus();
    } catch (error) {
      qs('#issue-handoff-status').textContent = error.message + ' Retry loading teammates.';
      button.disabled = false;
      button.focus();
    }
  });
  qs('#issue-handoff-recipient').addEventListener('change', event => {
    qs('#confirm-issue-handoff').disabled = !event.target.value;
  });
  qs('#confirm-issue-handoff').addEventListener('click', async () => {
    const recipient = qs('#issue-handoff-recipient').value;
    if (!selectedIssue || !recipient) return;
    const changingDelegate = selectedIssue.is_filed && !selectedIssue.is_completed &&
      Array.isArray(selectedIssue.assignees) && selectedIssue.assignees.length > 0;
    const previousDelegates = changingDelegate ? selectedIssue.assignees.join(', @') : '';
    const confirmation = changingDelegate ?
      'Change delegate from @' + previousDelegates + ' to @' + recipient + ' for ' + selectedIssue.key + '?' :
      'Hand off ' + selectedIssue.key + ' to @' + recipient + '?';
    if (!window.confirm(confirmation)) return;
    const handingOff = selectedIssue;
    const continuingSession = workSession.checkpointed(handingOff);
    const button = qs('#confirm-issue-handoff');
    button.disabled = true;
    qs('#issue-handoff-status').textContent = 'Confirming handoff…';
    try {
      if (changingDelegate) {
        const confirmed = await issueController.reassign(selectedIssue, recipient);
        Object.assign(handingOff, { assignees:confirmed.assignees, updated_at:confirmed.updated_at || handingOff.updated_at });
        selectedIssue = handingOff;
        if (selectedIssueDetail) selectedIssueDetail.assignees = confirmed.assignees;
        qs('#issue-assignees').textContent = 'Assigned to ' + recipient;
        qs('#issue-handoff').open = false;
        qs('#issue-handoff-status').textContent = 'Delegate changed to @' + recipient + '.';
        refreshMyWorkView({ reconcileSession:false });
        return;
      }
      await issueController.handoff(selectedIssue, recipient, lastContextSnapshot?.user?.login);
      lastContextSnapshot = buildMyWork.removeIssue(
        lastContextSnapshot, handingOff.repository, handingOff.number
      );
      closeIssueSheet();
      if (continuingSession) {
        const transitionResult = await completeOwnershipExitToday(handingOff);
        if (transitionResult === 'opened') {
          qs('#my-work-action-status').textContent = handingOff.key + ' handed off to @' + recipient + '. Next work item opened.';
        } else if (transitionResult === 'gated') {
          qs('#my-work-action-status').textContent = handingOff.key + ' handed off to @' + recipient + '. Choose the next ready Today item.';
        } else if (transitionResult === null) {
          qs('#my-work-action-status').textContent = handingOff.key + ' handed off to @' + recipient + ', but Today still needs completion.';
        }
      } else {
        paintMyWork(lastContextSnapshot);
        qs('#my-work-action-status').textContent = handingOff.key + ' handed off to @' + recipient + '.';
      }
    } catch (error) {
      qs('#issue-handoff-status').textContent = error.message + ' The issue remains in My Work; retry.';
      button.disabled = false;
      button.focus();
    }
  });
  qs('#close-issue').addEventListener('click', async () => {
    if (!selectedIssue) return;
    const withdrawing = selectedIssue.is_filed && !selectedIssue.is_assigned;
    const confirmation = withdrawing ?
      'Withdraw ' + selectedIssue.key + '? This closes the delegated request.' :
      'Close ' + selectedIssue.key + '?';
    if (!window.confirm(confirmation)) return;
    const closing = selectedIssue;
    const button = qs('#close-issue');
    button.disabled = true;
    if (selectedIssueOffline) {
      qs('#issue-sheet-status').textContent = 'Saving issue closure for background delivery…';
      try {
        const outcome = await closeOfflineIssue(closing);
        closeIssueSheet();
        refreshMyWorkView({ reconcileSession:false });
        if (!outcome.advanced) {
          qs('#my-work-action-status').textContent = 'Issue closure queued, but Today still needs completion.';
        } else if (outcome.admission.background) {
          qs('#my-work-action-status').textContent = 'Issue closure queued for reconnect. Next Today item opened.';
        } else {
          qs('#my-work-action-status').textContent = 'Issue closure saved for next launch. Next Today item opened.';
        }
      } catch (error) {
        qs('#issue-sheet-status').textContent = error.message + ' The issue remains in Today; retry.';
        button.disabled = false;
        button.focus();
      }
      return;
    }
    qs('#issue-sheet-status').textContent = 'Closing issue…';
    try {
      const result = await issueController.close(selectedIssue);
      closeIssueSheet();
      if (withdrawing) Object.assign(closing, {
        state:'closed',is_completed:true,updated_at:result.updated_at || closing.updated_at,
      });
      else lastMyWork = lastMyWork.filter(item =>
        !(item.kind === 'issue' && item.repository === closing.repository && item.number === closing.number));
      refreshMyWorkView({ reconcileSession:false });
      const continuingSession = workSession.active();
      const transitionResult = workSession.active() ? await runTodayTransition('complete') : null;
      if (transitionResult === 'opened') {
        qs('#my-work-action-status').textContent = closing.key + ' closed. Next work item opened.';
      } else if (transitionResult === 'gated') {
        qs('#my-work-action-status').textContent = closing.key + ' closed. Choose the next ready Today item.';
      } else if (!continuingSession) {
        qs('#my-work-action-status').textContent = closing.key + (withdrawing ? ' withdrawn.' : ' closed.');
      }
    } catch (error) {
      qs('#issue-sheet-status').textContent = error.message + ' The issue remains in My Work; retry.';
      button.disabled = false;
      button.focus();
    }
  });
  qs('#close-pull-sheet').addEventListener('click', closePullSheet);
  qs('#retry-pull-load').addEventListener('click', () => {
    if (selectedPull) openPullSheet(selectedPull, pullTrigger);
  });
  qs('#pull-review').addEventListener('toggle', event => {
    if (event.currentTarget.open) loadPullReview();
  });
  qs('#pull-review-retry').addEventListener('click', loadPullReview);
  qs('#refresh-pull-checks').addEventListener('click', async () => {
    if (!selectedPull || !selectedPullDetail?.head_sha) return;
    const item = selectedPull;
    const button = qs('#refresh-pull-checks');
    button.disabled = true;
    qs('#pull-checks-summary').textContent = 'Refreshing…';
    try {
      const status = await pullController.loadChecks(item);
      if (selectedPull !== item) return;
      renderPullCheckStatus(status);
    } catch (_error) {
      if (selectedPull === item) qs('#pull-checks-summary').textContent = 'Refresh failed · retry';
    } finally { button.disabled = false; }
  });
  qs('#next-unreviewed-pull-file').addEventListener('click', () => {
    createPullSheet.focusNextUnreviewed(document, selectedPullDetail, pullReviewState, pullController);
  });
  qs('#load-older-pull-comments').addEventListener('click', async () => {
    if (!pullConversation) return;
    const button = qs('#load-older-pull-comments');
    const panel = qs('#pull-sheet .pull-sheet-panel');
    const previousHeight = panel.scrollHeight;
    button.disabled = true;
    qs('#pull-conversation-status').textContent = 'Loading older messages…';
    try {
      renderPullConversation(await pullConversation.loadOlder());
      panel.scrollTop += panel.scrollHeight - previousHeight;
    } catch (error) {
      qs('#pull-conversation-status').textContent = error.message + ' Loaded messages and your draft are safe; retry.';
    } finally {
      button.disabled = false;
    }
  });
  qs('#pull-comment').addEventListener('input', event => {
    if (selectedPull) pullController.saveDraft(selectedPull, event.target.value);
  });
  qs('#send-pull-comment').addEventListener('click', async () => {
    if (!selectedPull) return;
    const item = selectedPull;
    const body = qs('#pull-comment').value.trim();
    if (!body && !pullAttachmentController.state()) {
      qs('#pull-comment-status').textContent = 'Write a comment before posting.';
      qs('#pull-comment').focus();
      return;
    }
    const button = qs('#send-pull-comment');
    button.disabled = true;
    pullAttachmentController.setBusy(true);
    qs('#pull-comment-status').textContent = pullAttachmentController.state() ?
      'Uploading screenshot…' : 'Posting comment…';
    const operationId = localStorage.getItem('stackchain.pull-comment.v1:' +
      item.repository + '#' + item.number + ':operation');
    let preparedBody;
    try {
      if (pullAttachmentController.state()) {
        const admission = await queuePullScreenshotComment(item, body, operationId, false, true);
        refreshMyWorkView();
        pullController.saveDraft(item, '');
        if (selectedPull === item) {
          if (admission.delivered && pullConversation) {
            renderPullConversation(pullConversation.append(admission.delivered));
          }
          qs('#pull-comment').value = '';
          await conversationPhotoDrafts.complete('pull');
          qs('#pull-comment-status').textContent = admission.delivered ? 'Comment posted.' :
            (admission.background ? 'Queued with screenshot for sync when the connection returns.' :
              'Saved with screenshot for next launch; background delivery unavailable.');
        }
        return;
      }
      preparedBody = body;
      const comment = await pullController.comment(item, preparedBody);
      if (selectedPull === item && pullConversation) renderPullConversation(pullConversation.append(comment));
      pullController.saveDraft(item, '');
      if (selectedPull === item) qs('#pull-comment').value = '';
      await conversationPhotoDrafts.complete('pull');
      qs('#pull-comment-status').textContent = 'Comment posted.';
    } catch (error) {
      if (canQueueMessage(error) && !pullAttachmentController.state()) {
        try {
          qs('#pull-comment-status').textContent = 'Saving for background delivery…';
          const admission = await authoredOutbox.enqueueDurably({
            kind:'pull-comment', repository:item.repository, number:item.number,
            body:preparedBody ?? body, operationId,
          });
          pullController.saveDraft(item, '');
          if (selectedPull === item) qs('#pull-comment').value = '';
          refreshMyWorkView();
          qs('#pull-comment-status').textContent = admission.background ?
            'Queued for sync when the connection returns.' :
            'Saved for next launch; background delivery unavailable.';
          return;
        } catch (admissionError) {
          error = admissionError;
        }
      }
      qs('#pull-comment-status').textContent = error.message + ' Your comment and screenshot are safe; retry.';
      qs('#pull-comment').focus();
    } finally {
      pullAttachmentController.setBusy(false);
      button.disabled = false;
    }
  });
  qs('#merge-pull').addEventListener('click', async () => {
    if (!selectedPull || !selectedPullDetail?.head_sha || !window.confirm('Merge ' + selectedPull.key + ' at current head?')) return;
    const merging = selectedPull;
    const button = qs('#merge-pull');
    button.disabled = true;
    qs('#pull-sheet-status').textContent = 'Merging pull request…';
    try {
      const mergeResult = await pullController.merge(selectedPull, selectedPullDetail.head_sha);
      releaseReceipt.capture(merging, mergeResult);
      closePullSheet();
      lastMyWork = lastMyWork.filter(item =>
        !(item.kind === 'pull' && item.repository === merging.repository && item.number === merging.number)
      );
      refreshMyWorkView({ reconcileSession:false });
      const continuingSession = workSession.active();
      const transitionResult = workSession.active() ? await runTodayTransition('complete') : null;
      if (transitionResult === 'opened') {
        qs('#my-work-action-status').textContent = merging.key + ' merged. Next work item opened.';
      } else if (transitionResult === 'gated') {
        qs('#my-work-action-status').textContent = merging.key + ' merged. Choose the next ready Today item.';
      } else if (!continuingSession) {
        qs('#my-work-action-status').textContent = merging.key + ' merged.';
      }
    } catch (error) {
      qs('#pull-sheet-status').textContent = error.message + ' The pull request remains in My Work; refresh and retry.';
      button.disabled = false;
      button.focus();
    }
  });
  const updateDecisionActions = createUpdateDecisionActions({
    transaction:updateDecision, triage:updateTriage, close:()=>closeUpdateSheet(true),
    reader:notificationReader, items:()=>lastMyWork, undo:notificationUndo,
    keepControl:qs('#keep-update-unread'), readControl:qs('#mark-update-read-next'),
  });
  const keepUpdateUnread = () => updateDecisionActions.keepUnread();
  const markUpdateRead = () => updateDecisionActions.markRead();
  qs('#keep-update-unread').addEventListener('click', keepUpdateUnread);
  createUpdateTriageGesture({
    surface: qs('#update-sheet .update-sheet-panel'), enabled: () => selectedUpdateDetail,
    keepUnread: keepUpdateUnread, markRead: markUpdateRead,
  });
  qs('#update-ownership-action').addEventListener('click', () => updateOwnership.act());
  qs('#update-ownership-start').addEventListener('click', () => updateOwnership.start());
  qs('#retry-update-load').addEventListener('click', () => {
    if (selectedUpdate) notificationReader.open(selectedUpdate, lastMyWork);
  });
  qs('#retry-update-conversation').addEventListener('click', () => {
    notificationReader.retryConversation();
  });
  qs('#load-older-update-comments').addEventListener('click', async () => {
    const button = qs('#load-older-update-comments');
    const panel = qs('#update-sheet .update-sheet-panel');
    const previousHeight = panel.scrollHeight;
    const previousTop = panel.scrollTop;
    button.disabled = true;
    await notificationReader.loadOlder();
    panel.scrollTop = previousTop + (panel.scrollHeight - previousHeight);
    button.disabled = false;
  });
  qs('#update-reply').addEventListener('input', event => {
    if (selectedUpdate) notificationReplier.saveDraft(selectedUpdate, event.target.value);
  });
  qs('#send-update-reply').addEventListener('click', async () => {
    if (!selectedUpdate) return;
    const body = qs('#update-reply').value.trim();
    const attachment = await updateReplyAttachmentController.serialize();
    if (!body && !attachment) {
      qs('#update-reply-status').textContent = 'Write a reply or attach a screenshot before sending.';
      qs('#update-reply').focus();
      return;
    }
    qs('#send-update-reply').disabled = true;
    updateReplyAttachmentController.setBusy(true);
    const result = await notificationReplier.submit(selectedUpdate, body, attachment);
    qs('#send-update-reply').disabled = false;
    updateReplyAttachmentController.setBusy(false);
    if (result?.queued) {
      qs('#update-reply').value = '';
      await conversationPhotoDrafts.complete('update');
      refreshMyWorkView();
      qs('#my-work-action-status').textContent = 'Reply queued for sync.';
    } else if (result) {
      notificationReader.appendReply(result);
      qs('#update-reply').value = '';
      await conversationPhotoDrafts.complete('update');
      qs('#mark-update-read-next').focus();
    } else {
      qs('#update-reply').focus();
    }
  });
  qs('#send-update-reply-read-next').addEventListener('click', async () => {
    if (!selectedUpdate) return;
    const item = selectedUpdate;
    const body = qs('#update-reply').value.trim();
    const attachment = await updateReplyAttachmentController.serialize();
    if (!body && !attachment) {
      qs('#update-reply-status').textContent = 'Write a reply or attach a screenshot before sending.';
      qs('#update-reply').focus();
      return;
    }
    const button = qs('#send-update-reply-read-next');
    const sendButton = qs('#send-update-reply');
    button.disabled = true;
    sendButton.disabled = true;
    updateReplyAttachmentController.setBusy(true);
    qs('#update-reply-status').textContent = 'Replying, then marking read…';
    const operationId = globalThis.crypto?.randomUUID?.() || String(Date.now()) + '-' + Math.random();
    try {
      const result = await updateReplyReadNext.submit(item, body, operationId, attachment);
      if (result?.accepted) await conversationPhotoDrafts.complete('update');
      if (result?.accepted) qs('#my-work-action-status').textContent =
        result.delivery === 'posted' ? 'Reply posted and update marked read.' :
          'Reply and read acknowledgement queued for sync.';
      if (result?.delivery === 'posted' && result?.next) {
        notificationUndo.offer(item, result.next.items);
        if (updateTriage.active()) updateTriage.acceptCompleted();
      }
    } catch (error) {
      qs('#update-reply-status').textContent = error.message + ' Your draft is safe; retry.';
      qs('#update-reply').focus();
    } finally {
      button.disabled = false;
      sendButton.disabled = false;
      updateReplyAttachmentController.setBusy(false);
    }
  });
  qs('#mark-update-read-next').addEventListener('click', markUpdateRead);
  qs('#acknowledge-update-next').addEventListener('click', async () => {
    const button = qs('#acknowledge-update-next');
    button.disabled = true;
    try {
      const result = await notificationReader.acknowledgeAndNext(lastMyWork);
      if (result) {
        notificationUndo.offer(result.item, result.items);
        if (updateTriage.active()) updateTriage.acceptCompleted();
      }
    } finally {
      button.disabled = offlineWorkMode;
    }
  });
  qs('#mute-update-next').addEventListener('click', async () => {
    if (!selectedUpdate || offlineWorkMode) return;
    const button = qs('#mute-update-next');
    const item = selectedUpdate;
    button.disabled = true;
    qs('#update-sheet-status').textContent = 'Muting future updates…';
    try {
      await muteNotification(item.notification_id);
      const result = await notificationReader.acceptReadAndNext(lastMyWork, item);
      if (result && updateTriage.active()) updateTriage.acceptCompleted();
    } catch (error) {
      qs('#update-sheet-status').textContent = error.muted ?
        'Future updates are muted; current item is still unread. Retry mark read & next.' : error.message;
      if (error.muted) {
        button.hidden = true;
        qs('#mark-update-read-next').focus();
      }
    } finally {
      button.disabled = offlineWorkMode;
    }
  });
  qs('#undo-notification').addEventListener('click', async () => {
    const button = qs('#undo-notification');
    button.disabled = true;
    const restored = await notificationUndo.run();
    button.disabled = restored;
  });
  qs('#close-review-sheet').addEventListener('click', closeReviewSheet);
  qs('#retry-review-load').addEventListener('click', () => {
    if (selectedReview) openReviewSheet(selectedReview, reviewTrigger);
  });
  qs('#refresh-review-checks').addEventListener('click', async () => {
    if (!selectedReview || offlineReview) return;
    const item = selectedReview;
    const button = qs('#refresh-review-checks');
    button.disabled = true;
    qs('#review-checks-summary').textContent = 'Refreshing…';
    try {
      const detail = await reviewController.loadChecks(item);
      if (selectedReview !== item) return;
      if (selectedReviewHead && detail.head_sha !== selectedReviewHead) {
        qs('#review-sheet-status').textContent = 'New commits detected. Reload the review before submitting feedback.';
        qs('#submit-review').disabled = true;
      }
      qs('#review-ci-state').textContent = 'CI ' + (detail.ci_state || 'unknown');
      renderCheckSection('review', detail);
    } catch (error) {
      if (selectedReview === item) qs('#review-checks-summary').textContent = 'Refresh failed · retry';
    } finally { button.disabled = false; }
  });
  qs('#next-unreviewed-review').addEventListener('click', () => {
    if (progress) openNextUnreviewed(progress.snapshot());
  });
  qs('#review-wrap-lines').addEventListener('click', () => {
    const next = !wrapPreference.snapshot().wrapped;
    applyReviewWrap(wrapPreference.setWrapped(next));
  });
  qs('#review-summary').addEventListener('input', event => draft?.setSummary(event.target.value));
  qs('#review-decision').addEventListener('change', event => draft?.setDecision(event.target.value));
  qs('#save-inline-comment').addEventListener('click', () => {
    if (!draft || !activeInlineTarget) return;
    const body = qs('#review-inline-body').value.trim();
    if (!body) {
      qs('#review-inline-body').focus();
      return;
    }
    draft.setInlineComment(inlineAnchor(activeInlineTarget), body);
    activeInlineTarget.classList.add('has-draft');
    const target = activeInlineTarget;
    closeInlineComposer();
    target.focus();
  });
  qs('#delete-inline-comment').addEventListener('click', () => {
    if (!draft || !activeInlineTarget) return;
    draft.removeInlineComment(inlineAnchor(activeInlineTarget));
    activeInlineTarget.classList.remove('has-draft');
    const target = activeInlineTarget;
    closeInlineComposer();
    target.focus();
  });
  qs('#cancel-inline-comment').addEventListener('click', () => {
    const target = activeInlineTarget;
    closeInlineComposer();
    target?.focus();
  });
  qs('#submit-review').addEventListener('click', async () => {
    if (!draft || !selectedReview || !selectedReviewHead) return;
    const snapshot = draft.snapshot();
    const labels = { approve: 'Approve', request_changes: 'Request changes' };
    if (labels[snapshot.decision] && !window.confirm(
      labels[snapshot.decision] + ' ' + selectedReview.repository + '#' + selectedReview.number + '?'
    )) return;
    const button = qs('#submit-review');
    button.disabled = true;
    if (updateReviewHandoff.active() && reviewHandoffSubmitted) {
      try {
        await updateReviewHandoff.complete();
      } catch (error) {
        qs('#review-submit-status').textContent = 'Review submitted, but the update is still unread. ' +
          error.message + ' Retry to continue.';
        button.disabled = false;
        button.focus();
      }
      return;
    }
    if (offlineReview) {
      const queuedTodayReview = reviewingActiveTodayItem();
      qs('#review-submit-status').textContent = 'Queueing review safely…';
      try {
        await authoredOutbox.enqueueDurably({
          kind: 'pull-review',
          repository: selectedReview.repository,
          number: selectedReview.number,
          body: createReviewController.formatFeedback(snapshot, reviewFiles),
          decision: snapshot.decision,
          expectedHeadSha: selectedReviewHead,
          comments: snapshot.comments,
          draftKey: draft.storageKey,
          progressKey: progress?.storageKey || '',
          draftFingerprint: localStorage.getItem(draft.storageKey) || '',
          progressFingerprint: localStorage.getItem(progress?.storageKey) || '',
        });
        if (updateReviewHandoff.active()) {
          reviewHandoffSubmitted = true;
          await updateReviewHandoff.complete();
          return;
        }
        if (queuedTodayReview) {
          const advanced = completeTodayItem(selectedReview, {
            successMessage: 'Review queued. Next Today item opened.',
            failureMessage: 'Review queued, but Today still needs completion.',
          });
          if (!advanced) {
            qs('#review-submit-status').textContent = 'Review queued, but Today still needs completion.';
          }
        } else {
          qs('#review-submit-status').textContent = 'Review queued · it will submit after reconnect.';
        }
      } catch (error) {
        qs('#review-submit-status').textContent = error.message + ' Your draft is safe; retry when ready.';
        button.disabled = false;
        button.focus();
      }
      return;
    }
    qs('#review-submit-status').textContent = 'Submitting review…';
    try {
      const item = selectedReview;
      const progressSnapshot = progress?.snapshot() || { reviewed: [] };
      const result = await reviewController.submit(selectedReview, {
        decision: snapshot.decision,
        body: createReviewController.formatFeedback(snapshot, reviewFiles),
        expected_head_sha: selectedReviewHead,
        comments: snapshot.comments,
      });
      if (updateReviewHandoff.active()) {
        reviewHandoffSubmitted = true;
        await updateReviewHandoff.complete();
        return;
      }
      const canContinueToMerge = createReviewController.prepareMergeContinuation({
        storage: localStorage,
        item,
        headSha: selectedReviewHead,
        reviewed: progressSnapshot.reviewed,
        decision: snapshot.decision,
      });
      draft.clear();
      progress?.clear();
      qs('#review-decision').value = 'comment';
      qs('#review-summary').value = '';
      document.querySelectorAll('.review-note').forEach(note => { note.value = ''; });
      if (progress) showReviewProgress(progress.snapshot());
      qs('#review-submit-status').textContent = 'Review submitted · ' + (result.state || 'complete') + '.';
      if (canContinueToMerge) {
        qs('#continue-review-to-merge').hidden = false;
        qs('#continue-review-to-merge').focus();
      } else {
        await load();
        if (workSession.active()) await runTodayTransition('complete');
        else button.focus();
      }
    } catch (error) {
      qs('#review-submit-status').textContent = error.message + ' Your draft is safe; retry or open in Gitea.';
      button.disabled = false;
      button.focus();
    }
  });
  qs('#continue-review-to-merge').addEventListener('click', () => {
    const item = selectedReview;
    if (!item) return;
    workRoute.open({ ...item, kind:'pull', is_review:false }, { replace:true });
  });
  qs('#copy-review-feedback').addEventListener('click', async () => {
    if (!draft || !selectedReview || reviewHandoffPending) return;
    reviewHandoffPending = true;
    qs('#copy-review-feedback').disabled = true;
    const fallback = qs('#review-copy-fallback');
    const directLink = qs('#review-handoff-link');
    fallback.hidden = true;
    directLink.hidden = true;
    let handoffWindow = null;
    try {
      const result = await createReviewController.copyAndContinue({
        text: createReviewController.formatFeedback(draft.snapshot(), reviewFiles),
        url: selectedReview.url,
        copy: text => navigator.clipboard.writeText(text),
        open: () => {
          handoffWindow = window.open('about:blank', '_blank');
          if (handoffWindow) handoffWindow.opener = null;
          return handoffWindow;
        },
        fallback: text => {
          fallback.value = text;
          fallback.hidden = false;
          fallback.focus();
          fallback.select();
        },
      });
      if (result.opened) {
        qs('#review-handoff-status').textContent = 'Feedback copied. Gitea opened in a new tab.';
      } else {
        directLink.hidden = false;
        qs('#review-handoff-status').textContent = result.copied ?
          'Feedback copied. Your browser blocked the new tab; continue with the link below.' :
          'Clipboard unavailable. Copy the selected feedback, then continue to Gitea.';
      }
    } finally {
      reviewHandoffPending = false;
      qs('#copy-review-feedback').disabled = false;
    }
  });

  const contextPoller = createContextPoller({
    fetchContext: fetchLiveSnapshot,
    onSnapshot: renderLiveSnapshot,
    onError: async error => {
      await handleContextError(error);
      setEventStreamStatus('Update failed · showing last activity');
    },
    isHidden: () => document.hidden,
    intervalMs: 8000,
  });
  function load() { return contextPoller.refresh({ force: true }); }
  createMobilePullRefresh({refresh:load}).start();
  const liveDataStatusSheet = qs('#live-data-status-sheet');
  const liveDataStatusTrigger = qs('#open-live-data-status');
  let latestLiveFreshness = {};
  function feedAge(feed) {
    return feed.ageSeconds === null ? 'Snapshot age unavailable' :
      (feed.ageSeconds < 60 ? feed.ageSeconds + 's old' : Math.floor(feed.ageSeconds / 60) + 'm old');
  }
  function renderLiveDataStatus(freshness = latestLiveFreshness) {
    latestLiveFreshness = freshness;
    const description = liveDataStatus.describe(freshness);
    setStatus(description.summary);
    qs('#live-data-status-feeds').innerHTML = description.feeds.map(feed =>
      '<div class="live-data-status-feed"><strong>' + escapeHtml(feed.label) + '</strong><span>' +
      escapeHtml(feed.state === 'live' ? 'Live · ' + feedAge(feed) :
        feed.state === 'refreshing' ? 'Refreshing · ' + feedAge(feed) : 'Delayed · ' + feedAge(feed)) + '</span></div>'
    ).join('');
    const pollState = contextPoller.getState();
    const retrySeconds = description.nextRetrySeconds || (pollState.nextRetryAt ?
      Math.max(1, Math.ceil((pollState.nextRetryAt - Date.now()) / 1000)) : null);
    qs('#live-data-status-retry').textContent = retrySeconds ?
      'Next automatic retry in ' + retrySeconds + 's.' :
      (pollState.lastSuccessAt ? 'Last successful refresh ' + fmt(new Date(pollState.lastSuccessAt)) + '.' : 'Waiting for the first successful refresh.');
  }
  liveDataStatus.mount({document, window, timerView, onOpen:renderLiveDataStatus}).start();
  const liveDataRefresh = liveDataStatus.createRefreshController({
    button: qs('#refresh-live-data'),
    output: qs('#live-data-status-result'),
    refresh: () => contextPoller.refresh({ force: true }),
    onState: state => { if (state === 'refreshing') setStatus('Refreshing live data'); },
  });
  qs('#refresh-live-data').addEventListener('click', liveDataRefresh.run);

  const offlineStatus = qs('#offline-status');
  const keepWorkOffline = qs('#keep-work-offline');
  const offlineWorkStatus = qs('#offline-work-status');
  const retryOfflineStorage = qs('#retry-offline-storage');
  const deliveryReceipts = qs('#delivery-receipts');
  const deliveryReceiptStatus = qs('#delivery-receipt-status');
  async function updateOfflineWorkControls(message) {
    keepWorkOffline.checked = offlineWorkStore.enabled();
    keepWorkOffline.disabled = !offlineStorageReady;
    retryOfflineStorage.hidden = offlineStorageReady;
    const saved = await offlineWorkStore.load();
    offlineWorkStatus.textContent = message || (!offlineStorageReady ?
      'Offline saving unavailable · online work remains live.' : saved ? 'Saved ' + fmt(saved.saved_at) + ' · expires after 7 days.' :
      (keepWorkOffline.checked ? 'Waiting for a healthy live refresh.' : 'Off · no work data is stored.'));
  }
  async function updateDeliveryReceiptControls(message) {
    const supported = Boolean(backgroundIssueSync && 'Notification' in window && 'serviceWorker' in navigator);
    deliveryReceipts.disabled = !supported || !confirmedOwnerLogin;
    if (!supported) {
      deliveryReceipts.checked = false;
      deliveryReceiptStatus.textContent = 'Delivery notifications are unavailable in this browser.';
      return;
    }
    if (!confirmedOwnerLogin) {
      deliveryReceipts.checked = false;
      deliveryReceiptStatus.textContent = 'Waiting for your signed-in account.';
      return;
    }
    deliveryReceipts.checked = Notification.permission === 'granted' &&
      await backgroundIssueSync.getReceiptPreference(confirmedOwnerLogin);
    deliveryReceiptStatus.textContent = message || (deliveryReceipts.checked
      ? 'Background delivery receipts enabled for @' + confirmedOwnerLogin + '.'
      : Notification.permission === 'denied' ? 'Notifications are blocked in browser settings.' : 'Off by default.');
  }
  function setOfflineWorkMode(value) {
    offlineWorkMode = value;
    ['#find-work', '#start-work-session', '#load-more-work', '#load-more-notifications', '#bulk-mark-read']
      .forEach(selector => { const button = qs(selector); if (button) button.disabled = value; });
    if (value) {
      document.querySelectorAll('[data-notification-id], [data-later-preset], [data-today-add]')
        .forEach(button => { button.disabled = true; });
    }
  }
  async function hydrateOfflineWork(mode = 'offline') {
    const saved = await offlineWorkStore.load();
    if (!saved) return false;
    const outage = mode === 'outage';
    confirmedOwnerLogin = String(saved.user?.login || '').trim();
    restoreReleaseReceipt();
    planningOwnerLogin = confirmedOwnerLogin;
    interruptionPrompt.restore();
    updatePlanningAvailability();
    saved.notifications = notificationReadOutbox.suppress(saved.notifications || []);
    lastNotifications = saved.notifications;
    notificationPagination = saved.notification_pagination || { page:1, total:lastNotifications.length, has_more:false };
    workPagination = saved.work_pagination || {};
    lastContextSnapshot = saved;
    hasContextSnapshot = true;
    paintMyWork(saved);
    setOfflineWorkMode(true);
    const savedLabel = fmt(saved.saved_at);
    if (outage) {
      qs('#my-work-status').textContent = 'Outage · saved ' + savedLabel + ' · read-only';
      offlineStatus.textContent = 'Server unavailable · showing private My Work saved ' + savedLabel + '. Live details and actions will return automatically.';
      offlineWorkStatus.textContent = 'Outage · saved ' + savedLabel + ' · expires after 7 days.';
      setStatus('Outage · saved snapshot');
    } else {
      qs('#my-work-status').textContent = 'Offline · saved ' + savedLabel + ' · read-only';
      offlineStatus.textContent = 'Offline · showing private My Work saved ' + savedLabel + '. Live details and actions require reconnection.';
      offlineWorkStatus.textContent = 'Offline · saved ' + savedLabel + ' · expires after 7 days.';
      setStatus('Offline · saved snapshot');
    }
    offlineStatus.hidden = false;
    return true;
  }
  async function showOfflineStatus() {
    activeFlushLogin = '';
    offlineStatus.hidden = false;
    setStatus('Offline');
    if (!hasContextSnapshot) await hydrateOfflineWork();
  }
  const reconnectOutboxes = createReconnectOutboxes({
    refresh: async () => {
      setStatus('Reconnecting…');
      const snapshot = await contextPoller.refresh({ force: true });
      if (!snapshot) {
        offlineStatus.hidden = false;
        setOfflineWorkMode(true);
        return null;
      }
      offlineStatus.hidden = true;
      setOfflineWorkMode(false);
      if (selectedReview && offlineReview) openReviewSheet(selectedReview, reviewTrigger);
      return snapshot;
    },
    restoreIdentity: login => { activeFlushLogin = login; confirmedOwnerLogin = login; },
    flushIssue: flushIssueOutbox,
    flushAuthored: flushAuthoredOutbox,
    flushNotificationReads: flushNotificationReadOutbox,
  });
  const reconnectAfterOnline = () => setTimeout(reconnectOutboxes, 500);
  window.addEventListener('online', reconnectAfterOnline);
  workspaceLifecycle.replayOnline(reconnectAfterOnline);
  async function setOfflineWorkEnabled(enabled) {
    keepWorkOffline.checked = enabled;
    offlineWorkStore.setEnabled(enabled);
    if (enabled && liveMode && lastContextSnapshot) {
      const admitted = await offlineWorkStore.save({ ...lastContextSnapshot, notifications:lastNotifications,
        notification_pagination:notificationPagination });
      if (admitted === false) {
        await updateOfflineWorkControls('Offline saving unavailable · retry after reconnect.');
        return false;
      }
    }
    if (!enabled) await offlineWorkStore.clear();
    await updateOfflineWorkControls(enabled ? 'Offline saving enabled.' : 'Offline work data cleared.');
    if (enabled) warmTodayOffline();
    else offlineToday.cancel();
    return offlineWorkStore.enabled();
  }
  keepWorkOffline.addEventListener('change', async () => {
    await setOfflineWorkEnabled(keepWorkOffline.checked);
  });
  deliveryReceipts.addEventListener('change', async () => {
    let enabled = deliveryReceipts.checked;
    if (enabled && Notification.permission !== 'granted') {
      enabled = await Notification.requestPermission() === 'granted';
    }
    deliveryReceipts.checked = enabled;
    if (backgroundIssueSync && confirmedOwnerLogin) {
      await backgroundIssueSync.setReceiptPreference(confirmedOwnerLogin, enabled);
    }
    await updateDeliveryReceiptControls(enabled ? 'Background delivery receipts enabled.' :
      (Notification.permission === 'denied' ? 'Notifications are blocked in browser settings.' : 'Background delivery receipts disabled.'));
  });
  qs('#clear-offline-work').addEventListener('click', async () => {
    await offlineWorkStore.clear();
    offlineToday.cancel();
    renderOfflineTodayStatus({ total:0, ready:0, failed:0, pending:0 });
    await updateOfflineWorkControls('Offline work data cleared.');
  });
  retryOfflineStorage.addEventListener('click', async () => {
    retryOfflineStorage.disabled = true;
    offlineWorkStatus.textContent = 'Retrying offline saving…';
    offlineStorageReady = await offlineWorkStore.retry();
    retryOfflineStorage.disabled = false;
    if (offlineStorageReady && offlineWorkStore.enabled() && liveMode && lastContextSnapshot) {
      await offlineWorkStore.save({ ...lastContextSnapshot, notifications:lastNotifications,
        notification_pagination:notificationPagination });
    }
    await updateOfflineWorkControls(offlineStorageReady ? 'Offline saving restored.' :
      'Offline saving unavailable · online work remains live.');
  });
  qs('#retry-offline-today').addEventListener('click', () =>
    offlineToday.retry(confirmedOwnerLogin, todayMyWork)
  );
  await updateOfflineWorkControls();
  updateDeliveryReceiptControls();
  if (!navigator.onLine) await showOfflineStatus();
  window.addEventListener('offline', showOfflineStatus);

  qs('#refresh').addEventListener('click', load);
  qs('#plan-today').addEventListener('click', event => openPlanToday(event.currentTarget));
  qs('#plan-tomorrow').addEventListener('click', event => openTomorrowPlanner(event.currentTarget));
  qs('#keep-phone-tomorrow').addEventListener('click', async () => {
    const keep = qs('#keep-phone-tomorrow');
    const use = qs('#use-server-tomorrow');
    keep.disabled = true;
    use.disabled = true;
    qs('#tomorrow-conflict-status').textContent = 'Saving this phone’s plan…';
    try {
      const saved = await tomorrowPlan.keepLocal();
      renderTomorrowQueueSummary(saved);
      qs('#my-work-action-status').textContent = 'This phone’s Tomorrow plan is saved to your account. Today was not changed.';
      closePlanToday();
    } catch (error) {
      const conflict = tomorrowPlan.conflict();
      if (conflict) showTomorrowConflict(conflict);
      qs('#tomorrow-conflict-status').textContent = error?.status === 409 ?
        'Tomorrow changed again. Both latest plans are still preserved; choose again.' :
        `${error.message || 'Tomorrow could not be saved.'} Both plans are still preserved.`;
    } finally {
      keep.disabled = false;
      use.disabled = false;
    }
  });
  qs('#use-server-tomorrow').addEventListener('click', () => {
    const adopted = tomorrowPlan.useRemote();
    if (!adopted) return;
    renderTomorrowQueueSummary(adopted);
    qs('#my-work-action-status').textContent = 'Saved account Tomorrow plan selected. Today was not changed.';
    closePlanToday();
  });
  qs('#keep-phone-week').addEventListener('click', async () => {
    const keep=qs('#keep-phone-week'),use=qs('#use-server-week');
    keep.disabled=true;use.disabled=true;
    qs('#week-conflict-status').textContent='Saving this phone’s complete week…';
    try {
      await weekPlan.keepLocal();
      qs('#mobile-week-summary').textContent=weekPlan.summary();
      qs('#my-work-action-status').textContent='This phone’s Week Ahead plan is saved to your account. Today was not changed.';
      closePlanToday();
    } catch(error) {
      const conflict=weekPlan.conflict();
      if(conflict)showWeekConflict(conflict);
      qs('#week-conflict-status').textContent=error?.status===409?
        'Week Ahead changed again. Both latest weeks are preserved; choose again.':
        `${error.message||'Week Ahead could not be saved.'} Both weeks are still preserved.`;
    } finally {keep.disabled=false;use.disabled=false;}
  });
  qs('#use-server-week').addEventListener('click', () => {
    const adopted=weekPlan.useRemote();
    if(!adopted)return;
    qs('#mobile-week-summary').textContent=weekPlan.summary();
    qs('#my-work-action-status').textContent='Saved account Week Ahead plan selected. Today was not changed.';
    closePlanToday();
  });
  qs('#save-merged-week').addEventListener('click', async () => {
    const save=qs('#save-merged-week');
    save.disabled=true;
    qs('#week-conflict-status').textContent='Saving combined Week Ahead plan…';
    try {
      await weekPlan.saveMerged();
      qs('#mobile-week-summary').textContent=weekPlan.summary();
      qs('#my-work-action-status').textContent='Combined Week Ahead changes are saved. Today was not changed.';
      closePlanToday();
    } catch(error) {
      const conflict=weekPlan.conflict();
      if(conflict)showWeekConflict(conflict);
      qs('#week-conflict-status').textContent=error?.status===409?
        'Week Ahead changed again. The latest days are preserved; review the remaining choices.':
        `${error.message||'The combined week could not be saved.'} Your phone plan is still preserved.`;
    } finally {
      const conflict=weekPlan.conflict();
      save.disabled=Boolean(conflict?.conflicts?.some(item=>!item.choice));
    }
  });
  qs('#cancel-plan-today').addEventListener('click', closePlanToday);
  qs('#plan-today-sheet').addEventListener('click', event => {
    if (event.target === qs('#plan-today-sheet')) closePlanToday();
  });
  qs('#today-readiness-close').addEventListener('click', () => closeTodayReadiness());
  qs('#today-readiness-sheet').addEventListener('click', event => {
    if (event.target === qs('#today-readiness-sheet')) closeTodayReadiness();
  });
  qs('#today-readiness-next').addEventListener('click', () => todayReadiness.startNextReady());
  qs('#today-readiness-anyway').addEventListener('click', () => todayReadiness.workAnyway());
  qs('#today-readiness-retry').addEventListener('click', () => todayReadiness.retry());
  qs('#today-readiness-plan').addEventListener('click', () => {
    closeTodayReadiness();
    openPlanToday(qs('#plan-today'));
  });
  qs('#plan-today-available').addEventListener('change', event => {
    planToday.setCapacity(Number(event.currentTarget.value));
    qs('#plan-today-error').textContent = '';
    renderPlanToday();
  });
  qs('#build-today-plan').addEventListener('click', () => buildTodayPlan());
  function commitPlanToday(start, button) {
    const result = planToday.commit({ start, confirmOverCapacity: button.dataset.confirmOverCapacity === 'true' });
    if (result === 'saved') {
      button.dataset.confirmOverCapacity = '';
      taskOverlayHistory.leave();
    } else if (result === 'confirm-over-capacity') {
      button.dataset.confirmOverCapacity = 'true';
      qs('#plan-today-error').textContent = 'This plan exceeds your available time. Press again to save over capacity.';
      button.textContent = start ? 'Save over capacity & start' : 'Save over capacity';
    } else {
      qs('#plan-today-error').textContent = 'Could not save the plan on this device. Free storage and retry.';
    }
  }
  qs('#save-today-plan').addEventListener('click', event => commitPlanToday(false, event.currentTarget));
  qs('#save-and-start-today').addEventListener('click', event => commitPlanToday(true, event.currentTarget));
  qs('#start-work-session').addEventListener('click', () => {
    const sessionItems = workSession.items();
    if (!sessionItems.length) {
      qs('#my-work-action-status').textContent = 'No visible work to start.';
      return;
    }
    if (selectedWorkFilter === 'today') runTodayTransition('start');
    else if (selectedWorkFilter === 'agenda' && agendaSessionCheckpoint.read()) workSession.resume();
    else workSession.start();
  });
  qs('#resume-today-session').addEventListener('click', () => resumeTodaySession());

  qs('#end-today-session').addEventListener('click', () => endTodaySession(workSession, qs));
  document.querySelectorAll('[data-work-session-previous]').forEach(button =>
    button.addEventListener('click', () => workSession.previous())
  );
  document.querySelectorAll('[data-work-session-next]').forEach(button =>
    button.addEventListener('click', () => workSession.checkpointed() ? runTodayTransition('next') : workSession.next())
  );
  document.querySelectorAll('[data-work-session-timer-toggle]').forEach(button =>
    button.addEventListener('click', () => timerView.toggle())
  );
  document.querySelectorAll('[data-work-session-complete]').forEach(button =>
    button.addEventListener('click', () =>
      completeTodayItem(selectedSessionItem(button.dataset.workSessionComplete))
    )
  );
  qs('#load-more-notifications').addEventListener('click', () =>
    notificationPager.loadMore(lastNotifications)
  );
  qs('#load-more-work').addEventListener('click', async () => {
    if (selectedWorkFilter === 'agenda') {
      await completeAgendaIssues();
      return;
    }
    const stream = activeWorkStreams().find(item => workPagination[item]?.has_more);
    if (!stream || !lastContextSnapshot) return;
    const button = qs('#load-more-work');
    button.disabled = true;
    const existing = stream === 'issue' || stream === 'filed' ?
      (lastContextSnapshot.issues || []) : (lastContextSnapshot.pull_requests || []);
    try {
      const loaded = await workPager.loadMore(stream, existing);
      if (loaded) document.querySelector('.my-work-card:last-child .my-work-card-main')?.focus();
      else button.focus();
    } finally {
      button.disabled = false;
    }
  });
  qs('#select-work').addEventListener('click', () => {
    if (notificationSelection.snapshot().active) notificationSelection.cancel();
    workSelection.start();
    document.querySelector('[data-select-work-id]')?.focus();
  });
  qs('#cancel-work-selection').addEventListener('click', () => {
    workSelection.cancel();
    qs('#select-work').focus();
  });
  qs('#batch-add-today').addEventListener('click', () => {
    const ids = new Set(workSelection.snapshot().ids);
    const selectedItems = lastMyWork.filter(item => ids.has(workSelection.identity(item)));
    const result = todayWork.addMany(selectedItems);
    if (result.status === 'added') {
      result.ids.forEach(id => todaySync.enqueue('add', id));
      todaySync.flush();
      warmTodayOffline();
      qs('#my-work-action-status').textContent = result.ids.length + ' items added to Today without changing Gitea.';
      workSelection.cancel();
    } else {
      qs('#my-work-action-status').textContent = result.status === 'full' ?
        'The full selection will not fit in Today. Nothing was added; selection unchanged.' :
        (result.status === 'exists' ? 'Every selected item is already in Today.' :
          'Could not save Today on this device. Nothing was added; selection unchanged.');
    }
    refreshMyWorkView();
  });
  document.querySelectorAll('[data-batch-defer]').forEach(button => button.addEventListener('click', () => {
    const ids = new Set(workSelection.snapshot().ids);
    const selectedItems = lastMyWork.filter(item => ids.has(workSelection.identity(item)));
    const until = laterWork.presetUntil(button.dataset.batchDefer);
    const result = laterWork.deferMany(selectedItems, until);
    qs('#my-work-action-status').textContent = result === 'deferred' ?
      selectedItems.length + ' items deferred until ' + fmt(until) + '; updates stay unread and Gitea is unchanged.' :
      'Could not save Later on this device. Selection unchanged.';
    if (result === 'deferred') workSelection.cancel();
    refreshMyWorkView();
  }));
  qs('#select-updates').addEventListener('click', () => {
    notificationSelection.start();
    qs('#update-selection-status').textContent = '0 of 50 selected';
    document.querySelector('[data-select-notification-id]')?.focus();
  });
  qs('#cancel-update-selection').addEventListener('click', () => {
    notificationSelection.cancel();
    qs('#select-updates').focus();
  });
  document.querySelectorAll('[data-defer-selected]').forEach(button => button.addEventListener('click', () => {
    const selection = notificationSelection.snapshot();
    const ids = new Set(selection.ids);
    const selectedUpdates = lastMyWork.filter(item => item.has_update && ids.has(item.notification_id));
    const until = laterWork.presetUntil(button.dataset.deferSelected);
    const result = laterWork.deferMany(selectedUpdates, until);
    qs('#my-work-action-status').textContent = result === 'deferred' ?
      selection.count + ' updates deferred until ' + fmt(until) + '; work stays unread and unchanged in Gitea.' :
      'Could not save Later on this device. Selection unchanged.';
    if (result === 'deferred') notificationSelection.cancel();
    refreshMyWorkView();
  }));
  qs('#bulk-mark-read').addEventListener('click', async () => {
    const selection = notificationSelection.snapshot();
    if (!selection.ids.length || bulkMarkPending) return;
    if (!bulkConfirmationPending) {
      bulkConfirmationPending = true;
      qs('#my-work-action-status').textContent = 'Confirm to mark only the selected updates read.';
      renderMyWork();
      return;
    }
    bulkConfirmationPending = false;
    bulkMarkPending = true;
    renderMyWork();
    const result = await bulkNotificationAcknowledger.acknowledge(lastMyWork, selection.ids);
    if (result) {
      const marked = new Set(result.marked);
      lastNotifications = lastNotifications.filter(item => !marked.has(item.id));
      notificationSelection.retain(result.failed);
      if (!result.failed.length) notificationSelection.cancel();
    }
    bulkMarkPending = false;
    renderMyWork();
    (document.querySelector('[data-select-notification-id]') || qs('#select-updates'))?.focus();
  });
  document.querySelectorAll('[data-work-filter]').forEach(button => {
    button.setAttribute('aria-pressed', String(button.dataset.workFilter === selectedWorkFilter));
    button.addEventListener('click', () => {
      selectWorkQueue(button.dataset.workFilter);
    });
  });
  function updateQueueFinder(matches, loaded, incomplete) {
    const activeQueue = qs('[data-work-filter="' + selectedWorkFilter + '"]');
    const queueLabel = activeQueue?.firstChild?.textContent?.trim() || 'work';
    qs('#queue-find-label').textContent = queueLabel;
    qs('#clear-queue-find').hidden = !queueFindQuery;
    qs('#search-older-work').hidden = !queueFindQuery || matches > 0 || !incomplete;
    qs('#queue-find-status').textContent = queueFindQuery ?
      (matches + (matches === 1 ? ' match' : ' matches') + ' in ' + queueLabel +
        (incomplete ? ' among loaded work.' : '.')) : '';
  }
  qs('#queue-finder').addEventListener('submit', event => event.preventDefault());
  qs('#queue-find-input').addEventListener('input', event => {
    queueFindQuery = event.target.value;
    renderMyWork();
  });
  qs('#clear-queue-find').addEventListener('click', () => {
    queueFindQuery = '';
    qs('#queue-find-input').value = '';
    renderMyWork();
    qs('#queue-find-input').focus();
  });
  qs('#search-older-work').addEventListener('click', () => {
    const notificationButton = qs('#load-more-notifications');
    const workButton = qs('#load-more-work');
    const target = selectedWorkFilter === 'update' ? notificationButton : workButton;
    if (!target || target.hidden || target.disabled) return;
    qs('#queue-find-status').textContent = 'Searching older ' +
      (selectedWorkFilter === 'update' ? 'updates…' : 'work…');
    target.click();
  });
  function selectWorkQueue(filter, { preserveRoute = false } = {}) {
    const button = qs('[data-work-filter="' + filter + '"]');
    if (!button) return false;
    const leavingUpdates = selectedWorkFilter === 'update' && filter !== 'update';
    selectedWorkFilter = filter;
    if (leavingUpdates && notificationSelection.snapshot().active) notificationSelection.cancel();
    if (workSelection.snapshot().active) workSelection.cancel();
    savedWorkFilter = selectedWorkFilter;
    launchFilterResolved = true;
    try {
      sessionStorage.setItem(WORK_FILTER_KEY, selectedWorkFilter);
    } catch (e) {}
    document.querySelectorAll('[data-work-filter]').forEach(item =>
      item.setAttribute('aria-pressed', String(item === button))
    );
    const selectedCount = button.querySelector('[data-work-count]').textContent;
    qs('#active-work-queue').textContent = button.firstChild.textContent.trim() + ' (' + selectedCount + ')';
    renderMyWork();
    updateWorkSessionActions();
    updateWorkPaginationControls();
    if (selectedWorkFilter === 'agenda') completeAgendaIssues();
    if (!preserveRoute) workRoute.queue(filter);
    return true;
  }
  async function openWorkQueueRoute(filter, action = null) {
    if (!selectWorkQueue(filter, { preserveRoute:true })) return;
    qs('#my-work').scrollIntoView({block:'start'});
    qs('#my-work').focus();
    if (action !== 'protect-today') return;
    await completeAgendaIssues();
    if (workPagination.issue?.has_more) {
      qs('#my-work-action-status').textContent =
        'Protect Today needs all assigned deadlines. Retry when connected.';
      return;
    }
    const proposal = protectToday.propose({
      agenda:agendaMyWork(activeMyWork), today:todayMyWork,
      identity:item => todayWork.identity(item), limit:todayWork.limit,
    });
    if (!proposal.protected.length) {
      qs('#protect-today-status').textContent = 'No overdue or due-today work needs protection.';
      return;
    }
    pendingProtectToday = proposal;
    openPlanToday(qs('#protect-today'));
  }
  qs('#work-milestone-filter').addEventListener('change', event => {
    selectedWorkMilestone = event.target.value;
    try { sessionStorage.setItem(WORK_MILESTONE_KEY, selectedWorkMilestone); }
    catch (e) {}
    renderMyWork();
    if (workSession.active()) workSession.reconcile();
  });
  let pushController = null;
  for (const selector of [
    qs('#push-deadline-hour'), qs('#device-setup-deadline-hour'),
    qs('#push-start-day-hour'), qs('#device-setup-start-day-hour'),
  ]) {
    for (let hour = 0; hour < 24; hour += 1) {
      const option = document.createElement('option');
      option.value = String(hour);
      option.textContent = `${String(hour).padStart(2, '0')}:00`;
      selector.appendChild(option);
    }
    selector.value = '9';
  }
  qs('#push-deadline-hour').addEventListener('change', event => {
    qs('#device-setup-deadline-hour').value = event.target.value;
    if (qs('#push-deadlines').checked) pushController?.changeDeadline();
  });
  qs('#device-setup-deadline-hour').addEventListener('change', event => {
    qs('#push-deadline-hour').value = event.target.value;
  });
  qs('#push-deadline-days').addEventListener('change', event => {
    qs('#device-setup-deadline-days').value = event.target.value;
    if (qs('#push-deadlines').checked) pushController?.changeDeadline();
  });
  qs('#device-setup-deadline-days').addEventListener('change', event => {
    qs('#push-deadline-days').value = event.target.value;
  });
  qs('#push-start-day-hour').addEventListener('change', event => {
    qs('#device-setup-start-day-hour').value = event.target.value;
    if (qs('#push-start-day').checked) pushController?.changeStartDay();
  });
  qs('#device-setup-start-day-hour').addEventListener('change', event => {
    qs('#push-start-day-hour').value = event.target.value;
  });
  let pushControllerReady = Promise.resolve(null);
  if ('serviceWorker' in navigator) {
    pushControllerReady = navigator.serviceWorker.register('service-worker.js').then(async () => {
      await issueCaptureFeatures.load('push-notifications');
      const controller = createPushNotifications({
        control:qs('#push-updates'),
        status:qs('#push-update-status'),
        testControl:qs('#push-test'),
        deadlineControl:qs('#push-deadlines'),
        deadlineStatus:qs('#push-deadline-status'),
        deadlineHour:qs('#push-deadline-hour'),
        deadlineDays:qs('#push-deadline-days'),
        startDayControl:qs('#push-start-day'),
        startDayStatus:qs('#push-start-day-status'),
        startDayHour:qs('#push-start-day-hour'),
        deadlineSnooze:qs('#deadline-snooze'),
        deadlineSnoozeStatus:qs('#deadline-snooze-status'),
        deadlineSnoozeReview:qs('#review-snoozed-deadlines'),
        onReviewDeadlines:() => {
          window.location.hash = '#/my-work/agenda';
          setTimeout(() => {
            const protect = qs('#protect-today');
            if (!protect.closest('[hidden]')) protect.click();
          }, 0);
        },
        notification:window.Notification,
        serviceWorker:navigator.serviceWorker,
        fetchJson:fetchReviewJson,
      });
      await controller.init();
      pushController = controller;
      qs('#device-setup-deadline-hour').value = qs('#push-deadline-hour').value;
      qs('#device-setup-deadline-days').value = qs('#push-deadline-days').value;
      qs('#device-setup-start-day-hour').value = qs('#push-start-day-hour').value;
      return controller;
    }).catch(error => {
      qs('#push-updates').disabled = true;
      qs('#push-update-status').textContent = 'Update notification settings unavailable.';
      return null;
    });
  } else {
    qs('#push-updates').disabled = true;
    qs('#push-update-status').textContent = 'This browser does not support update notifications.';
  }
  qs('#device-setup-start-day').addEventListener('click', async () => {
    const controller = await pushControllerReady;
    if (!controller) return;
    qs('#push-start-day-hour').value = qs('#device-setup-start-day-hour').value;
    qs('#push-start-day').checked = true;
    await controller.changeStartDay();
    qs('#device-setup-start-day-status').textContent = qs('#push-start-day-status').textContent;
  });
  let deferredInstallPrompt = null;
  window.addEventListener('beforeinstallprompt', event => {
    event.preventDefault();
    deferredInstallPrompt = event;
  });
  let deviceSetup = null;
  async function ensureDeviceSetup() {
    if (deviceSetup) return deviceSetup;
    await issueCaptureFeatures.load('device-setup');
    const isIosDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
      (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
    const installApp = createInstallApp({
      window, initialPrompt:deferredInstallPrompt,
      card:qs('#install-app-card'), installButton:qs('#install-app'),
      dismissButton:qs('#dismiss-install-app'), guidance:qs('#install-app-guidance'),
      status:qs('#install-app-status'), storage:localStorage,
      isStandalone:() => window.matchMedia('(display-mode: standalone)').matches || navigator.standalone === true,
      isIosSafari:() => isIosDevice && /Safari/.test(navigator.userAgent) && !/CriOS|FxiOS|EdgiOS|OPiOS/.test(navigator.userAgent),
    });
    installApp.start();
    const deviceStorage = createDeviceStorage.mount(document);
    await deviceStorage.start();
    deviceSetup = createMobileDeviceSetup.mount({
      document, installApp, promptStorage:localStorage,
      timerView,
      offlineAvailable:() => offlineStorageReady,
      offlineEnabled:() => offlineWorkStore.enabled(),
      enableOffline:() => setOfflineWorkEnabled(true),
      storageProtectionReadiness:() => deviceStorage.persistenceReadiness(),
      protectStorage:() => deviceStorage.requestPersistence(),
      notificationReadiness:() => pushController?.notificationReadiness()
        || {state:'unavailable', detail:'Update notifications are unavailable.'},
      enablePush:async () => {
        const controller = await pushControllerReady;
        if (!controller) return;
        if (controller.notificationReadiness().state === 'blocked') {
          await controller.recoverPermission('updates');
          return;
        }
        qs('#push-updates').checked = true;
        await controller.change();
      },
      deadlineReadiness:() => pushController?.deadlineReadiness()
        || {state:'unavailable', detail:'Deadline reminders are unavailable.'},
      enableDeadline:async () => {
        const controller = await pushControllerReady;
        if (!controller) return;
        qs('#push-deadline-hour').value = qs('#device-setup-deadline-hour').value;
        qs('#push-deadline-days').value = qs('#device-setup-deadline-days').value;
        if (controller.deadlineReadiness().state === 'blocked') {
          await controller.recoverPermission('deadline');
          return;
        }
        await controller.enableDeadline();
      },
    });
    await deviceSetup.start();
    return deviceSetup;
  }
  qs('#open-device-setup').addEventListener('click', async event => {
    if (!deviceSetup) await (await ensureDeviceSetup()).open(event);
  });
  pushControllerReady.then(ensureDeviceSetup).catch(console.warn);
  await load();
  await appShortcut.run();
  contextPoller.start();
  document.addEventListener('visibilitychange', () => {
    contextPoller.setVisible(!document.hidden);
    if (!document.hidden) deviceSetup?.render();
  });

  function widgetTick() { const el=qs('#widget-clock'); if(el) el.textContent = fmt(new Date()); }
  setInterval(widgetTick, 1000);
})();
