@starlove/orbit 1.3.4 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/Dockerfile +2 -1
  2. package/README.md +10 -9
  3. package/SKILL-ORBIT.md +41 -17
  4. package/dist/full/fonts/Chakra_Petch/ChakraPetch-Bold.ttf +0 -0
  5. package/dist/full/fonts/Chakra_Petch/ChakraPetch-BoldItalic.ttf +0 -0
  6. package/dist/full/fonts/Chakra_Petch/ChakraPetch-Italic.ttf +0 -0
  7. package/dist/full/fonts/Chakra_Petch/ChakraPetch-Light.ttf +0 -0
  8. package/dist/full/fonts/Chakra_Petch/ChakraPetch-LightItalic.ttf +0 -0
  9. package/dist/full/fonts/Chakra_Petch/ChakraPetch-Medium.ttf +0 -0
  10. package/dist/full/fonts/Chakra_Petch/ChakraPetch-MediumItalic.ttf +0 -0
  11. package/dist/full/fonts/Chakra_Petch/ChakraPetch-Regular.ttf +0 -0
  12. package/dist/full/fonts/Chakra_Petch/ChakraPetch-SemiBold.ttf +0 -0
  13. package/dist/full/fonts/Chakra_Petch/ChakraPetch-SemiBoldItalic.ttf +0 -0
  14. package/dist/full/fonts/Chakra_Petch/OFL.txt +93 -0
  15. package/dist/full/fonts/Inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
  16. package/dist/full/fonts/Inter/Inter-VariableFont_opsz,wght.ttf +0 -0
  17. package/dist/full/fonts/Inter/OFL.txt +93 -0
  18. package/dist/full/fonts/Inter/README.txt +118 -0
  19. package/dist/full/fonts/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
  20. package/dist/full/fonts/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf +0 -0
  21. package/dist/full/fonts/JetBrains_Mono/OFL.txt +93 -0
  22. package/dist/full/fonts/JetBrains_Mono/README.txt +79 -0
  23. package/dist/full/fonts/OpenRing-Regular.ttf +0 -0
  24. package/dist/full/fonts/Open_Sans/OFL.txt +93 -0
  25. package/dist/full/fonts/Open_Sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  26. package/dist/full/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
  27. package/dist/full/fonts/Open_Sans/README.txt +100 -0
  28. package/dist/full/fonts/Orbitron/OFL.txt +93 -0
  29. package/dist/full/fonts/Orbitron/Orbitron-VariableFont_wght.ttf +0 -0
  30. package/dist/full/fonts/Orbitron/README.txt +68 -0
  31. package/dist/full/fonts/Rajdhani/OFL.txt +93 -0
  32. package/dist/full/fonts/Rajdhani/Rajdhani-Bold.ttf +0 -0
  33. package/dist/full/fonts/Rajdhani/Rajdhani-Light.ttf +0 -0
  34. package/dist/full/fonts/Rajdhani/Rajdhani-Medium.ttf +0 -0
  35. package/dist/full/fonts/Rajdhani/Rajdhani-Regular.ttf +0 -0
  36. package/dist/full/fonts/Rajdhani/Rajdhani-SemiBold.ttf +0 -0
  37. package/dist/full/fonts/runescape-uf.ttf +0 -0
  38. package/dist/full/index.html +137 -27
  39. package/dist/full/js/app.62905fcb.js +952 -0
  40. package/dist/full/js/app.62905fcb.js.map +7 -0
  41. package/dist/full/styles.4e60d824.css +1 -0
  42. package/dist/full/version.json +2 -2
  43. package/docs/AGENT_PROTOCOL.md +20 -13
  44. package/docs/ORBIT_DISPATCH.md +73 -38
  45. package/docs/UPDATING.md +114 -0
  46. package/package.json +5 -7
  47. package/public/fonts/Chakra_Petch/ChakraPetch-Bold.ttf +0 -0
  48. package/public/fonts/Chakra_Petch/ChakraPetch-BoldItalic.ttf +0 -0
  49. package/public/fonts/Chakra_Petch/ChakraPetch-Italic.ttf +0 -0
  50. package/public/fonts/Chakra_Petch/ChakraPetch-Light.ttf +0 -0
  51. package/public/fonts/Chakra_Petch/ChakraPetch-LightItalic.ttf +0 -0
  52. package/public/fonts/Chakra_Petch/ChakraPetch-Medium.ttf +0 -0
  53. package/public/fonts/Chakra_Petch/ChakraPetch-MediumItalic.ttf +0 -0
  54. package/public/fonts/Chakra_Petch/ChakraPetch-Regular.ttf +0 -0
  55. package/public/fonts/Chakra_Petch/ChakraPetch-SemiBold.ttf +0 -0
  56. package/public/fonts/Chakra_Petch/ChakraPetch-SemiBoldItalic.ttf +0 -0
  57. package/public/fonts/Chakra_Petch/OFL.txt +93 -0
  58. package/public/fonts/Inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
  59. package/public/fonts/Inter/Inter-VariableFont_opsz,wght.ttf +0 -0
  60. package/public/fonts/Inter/OFL.txt +93 -0
  61. package/public/fonts/Inter/README.txt +118 -0
  62. package/public/fonts/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
  63. package/public/fonts/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf +0 -0
  64. package/public/fonts/JetBrains_Mono/OFL.txt +93 -0
  65. package/public/fonts/JetBrains_Mono/README.txt +79 -0
  66. package/public/fonts/OpenRing-Regular.ttf +0 -0
  67. package/public/fonts/Open_Sans/OFL.txt +93 -0
  68. package/public/fonts/Open_Sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  69. package/public/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
  70. package/public/fonts/Open_Sans/README.txt +100 -0
  71. package/public/fonts/Orbitron/OFL.txt +93 -0
  72. package/public/fonts/Orbitron/Orbitron-VariableFont_wght.ttf +0 -0
  73. package/public/fonts/Orbitron/README.txt +68 -0
  74. package/public/fonts/Rajdhani/OFL.txt +93 -0
  75. package/public/fonts/Rajdhani/Rajdhani-Bold.ttf +0 -0
  76. package/public/fonts/Rajdhani/Rajdhani-Light.ttf +0 -0
  77. package/public/fonts/Rajdhani/Rajdhani-Medium.ttf +0 -0
  78. package/public/fonts/Rajdhani/Rajdhani-Regular.ttf +0 -0
  79. package/public/fonts/Rajdhani/Rajdhani-SemiBold.ttf +0 -0
  80. package/public/fonts/runescape-uf.ttf +0 -0
  81. package/public/index.html +135 -25
  82. package/public/js/artifact-drawer.js +79 -0
  83. package/public/js/board-export.js +161 -0
  84. package/public/js/board-menu.js +219 -17
  85. package/public/js/card-actions.js +1 -1
  86. package/public/js/create-card.js +60 -23
  87. package/public/js/drawer.js +164 -4
  88. package/public/js/font-preference.js +229 -0
  89. package/public/js/format.js +0 -10
  90. package/public/js/icons.js +16 -0
  91. package/public/js/kanban.js +123 -1
  92. package/public/js/local-backend.js +31 -4
  93. package/public/js/main.js +7 -1
  94. package/public/js/modal.js +3 -1
  95. package/public/js/panel.js +58 -0
  96. package/public/js/settings-tabs.js +1 -1
  97. package/public/js/settings.js +606 -275
  98. package/public/js/sse.js +3 -0
  99. package/public/js/state.js +1 -1
  100. package/public/js/text-editing.js +128 -0
  101. package/public/js/ticket-detail.js +377 -148
  102. package/public/js/ticket-typeahead.js +49 -0
  103. package/public/js/toast.js +19 -4
  104. package/public/js/topbar-notes.js +3 -3
  105. package/public/js/typeahead.js +206 -0
  106. package/public/js/update-check.js +58 -0
  107. package/public/styles.css +5455 -3538
  108. package/src/cli/orbit.js +9 -5
  109. package/src/core/agent.js +12 -4
  110. package/src/core/agents-md.js +3 -3
  111. package/src/core/artifacts.js +149 -0
  112. package/src/core/board.js +3 -2
  113. package/src/core/boards.js +0 -1
  114. package/src/core/css-bundle.js +1 -0
  115. package/src/core/db.js +6 -0
  116. package/src/core/dispatch.js +344 -34
  117. package/src/core/http.js +9 -2
  118. package/src/core/paths.js +26 -2
  119. package/src/core/router.js +33 -0
  120. package/src/core/search.js +3 -2
  121. package/src/core/snapshots.js +10 -5
  122. package/src/core/tickets.js +34 -3
  123. package/src/core/util.js +3 -2
  124. package/src/core/version-check.js +154 -0
  125. package/src/mcp/orbit-client.js +18 -2
  126. package/src/mcp-server.js +19 -14
  127. package/src/server.js +28 -3
  128. package/dist/full/js/app.fb7767dc.js +0 -742
  129. package/dist/full/js/app.fb7767dc.js.map +0 -7
  130. package/dist/full/styles.bbc542f5.css +0 -1
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["public/js/dom.js", "public/js/motion-preference.js", "public/js/theme-preference.js", "public/js/settings-tabs.js", "public/js/state.js", "public/js/format.js", "public/js/icons.js", "public/js/toast.js", "public/js/transport.js", "public/js/api.js", "public/js/text-editing.js", "public/js/drawer.js", "public/js/card-actions.js", "public/js/unread.js", "public/js/kanban.js", "public/js/config.js", "public/js/font-preference.js", "public/js/board-export.js", "public/js/update-check.js", "public/js/settings.js", "public/js/actor-labels.js", "public/js/artifact-drawer.js", "public/js/panel.js", "public/js/typeahead.js", "public/js/ticket-typeahead.js", "public/js/ticket-detail.js", "public/js/sse.js", "public/js/topbar-notes.js", "public/js/app.js", "public/js/create-card.js", "public/js/board-menu.js", "public/js/url-routes.js", "public/js/router.js", "public/js/starscape.js", "public/js/main.js", "public/js/search.js", "public/js/modal.js", "public/js/help-menu.js"],
4
+ "sourcesContent": ["// Cached DOM references queried once at module-load time. Importing this\n// module assumes the body has been parsed (the script tag is at the bottom\n// of <body> and uses type=\"module\", so this holds).\n\nexport const $ = (selector) => document.querySelector(selector);\n\nexport const boardMenuBtn = $(\"#boardMenuBtn\");\nexport const boardFlyout = $(\"#boardFlyout\");\nexport const kanban = $(\"#kanban\");\nexport const drawer = $(\"#drawer\");\nexport const drawerInner = $(\"#drawerInner\");\nexport const drawerBackdrop = $(\"#drawerBackdrop\");\nexport const createFlyout = $(\"#createFlyout\");\nexport const createFlyoutInner = $(\"#createFlyoutInner\");\nexport const createFlyoutBackdrop = $(\"#createFlyoutBackdrop\");\nexport const searchInput = $(\"#searchInput\");\nexport const searchResults = $(\"#searchResults\");\nexport const themeToggle = $(\"#themeToggle\");\nexport const themeIcon = $(\"#themeIcon\");\n", "export const REDUCE_MOTION_STORAGE_KEY = \"mab_reduce_motion\";\n\nfunction safeStorage(storage) {\n try {\n return storage ?? globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nfunction defaultMediaMatcher(query) {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\"\n ? window.matchMedia(query)\n : { matches: false };\n}\n\nexport function storedReducedMotionPreference(storage = safeStorage()) {\n const store = safeStorage(storage);\n const value = store?.getItem?.(REDUCE_MOTION_STORAGE_KEY);\n if (value === \"true\") return true;\n if (value === \"false\") return false;\n return null;\n}\n\nexport function browserPrefersReducedMotion(mediaMatcher = defaultMediaMatcher) {\n try {\n return !!mediaMatcher(\"(prefers-reduced-motion: reduce)\")?.matches;\n } catch {\n return false;\n }\n}\n\nexport function effectiveReducedMotionPreference({ storage = safeStorage(), mediaMatcher = defaultMediaMatcher } = {}) {\n const stored = storedReducedMotionPreference(storage);\n return stored ?? browserPrefersReducedMotion(mediaMatcher);\n}\n\nexport function setReducedMotionPreference(reduce, storage = safeStorage()) {\n const store = safeStorage(storage);\n const value = reduce ? \"true\" : \"false\";\n store?.setItem?.(REDUCE_MOTION_STORAGE_KEY, value);\n return reduce;\n}\n\nexport function applyReducedMotionPreference({\n doc = globalThis.document,\n storage = safeStorage(),\n mediaMatcher = defaultMediaMatcher\n} = {}) {\n // Starscape v3 `data-motion` contract (three-state; shared with the\n // ui-system-v3 package and ss-nebula). Replaces the legacy two-state\n // `data-reduced-motion=\"reduce|allow\"`:\n // \u2022 stored reduce \u2192 data-motion=\"reduce\" (always reduce)\n // \u2022 stored allow \u2192 data-motion=\"full\" (ignore OS reduce)\n // \u2022 no stored pref \u2192 no attribute (follow OS prefers-reduced-motion)\n const root = doc?.documentElement;\n const stored = storedReducedMotionPreference(storage);\n if (root) {\n if (stored === true) root.setAttribute(\"data-motion\", \"reduce\");\n else if (stored === false) root.setAttribute(\"data-motion\", \"full\");\n else root.removeAttribute(\"data-motion\");\n }\n return effectiveReducedMotionPreference({ storage, mediaMatcher });\n}\n", "export const THEME_STORAGE_KEY = \"mab_theme\";\nexport const THEME_CHANGE_EVENT = \"orbit:theme-change\";\n\nconst THEMES = new Set([\"light\", \"dark\"]);\n\nfunction safeStorage(storage) {\n try {\n return storage ?? globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nfunction safeDocument(doc) {\n try {\n return doc ?? globalThis.document ?? null;\n } catch {\n return null;\n }\n}\n\nfunction safeEventTarget(eventTarget) {\n try {\n return eventTarget ?? globalThis.window ?? null;\n } catch {\n return null;\n }\n}\n\nexport function normalizeTheme(theme) {\n return THEMES.has(theme) ? theme : \"light\";\n}\n\nexport function storedThemePreference(storage = safeStorage()) {\n const store = safeStorage(storage);\n const value = store?.getItem?.(THEME_STORAGE_KEY);\n return THEMES.has(value) ? value : null;\n}\n\nfunction systemTheme() {\n try {\n return globalThis.matchMedia?.(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n } catch {\n return \"light\";\n }\n}\n\nexport function currentTheme({ doc = safeDocument(), storage = safeStorage() } = {}) {\n const rootTheme = safeDocument(doc)?.documentElement?.getAttribute?.(\"data-theme\");\n if (THEMES.has(rootTheme)) return rootTheme;\n return storedThemePreference(storage) ?? systemTheme();\n}\n\nexport function applyStoredThemePreference({\n doc = safeDocument(),\n storage = safeStorage()\n} = {}) {\n const theme = storedThemePreference(storage) ?? systemTheme();\n safeDocument(doc)?.documentElement?.setAttribute?.(\"data-theme\", theme);\n return theme;\n}\n\nexport function setThemePreference(theme, {\n doc = safeDocument(),\n storage = safeStorage(),\n eventTarget = safeEventTarget(),\n notify = true\n} = {}) {\n const next = normalizeTheme(theme);\n safeDocument(doc)?.documentElement?.setAttribute?.(\"data-theme\", next);\n safeStorage(storage)?.setItem?.(THEME_STORAGE_KEY, next);\n\n if (notify) {\n dispatchThemeChange(next, eventTarget);\n }\n\n return next;\n}\n\nexport function toggleThemePreference(options = {}) {\n const next = currentTheme(options) === \"dark\" ? \"light\" : \"dark\";\n return setThemePreference(next, options);\n}\n\nfunction dispatchThemeChange(theme, eventTarget = safeEventTarget()) {\n const target = safeEventTarget(eventTarget);\n if (typeof target?.dispatchEvent !== \"function\") return;\n\n if (typeof CustomEvent === \"function\") {\n target.dispatchEvent(new CustomEvent(THEME_CHANGE_EVENT, { detail: { theme } }));\n return;\n }\n\n target.dispatchEvent({ type: THEME_CHANGE_EVENT, detail: { theme } });\n}\n", "/** Settings drawer tab ids \u2014 must match URL segments `#/b/\u2026/settings/:tab` and `settings.js` tab config. */\nexport const SETTINGS_TAB_IDS = new Set([\"lanes\", \"appearance\", \"ai\", \"notes\", \"journal\", \"data\", \"archive\"]);\n\nexport function normalizeSettingsTab(raw) {\n if (!raw || !SETTINGS_TAB_IDS.has(raw)) return \"lanes\";\n return raw;\n}\n", "import { normalizeSettingsTab } from \"./settings-tabs.js\";\n\n// Mutable application state plus board/ticket query helpers. The `state`\n// object is the single source of truth for \"what view is showing\" and\n// \"what data did the bootstrap give us\"; modules read it freely and mutate\n// it in-place. The query helpers wrap the most common slices.\n\nexport const state = {\n data: null,\n /** Currently selected board id. Single-board UI; this points at the active\n * board in `state.data.boards`. */\n boardId: \"\",\n /** URL-facing board identifier. Routes use slugs; API calls keep using ids. */\n boardSlug: \"\",\n selectedTicketId: \"\",\n expandedCardIds: new Set(),\n /** \"empty\" | \"ticket\" | \"settings\" \u2014 drives the main right overlay drawer (not the New flyout). */\n detailMode: \"empty\",\n /** \"lanes\" | \"ai\" | \"data\" | \"notes\" | \"journal\" \u2014 which Settings tab is active. */\n settingsTab: normalizeSettingsTab(localStorage.getItem(\"mab_settings_tab\")),\n /** Whether to render the priority pill on kanban / related cards. The detail\n * drawer header always shows it. Default on; user can toggle it from the\n * Lanes settings tab. */\n showPriority: localStorage.getItem(\"mab_show_priority\") !== \"false\",\n eventSource: null\n};\n\nexport function getSettingsTab() {\n return normalizeSettingsTab(state.settingsTab || localStorage.getItem(\"mab_settings_tab\"));\n}\n\nexport function syncBoardSelection() {\n if (!state.data) return;\n const boards = state.data.boards || [];\n let board = state.boardId ? boards.find((b) => b.id === state.boardId) : null;\n if (!board && state.boardSlug) {\n board = boards.find((b) => b.slug === state.boardSlug) || boards.find((b) => b.id === state.boardSlug);\n }\n if (!board) {\n const activeBoardId = state.data.active_board_id;\n board = boards.find((b) => b.id === activeBoardId) || boards[0] || null;\n }\n state.boardId = board?.id || \"\";\n state.boardSlug = board?.slug || \"\";\n}\n\nexport function currentBoard() {\n return (state.data?.boards || []).find((b) => b.id === state.boardId);\n}\n\n/** Labels defined for the current board (from bootstrap), for autocomplete. */\nexport function boardLabelCatalog() {\n if (!state.boardId) return [];\n return (state.data?.labels || []).filter((label) => label.board_id === state.boardId);\n}\n\nexport function statesForProject() {\n return state.data.states.filter((item) => item.board_id === state.boardId);\n}\n\nexport function isAiReadyState(item) {\n return item?.role === \"ai_ready\" || item?.name === \"AI Ready\";\n}\n\nexport function visibleStatesForProject() {\n const states = statesForProject();\n if (currentBoard()?.ai_enabled !== 0) return states;\n return states.filter((item) => !isAiReadyState(item));\n}\n\nexport function selectableStatesForProject(currentStateId = \"\") {\n const states = statesForProject();\n if (currentBoard()?.ai_enabled !== 0) return states;\n return states.filter((item) => !isAiReadyState(item) || item.id === currentStateId);\n}\n\nexport function ticketsForProject() {\n return state.data.tickets.filter((item) => item.board_id === state.boardId);\n}\n\nfunction compactTicketForBoard(ticket) {\n if (!ticket) return null;\n return {\n id: ticket.id,\n board_id: ticket.board_id,\n board_slug: ticket.board_slug,\n number: ticket.number,\n title: ticket.title,\n type: ticket.type,\n state_name: ticket.state_name,\n state_role: ticket.state_role,\n priority: ticket.priority\n };\n}\n\nfunction refreshBoardTicketDerivatives(boardId) {\n if (!state.data?.tickets) return;\n const boardTickets = state.data.tickets.filter((ticket) => ticket.board_id === boardId && !ticket.archived_at);\n const ticketById = new Map(boardTickets.map((ticket) => [ticket.id, ticket]));\n const childCountByParent = new Map();\n for (const ticket of boardTickets) {\n if (!ticket.parent_ticket_id) continue;\n childCountByParent.set(ticket.parent_ticket_id, (childCountByParent.get(ticket.parent_ticket_id) || 0) + 1);\n }\n for (const ticket of boardTickets) {\n ticket.parent_ticket = ticket.parent_ticket_id ? compactTicketForBoard(ticketById.get(ticket.parent_ticket_id)) : null;\n ticket.child_count = childCountByParent.get(ticket.id) || 0;\n }\n}\n\n/** Merge a ticket returned by a mutation/context endpoint into the bootstrap cache.\n * Keeps drawer edits responsive without paying for a full /api/bootstrap reload. */\nexport function upsertTicket(updatedTicket) {\n if (!state.data?.tickets || !updatedTicket?.id) return;\n const index = state.data.tickets.findIndex((ticket) => ticket.id === updatedTicket.id);\n const previous = index >= 0 ? state.data.tickets[index] : {};\n const merged = {\n ...previous,\n ...updatedTicket,\n labels: updatedTicket.labels || previous.labels || [],\n comment_count: updatedTicket.comment_count ?? previous.comment_count ?? 0,\n child_count: updatedTicket.child_count ?? previous.child_count ?? 0,\n parent_ticket: updatedTicket.parent_ticket || previous.parent_ticket || null\n };\n if (index >= 0) state.data.tickets.splice(index, 1, merged);\n else state.data.tickets.push(merged);\n state.data.tickets.sort((a, b) => String(b.updated_at || \"\").localeCompare(String(a.updated_at || \"\")) || String(a.id).localeCompare(String(b.id)));\n refreshBoardTicketDerivatives(merged.board_id || state.boardId);\n}\n", "// Pure string helpers: escape, dates, ticket/type/priority labels.\n// Zero side effects, no imports \u2014 safe to import from anywhere.\n\nexport function escapeHtml(value) {\n return String(value ?? \"\")\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#039;\");\n}\n\n// UTF-8 bytes mis-decoded as CP-437 (the typical Windows-tmux artifact).\n// Ported from a local fix-newlines utility \u2014 every entry is [mojibake sequence,\n// what it should have been]. Long sequences first so shorter prefixes do not\n// eat them.\nconst MOJIBAKE_REPLACEMENTS = [\n // General Punctuation (UTF-8 E2 80 XX \u2192 CP-437 \"\u0393\u00C7\" + glyph)\n [\"\u0393\u00C7\u00F4\", \"\u2013\"],\n [\"\u0393\u00C7\u00F6\", \"\u2014\"],\n [\"\u0393\u00C7\u00A3\", '\"'],\n [\"\u0393\u00C7\u00A5\", '\"'],\n [\"\u0393\u00C7\u00FF\", \"'\"],\n [\"\u0393\u00C7\u00D6\", \"'\"],\n [\"\u0393\u00C7\u00AA\", \"\u2026\"],\n [\"\u0393\u00C7\u00F3\", \"\u2022\"],\n [\"\u0393\u00C7\u2591\", \"\u2030\"],\n [\"\u0393\u00C7\u2563\", \"\u2039\"],\n [\"\u0393\u00C7\u2551\", \"\u203A\"],\n\n // Box drawing \u2014 light (UTF-8 E2 94 XX \u2192 CP-437 \"\u0393\u00F6\" + glyph)\n [\"\u0393\u00F6\u00C7\", \"\u2500\"],\n [\"\u0393\u00F6\u00E9\", \"\u2502\"],\n [\"\u0393\u00F6\u00EE\", \"\u250C\"],\n [\"\u0393\u00F6\u00C9\", \"\u2510\"],\n [\"\u0393\u00F6\u00F6\", \"\u2514\"],\n [\"\u0393\u00F6\u00FF\", \"\u2518\"],\n [\"\u0393\u00F6\u00A3\", \"\u251C\"],\n [\"\u0393\u00F6\u00F1\", \"\u2524\"],\n [\"\u0393\u00F6\u00BC\", \"\u252C\"],\n [\"\u0393\u00F6\u2524\", \"\u2534\"],\n [\"\u0393\u00F6\u255D\", \"\u253C\"],\n\n // Box drawing \u2014 heavy/double + rounded corners (UTF-8 E2 95 XX \u2192 \"\u0393\u00F2\" + glyph)\n [\"\u0393\u00F2\u00C9\", \"\u2550\"],\n [\"\u0393\u00F2\u00E6\", \"\u2551\"],\n [\"\u0393\u00F2\u00C6\", \"\u2552\"],\n [\"\u0393\u00F2\u00F6\", \"\u2554\"],\n [\"\u0393\u00F2\u00A1\", \"\u256D\"],\n [\"\u0393\u00F2\u00AB\", \"\u256E\"],\n [\"\u0393\u00F2\u00BB\", \"\u256F\"],\n [\"\u0393\u00F2\u2591\", \"\u2570\"],\n\n // Geometric shapes (UTF-8 E2 96 XX / E2 97 XX \u2192 \"\u0393\u00FB\" / \"\u0393\u00F9\" + glyph)\n [\"\u0393\u00FB\u00E6\", \"\u2591\"],\n [\"\u0393\u00FB\u00C6\", \"\u2592\"],\n [\"\u0393\u00FB\u00F4\", \"\u2593\"],\n [\"\u0393\u00FB\u00C9\", \"\u2590\"],\n [\"\u0393\u00FB\u00EE\", \"\u258C\"],\n [\"\u0393\u00FB\u00C4\", \">\"],\n [\"\u0393\u00FB\u00E1\", \"\u25A0\"],\n [\"\u0393\u00FB\u255D\", \"\u25BC\"],\n [\"\u0393\u00F9\u00C5\", \"\u25CF\"],\n [\"\u0393\u00F9\u00EF\", \"\u25CB\"],\n\n // Misc symbols (UTF-8 E2 9A XX \u2192 \"\u0393\u00DC\" + glyph)\n [\"\u0393\u00DC\u00F2\", \"\u2695\"],\n [\"\u0393\u00DC\u00E1\", \"\u26A0\"],\n [\"\u0393\u00DC\u00ED\", \"\u26A1\"],\n [\"\u0393\u00DC\u00F4\", \"\u2693\"],\n\n // Arrows (UTF-8 E2 86 XX \u2192 \"\u0393\u00E5\" + glyph)\n [\"\u0393\u00E5\u00C9\", \"\u2190\"],\n [\"\u0393\u00E5\u00E6\", \"\u2191\"],\n [\"\u0393\u00E5\u00C6\", \"\u2192\"],\n [\"\u0393\u00E5\u00F4\", \"\u2193\"],\n [\"\u0393\u00E5\u00F6\", \"\u2194\"],\n\n // Latin-1 Supplement (UTF-8 C2 XX \u2192 CP-437 \"\u252C\" + glyph)\n [\"\u252C\u00E1\", \" \"],\n [\"\u252C\u2310\", \"\u00A9\"],\n [\"\u252C\u00AB\", \"\u00AE\"],\n [\"\u252C\u2591\", \"\u00B0\"],\n [\"\u252C\u00BA\", \"\u00A7\"],\n [\"\u252C\u2556\", \"\u00B7\"],\n\n // Stray curly quotes that survived as proper Unicode; normalize to ASCII\n // straight quotes so pasted terminal/log text stays consistent.\n [\"\u201C\", '\"'],\n [\"\u201D\", '\"'],\n [\"\u2018\", \"'\"],\n [\"\u2019\", \"'\"],\n];\n\nfunction fixMojibake(text) {\n if (!text) return text;\n let out = text;\n for (const [from, to] of MOJIBAKE_REPLACEMENTS) {\n out = out.split(from).join(to);\n }\n return out;\n}\n\n/**\n * Repair common mojibake and normalize line endings without disturbing the\n * author's indentation or soft line breaks. Use this on inbound text before\n * saving (so the DB stays clean going forward) and again before rendering (so\n * existing dirty rows display fixed without a migration).\n */\nexport function cleanText(value) {\n if (!value) return \"\";\n return fixMojibake(String(value)).replace(/\\r\\n?/g, \"\\n\");\n}\n\nexport function renderPreservedText(value) {\n return escapeHtml(cleanText(value));\n}\n\nconst SAFE_LINK_PROTOCOLS = new Set([\"http:\", \"https:\", \"mailto:\", \"tel:\"]);\n\nfunction sanitizeMarkdownUrl(value) {\n const href = String(value || \"\").trim();\n if (!href) return \"\";\n\n // Collapse control characters/whitespace before checking the scheme so inputs\n // like `java\\nscript:` or `jav\\tascript:` cannot bypass the blocklist.\n const compact = href.replace(/[\\u0000-\\u001f\\u007f\\s]+/g, \"\").toLowerCase();\n if (/^(?:javascript|data|vbscript):/.test(compact)) return \"\";\n\n const scheme = compact.match(/^([a-z][a-z0-9+.-]*):/);\n if (scheme && !SAFE_LINK_PROTOCOLS.has(`${scheme[1]}:`)) return \"\";\n\n return href;\n}\n\nfunction renderEmphasis(text) {\n let html = escapeHtml(text);\n html = html.replace(/(\\*\\*|__)(?=\\S)([\\s\\S]*?\\S)\\1/g, \"<strong>$2</strong>\");\n html = html.replace(/(\\*|_)(?=\\S)([^*_]*?\\S)\\1/g, \"<em>$2</em>\");\n return html;\n}\n\nfunction renderLinksAndEmphasis(text) {\n const linkPattern = /\\[([^\\]\\n]+)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/g;\n let html = \"\";\n let lastIndex = 0;\n let match;\n\n while ((match = linkPattern.exec(text))) {\n html += renderEmphasis(text.slice(lastIndex, match.index));\n\n const labelHtml = renderEmphasis(match[1]);\n const href = sanitizeMarkdownUrl(match[2]);\n html += href\n ? `<a href=\"${escapeHtml(href)}\" target=\"_blank\" rel=\"noopener noreferrer\">${labelHtml}</a>`\n : labelHtml;\n\n lastIndex = match.index + match[0].length;\n }\n\n html += renderEmphasis(text.slice(lastIndex));\n return html;\n}\n\nfunction renderInlineMarkdown(text) {\n const source = String(text ?? \"\");\n let html = \"\";\n let cursor = 0;\n\n while (cursor < source.length) {\n const codeStart = source.indexOf(\"`\", cursor);\n if (codeStart === -1) {\n html += renderLinksAndEmphasis(source.slice(cursor));\n break;\n }\n\n const codeEnd = source.indexOf(\"`\", codeStart + 1);\n if (codeEnd === -1) {\n html += renderLinksAndEmphasis(source.slice(cursor));\n break;\n }\n\n html += renderLinksAndEmphasis(source.slice(cursor, codeStart));\n html += `<code>${escapeHtml(source.slice(codeStart + 1, codeEnd))}</code>`;\n cursor = codeEnd + 1;\n }\n\n return html;\n}\n\nfunction renderParagraph(lines) {\n return `<p>${renderInlineMarkdown(lines.join(\"\\n\")).replaceAll(\"\\n\", \"<br>\")}</p>`;\n}\n\nfunction renderTaskItem(rawContent) {\n // GFM-style `- [ ] text` or `- [x] text`. We render as a disabled checkbox\n // followed by the inline-rendered remainder. The list itself gets a\n // `task-list` class so CSS can drop the default bullet.\n const match = rawContent.match(/^\\[( |x|X)\\]\\s+(.*)$/);\n if (!match) return null;\n const checked = match[1].toLowerCase() === \"x\";\n const body = renderInlineMarkdown(match[2].trim()).replaceAll(\"\\n\", \"<br>\");\n return {\n checked,\n html: `<input type=\"checkbox\" disabled${checked ? \" checked\" : \"\"}> ${body}`,\n };\n}\n\nexport function renderMarkdown(value) {\n // Mojibake repair runs at render time too so existing dirty rows display\n // cleanly without a backfill. cleanText also normalizes line endings.\n const source = cleanText(value);\n if (!source.trim()) return \"\";\n\n const blocks = [];\n const lines = source.split(\"\\n\");\n let paragraph = [];\n let list = null;\n let blockquote = null;\n\n const flushParagraph = () => {\n if (!paragraph.length) return;\n blocks.push(renderParagraph(paragraph));\n paragraph = [];\n };\n\n const flushList = () => {\n if (!list) return;\n const classAttr = list.taskList ? ' class=\"task-list\"' : \"\";\n blocks.push(\n `<${list.type}${classAttr}>${list.items\n .map((item) => `<li${item.taskClass ? ` class=\"${item.taskClass}\"` : \"\"}>${item.html}</li>`)\n .join(\"\")}</${list.type}>`\n );\n list = null;\n };\n\n const flushBlockquote = () => {\n if (!blockquote) return;\n blocks.push(`<blockquote>${renderMarkdown(blockquote.join(\"\\n\"))}</blockquote>`);\n blockquote = null;\n };\n\n const flushAll = () => {\n flushParagraph();\n flushList();\n flushBlockquote();\n };\n\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i];\n\n if (/^\\s*```/.test(line)) {\n flushAll();\n const codeLines = [];\n i += 1;\n while (i < lines.length && !/^\\s*```\\s*$/.test(lines[i])) {\n codeLines.push(lines[i]);\n i += 1;\n }\n blocks.push(`<pre><code>${escapeHtml(codeLines.join(\"\\n\"))}</code></pre>`);\n continue;\n }\n\n // Horizontal rule: a line of three+ dashes / asterisks / underscores.\n if (/^\\s*(?:-\\s*){3,}\\s*$/.test(line) || /^\\s*(?:\\*\\s*){3,}\\s*$/.test(line) || /^\\s*(?:_\\s*){3,}\\s*$/.test(line)) {\n flushAll();\n blocks.push(\"<hr>\");\n continue;\n }\n\n // ATX header: 1-6 # followed by a space and content.\n const header = line.match(/^\\s{0,3}(#{1,6})\\s+(.+?)\\s*#*\\s*$/);\n if (header) {\n flushAll();\n const level = header[1].length;\n blocks.push(`<h${level}>${renderInlineMarkdown(header[2])}</h${level}>`);\n continue;\n }\n\n // Blockquote: `> ...`. We collect consecutive `>` lines, strip the leading\n // marker, and recurse so quoted content can itself contain lists/headers.\n const quoteMatch = line.match(/^\\s{0,3}>\\s?(.*)$/);\n if (quoteMatch) {\n flushParagraph();\n flushList();\n if (!blockquote) blockquote = [];\n blockquote.push(quoteMatch[1]);\n continue;\n }\n if (blockquote && !line.trim()) {\n flushBlockquote();\n continue;\n }\n flushBlockquote();\n\n if (!line.trim()) {\n flushParagraph();\n flushList();\n continue;\n }\n\n const ordered = line.match(/^\\s*\\d+[.)]\\s+(.+)$/);\n const unordered = line.match(/^\\s*[-*+]\\s+(.+)$/);\n if (ordered || unordered) {\n flushParagraph();\n const type = ordered ? \"ol\" : \"ul\";\n const content = (ordered || unordered)[1].trim();\n\n let task = null;\n if (unordered) task = renderTaskItem(content);\n\n if (!list || list.type !== type || Boolean(list.taskList) !== Boolean(task)) {\n flushList();\n list = { type, items: [], taskList: Boolean(task) };\n }\n\n if (task) {\n list.items.push({\n html: task.html,\n taskClass: task.checked ? \"task-item task-item-done\" : \"task-item\",\n });\n } else {\n list.items.push({\n html: renderInlineMarkdown(content).replaceAll(\"\\n\", \"<br>\"),\n });\n }\n continue;\n }\n\n flushList();\n paragraph.push(line);\n }\n\n flushAll();\n\n return blocks.join(\"\");\n}\n\nexport function formatDate(value) {\n if (!value) return \"\";\n return new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\"\n }).format(new Date(value));\n}\n\n/** Richer timestamp for the detail pane \u201CUpdated\u201D line (refreshes after every save). */\nexport function formatDateDetail(value) {\n if (!value) return \"\";\n return new Intl.DateTimeFormat(undefined, {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n second: \"2-digit\"\n }).format(new Date(value));\n}\n\nexport function ticketLabel(ticket) {\n return `#${ticket.number}`;\n}\n\nexport function stateClassFor(ticketOrState) {\n const source =\n ticketOrState?.state_role || ticketOrState?.role || ticketOrState?.state_name || ticketOrState?.name || \"state\";\n return String(source)\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\") || \"state\";\n}\n\nexport function canonicalTicketType(type) {\n if (type === \"epic\" || type === \"feature\" || type === \"bug\" || type === \"task\") return type;\n return \"task\";\n}\n\n// Short label for dense surfaces (card pills, child-card pills).\nexport function typeLabel(type) {\n const labels = {\n epic: \"Epic\",\n feature: \"Feature\",\n task: \"Task\",\n bug: \"Bug\"\n };\n return labels[canonicalTicketType(type)] || \"Task\";\n}\n\n// Long, hierarchy-aware label for dropdowns where we have the room.\nexport function typeLabelLong(type) {\n const labels = {\n epic: \"Epic\",\n feature: \"Feature\",\n task: \"Task\",\n bug: \"Bug\"\n };\n return labels[canonicalTicketType(type)] || \"Task\";\n}\n\nexport function priorityLabel(priority) {\n const labels = {\n 0: \"MAYBE\",\n 1: \"LOW\",\n 2: \"MED\",\n 3: \"HIGH\",\n 4: \"URGENT\"\n };\n return labels[Number(priority)] || \"MED\";\n}\n\n/** Lowercase key used for CSS class targeting: `priority-maybe`, `priority-urgent`, etc. */\nexport function priorityKeyFor(priority) {\n const keys = [\"maybe\", \"low\", \"med\", \"high\", \"urgent\"];\n const n = Number(priority);\n return keys[Number.isFinite(n) ? Math.max(0, Math.min(4, n)) : 2];\n}\n\nexport function renderLabels(labels = []) {\n if (!labels.length) return \"\";\n return `\n <div class=\"labels\">\n ${labels\n .map(\n (label) =>\n `<span class=\"label\" style=\"--label-color: ${escapeHtml(label.color)}\">${escapeHtml(label.name)}</span>`\n )\n .join(\"\")}\n </div>\n `;\n}\n", "export const closeIconSvg = `\n <svg class=\"ui-icon ui-icon-x\" viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M6 6l12 12M18 6 6 18\" />\n </svg>\n`;\n\n/** Trash bin \u2014 archive / permanent delete actions (drawer header, card archive controls, toasts). */\nexport const trashIconSvg = `\n <svg class=\"ui-icon ui-icon-trash\" viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M3 6h18\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n <path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\" />\n <path d=\"M10 11v6\" />\n <path d=\"M14 11v6\" />\n </svg>\n`;\n", "// Toast notifications + small UI utilities (downloadJson, debounce).\n\nimport { escapeHtml } from \"./format.js\";\nimport { closeIconSvg, trashIconSvg } from \"./icons.js\";\n\nconst toastIcons = {\n info: `<svg viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z\" clip-rule=\"evenodd\"/></svg>`,\n success: `<svg viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\" clip-rule=\"evenodd\"/></svg>`,\n warning: `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z\" clip-rule=\"evenodd\"/></svg>`,\n error: `<svg viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\" clip-rule=\"evenodd\"/></svg>`,\n removed: trashIconSvg\n};\n\nlet toastContainer = null;\n\nfunction ensureToastContainer() {\n if (toastContainer && toastContainer.isConnected) return toastContainer;\n toastContainer = document.createElement(\"div\");\n toastContainer.className = \"toast-container\";\n document.body.append(toastContainer);\n return toastContainer;\n}\n\nexport function toast(message, type = \"info\", duration = 4000, options = {}) {\n const container = ensureToastContainer();\n\n const node = document.createElement(\"div\");\n node.className = `toast toast-${type}`;\n node.setAttribute(\"role\", \"status\");\n\n const icon = toastIcons[type];\n node.innerHTML = `<span class=\"toast-icon\">${icon}</span><span class=\"toast-msg\">${escapeHtml(message)}</span><button class=\"toast-close\" aria-label=\"Dismiss\">${closeIconSvg}</button>`;\n\n node.querySelector(\".toast-close\").addEventListener(\"click\", (event) => {\n event.stopPropagation();\n dismissToast(node);\n });\n\n // Optional whole-toast click action (e.g. \"Update available \u2192 open Settings\").\n if (typeof options.onClick === \"function\") {\n node.classList.add(\"toast-clickable\");\n node.addEventListener(\"click\", () => {\n options.onClick();\n dismissToast(node);\n });\n }\n\n container.prepend(node);\n requestAnimationFrame(() => requestAnimationFrame(() => node.classList.add(\"toast-enter\")));\n\n const timer = setTimeout(() => dismissToast(node), duration);\n node.addEventListener(\"mouseenter\", () => clearTimeout(timer));\n node.addEventListener(\"mouseleave\", () => {\n const t2 = setTimeout(() => dismissToast(node), 1500);\n node.addEventListener(\"mouseenter\", () => clearTimeout(t2), { once: true });\n });\n}\n\ntoast.info = (msg, dur) => toast(msg, \"info\", dur);\ntoast.success = (msg, dur) => toast(msg, \"success\", dur);\ntoast.warning = (msg, dur) => toast(msg, \"warning\", dur);\ntoast.error = (msg, dur) => toast(msg, \"error\", dur);\ntoast.removed = (msg, dur) => toast(msg, \"removed\", dur);\n\nfunction dismissToast(node) {\n if (node.classList.contains(\"toast-exit\")) return;\n node.classList.add(\"toast-exit\");\n node.addEventListener(\"animationend\", () => node.remove(), { once: true });\n}\n\nexport function downloadJson(filename, value) {\n const blob = new Blob([JSON.stringify(value, null, 2)], { type: \"application/json\" });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = filename;\n document.body.append(anchor);\n anchor.click();\n anchor.remove();\n URL.revokeObjectURL(url);\n}\n\nexport function debounce(fn, wait) {\n let timer = 0;\n return (...args) => {\n clearTimeout(timer);\n timer = setTimeout(() => fn(...args), wait);\n };\n}\n", "// Request transport. The full edition talks to the Orbit HTTP server; a\n// preview build will replace this module (or branch on `edition`) to dispatch\n// the same path/body shapes to a local IndexedDB backend. Keep this file\n// I/O-only \u2014 UI concerns (toasts, redirects) belong in api.js callers.\n\nexport async function request({ method = \"GET\", path, body, headers }) {\n const finalHeaders = { \"Content-Type\": \"application/json\", ...(headers || {}) };\n const response = await fetch(path, {\n method,\n headers: finalHeaders,\n body: body !== undefined ? JSON.stringify(body) : undefined\n });\n const text = await response.text();\n const payload = text ? JSON.parse(text) : {};\n if (!response.ok) {\n const error = new Error(payload.error || response.statusText);\n error.payload = payload;\n error.status = response.status;\n throw error;\n }\n return payload;\n}\n", "// Network layer. `api()` is the single fetch wrapper used everywhere; it\n// delegates raw I/O to transport.js (swappable per edition) and surfaces\n// errors as toasts. Path helpers live here because they're shared by every\n// caller regardless of transport.\n\nimport { state } from \"./state.js\";\nimport { toast } from \"./toast.js\";\nimport { request } from \"./transport.js\";\n\n/** Bootstrap for the currently selected board (server opens the right DB). */\nexport function bootstrapPath() {\n const q = state.boardId\n ? `?board_id=${encodeURIComponent(state.boardId)}`\n : state.boardSlug\n ? `?board=${encodeURIComponent(state.boardSlug)}`\n : \"\";\n return `/api/bootstrap${q}`;\n}\n\n/** Append board_id for ticket/state/entry routes when the path has no board prefix. */\nexport function withBoardQuery(path) {\n if (!state.boardId || path.includes(\"board_id=\")) return path;\n const sep = path.includes(\"?\") ? \"&\" : \"?\";\n return `${path}${sep}board_id=${encodeURIComponent(state.boardId)}`;\n}\n\nexport async function api(path, options = {}) {\n try {\n return await request({\n method: options.method || \"GET\",\n path,\n body: options.body,\n headers: options.headers\n });\n } catch (err) {\n toast.error(err.payload?.error || err.message || \"Request failed\");\n throw err;\n }\n}\n", "// Shared textarea editing helpers. These stay DOM-light so node:test can cover\n// editor behavior without booting the browser app.\n\nconst DEFAULT_INDENT = \"\\t\";\n\nfunction clampIndex(value, index) {\n const n = Number(index);\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.min(value.length, n));\n}\n\nfunction lineStartFor(value, index) {\n return value.lastIndexOf(\"\\n\", Math.max(0, index - 1)) + 1;\n}\n\nfunction selectedLineRange(value, selectionStart, selectionEnd) {\n const lineStart = lineStartFor(value, selectionStart);\n const effectiveEnd =\n selectionEnd > selectionStart && value[selectionEnd - 1] === \"\\n\"\n ? selectionEnd - 1\n : selectionEnd;\n const nextBreak = value.indexOf(\"\\n\", Math.max(lineStart, effectiveEnd));\n return {\n lineStart,\n lineEnd: nextBreak === -1 ? value.length : nextBreak,\n };\n}\n\nfunction lineStartsForBlock(block, lineStart) {\n const starts = [];\n let cursor = lineStart;\n for (const line of block.split(\"\\n\")) {\n starts.push(cursor);\n cursor += line.length + 1;\n }\n return starts;\n}\n\nfunction leadingOutdentWidth(line) {\n if (line.startsWith(\"\\t\")) return 1;\n const spaces = line.match(/^ {1,2}/)?.[0] || \"\";\n return spaces.length;\n}\n\nfunction adjustmentBeforePosition(position, lineStarts, widths) {\n let total = 0;\n for (let i = 0; i < lineStarts.length; i += 1) {\n if (position <= lineStarts[i]) continue;\n total += Math.min(widths[i], position - lineStarts[i]);\n }\n return total;\n}\n\nexport function applyTextareaIndentation({\n value = \"\",\n selectionStart = 0,\n selectionEnd = selectionStart,\n shiftKey = false,\n indent = DEFAULT_INDENT,\n} = {}) {\n const source = String(value);\n const start = clampIndex(source, selectionStart);\n const end = clampIndex(source, selectionEnd);\n const first = Math.min(start, end);\n const last = Math.max(start, end);\n const indentText = String(indent || DEFAULT_INDENT);\n\n if (!shiftKey && first === last) {\n const nextValue = `${source.slice(0, first)}${indentText}${source.slice(last)}`;\n const nextCaret = first + indentText.length;\n return {\n value: nextValue,\n selectionStart: nextCaret,\n selectionEnd: nextCaret,\n handled: true,\n };\n }\n\n const { lineStart, lineEnd } = selectedLineRange(source, first, last);\n const block = source.slice(lineStart, lineEnd);\n const lines = block.split(\"\\n\");\n const lineStarts = lineStartsForBlock(block, lineStart);\n\n if (!shiftKey) {\n const widths = lines.map(() => indentText.length);\n const nextBlock = lines.map((line) => `${indentText}${line}`).join(\"\\n\");\n const selectionStartDelta = adjustmentBeforePosition(first, lineStarts, widths);\n const selectionEndDelta = adjustmentBeforePosition(last, lineStarts, widths);\n return {\n value: `${source.slice(0, lineStart)}${nextBlock}${source.slice(lineEnd)}`,\n selectionStart: first + selectionStartDelta,\n selectionEnd: last + selectionEndDelta,\n handled: true,\n };\n }\n\n const widths = lines.map(leadingOutdentWidth);\n const nextBlock = lines\n .map((line, index) => line.slice(widths[index]))\n .join(\"\\n\");\n const selectionStartDelta = adjustmentBeforePosition(first, lineStarts, widths);\n const selectionEndDelta = adjustmentBeforePosition(last, lineStarts, widths);\n return {\n value: `${source.slice(0, lineStart)}${nextBlock}${source.slice(lineEnd)}`,\n selectionStart: first - selectionStartDelta,\n selectionEnd: last - selectionEndDelta,\n handled: true,\n };\n}\n\nexport function handleTextareaIndentationKeydown(event, textarea = event?.currentTarget) {\n if (!event || event.key !== \"Tab\") return false;\n if (event.altKey || event.ctrlKey || event.metaKey) return false;\n if (!textarea || textarea.tagName !== \"TEXTAREA\") return false;\n\n event.preventDefault();\n const next = applyTextareaIndentation({\n value: textarea.value,\n selectionStart: textarea.selectionStart,\n selectionEnd: textarea.selectionEnd,\n shiftKey: event.shiftKey,\n });\n\n textarea.value = next.value;\n textarea.setSelectionRange(next.selectionStart, next.selectionEnd);\n textarea.dispatchEvent(new Event(\"input\", { bubbles: true }));\n return next.handled;\n}\n", "// Right-side overlay drawer used for ticket detail and project settings.\n// Owns the open/close transition state and the shared header layout\n// (eyebrow, title, subtitle, tabs, archive/close buttons). Bodies are\n// rendered by the feature modules that call `renderDrawerShell`.\n\nimport { drawer, drawerInner, drawerBackdrop } from \"./dom.js\";\nimport { state } from \"./state.js\";\nimport { escapeHtml } from \"./format.js\";\n\n/** Bumps on each open/close so a stale `transitionend` from an old close cannot clear a newly opened drawer. */\nlet drawerToken = 0;\n\n/** Aborts scroll/resize observers when tabs are re-rendered or the drawer closes. */\nlet drawerTabsScrollAbort = null;\n\n/** Toggle edge-fade classes on the tab shell when the strip can scroll further left/right. */\nfunction syncDrawerTabsScrollState(tabsEl) {\n const shellEl = document.getElementById(\"drawerTabsShell\");\n if (!tabsEl || !shellEl) return;\n\n const maxScroll = tabsEl.scrollWidth - tabsEl.clientWidth;\n if (maxScroll <= 1) {\n shellEl.classList.remove(\"can-scroll-left\", \"can-scroll-right\");\n return;\n }\n\n shellEl.classList.toggle(\"can-scroll-left\", tabsEl.scrollLeft > 1);\n shellEl.classList.toggle(\"can-scroll-right\", tabsEl.scrollLeft < maxScroll - 1);\n}\n\n/** Keep the active settings tab visible when the strip overflows horizontally. */\nfunction scrollActiveDrawerTabIntoView(tabsEl) {\n tabsEl\n ?.querySelector(\".drawer-tab.is-active\")\n ?.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n}\n\nfunction teardownDrawerTabsScroll() {\n drawerTabsScrollAbort?.abort();\n drawerTabsScrollAbort = null;\n const shellEl = document.getElementById(\"drawerTabsShell\");\n const tabsEl = document.getElementById(\"drawerTabs\");\n shellEl?.classList.remove(\"can-scroll-left\", \"can-scroll-right\");\n tabsEl?.classList.remove(\"is-grabbing\");\n}\n\nfunction bindDrawerTabsScroll(tabsEl) {\n teardownDrawerTabsScroll();\n if (!tabsEl) return;\n\n const controller = new AbortController();\n drawerTabsScrollAbort = controller;\n const { signal } = controller;\n\n const onScrollChange = () => syncDrawerTabsScrollState(tabsEl);\n tabsEl.addEventListener(\"scroll\", onScrollChange, { passive: true, signal });\n\n if (typeof ResizeObserver !== \"undefined\") {\n const observer = new ResizeObserver(onScrollChange);\n observer.observe(tabsEl);\n signal.addEventListener(\"abort\", () => observer.disconnect(), { once: true });\n }\n\n // Vertical wheel over the tab strip pans horizontally (no Shift required).\n const LINE_SCROLL_PX = 16;\n const wheelPixels = (value, mode) => {\n if (mode === WheelEvent.DOM_DELTA_LINE) return value * LINE_SCROLL_PX;\n if (mode === WheelEvent.DOM_DELTA_PAGE) return value * Math.max(tabsEl.clientWidth, 1);\n return value;\n };\n\n tabsEl.addEventListener(\n \"wheel\",\n (event) => {\n if (event.defaultPrevented || event.ctrlKey) return;\n if (tabsEl.scrollWidth <= tabsEl.clientWidth) return;\n\n const horizontalDelta = event.deltaX || event.deltaY;\n if (!horizontalDelta) return;\n\n event.preventDefault();\n tabsEl.scrollLeft += wheelPixels(horizontalDelta, event.deltaMode);\n },\n { passive: false, signal }\n );\n\n // Click-and-drag horizontal panning; threshold keeps tab clicks intact.\n const DRAG_THRESHOLD = 4;\n let dragActive = false;\n let dragged = false;\n let startX = 0;\n let startScroll = 0;\n let pointerId = 0;\n\n tabsEl.addEventListener(\n \"pointerdown\",\n (event) => {\n if (event.button !== 0) return;\n if (tabsEl.scrollWidth <= tabsEl.clientWidth) return;\n dragged = false;\n dragActive = true;\n pointerId = event.pointerId;\n startX = event.clientX;\n startScroll = tabsEl.scrollLeft;\n },\n { signal }\n );\n\n tabsEl.addEventListener(\n \"pointermove\",\n (event) => {\n if (!dragActive || event.pointerId !== pointerId) return;\n const delta = event.clientX - startX;\n if (!dragged && Math.abs(delta) > DRAG_THRESHOLD) {\n dragged = true;\n try {\n tabsEl.setPointerCapture(pointerId);\n } catch {\n /* no-op: some browsers can't capture here */\n }\n tabsEl.classList.add(\"is-grabbing\");\n }\n if (dragged) {\n event.preventDefault();\n tabsEl.scrollLeft = startScroll - delta;\n }\n },\n { signal }\n );\n\n const endDrag = (event) => {\n if (!dragActive || (event && event.pointerId !== pointerId)) return;\n dragActive = false;\n tabsEl.classList.remove(\"is-grabbing\");\n try {\n tabsEl.releasePointerCapture(pointerId);\n } catch {\n /* no-op */\n }\n };\n\n tabsEl.addEventListener(\"pointerup\", endDrag, { signal });\n tabsEl.addEventListener(\"pointercancel\", endDrag, { signal });\n tabsEl.addEventListener(\"pointerleave\", endDrag, { signal });\n\n tabsEl.addEventListener(\n \"click\",\n (event) => {\n if (dragged) {\n event.stopPropagation();\n event.preventDefault();\n dragged = false;\n }\n },\n { capture: true, signal }\n );\n\n requestAnimationFrame(() => {\n if (signal.aborted) return;\n onScrollChange();\n scrollActiveDrawerTabIntoView(tabsEl);\n });\n}\n\n/** Slide the right drawer in (ticket detail, project settings, or create form). */\nexport function openDrawer() {\n drawerToken += 1;\n drawer.hidden = false;\n drawerBackdrop.hidden = false;\n requestAnimationFrame(() => {\n drawer.classList.add(\"is-open\");\n drawerBackdrop.classList.add(\"is-visible\");\n });\n}\n\n/**\n * Close the drawer overlay. Uses transitionend with a timeout fallback for `hidden`.\n * `drawerToken` invalidates pending finish callbacks if the user opens the drawer again mid-animation.\n */\nexport function closeDrawer() {\n const finishToken = ++drawerToken;\n const wasOpen = drawer.classList.contains(\"is-open\");\n drawer.classList.remove(\"is-open\");\n drawerBackdrop.classList.remove(\"is-visible\");\n\n const finish = () => {\n if (drawerToken !== finishToken) return;\n drawer.hidden = true;\n drawerBackdrop.hidden = true;\n drawerInner.innerHTML = \"\";\n const titleBlockEl = document.getElementById(\"drawerTitleBlock\");\n const tabsEl = document.getElementById(\"drawerTabs\");\n const tabsShellEl = document.getElementById(\"drawerTabsShell\");\n if (titleBlockEl) titleBlockEl.innerHTML = \"\";\n if (tabsEl) tabsEl.innerHTML = \"\";\n if (tabsShellEl) tabsShellEl.hidden = true;\n teardownDrawerTabsScroll();\n drawer.classList.remove(\"is-wide\");\n };\n\n if (!wasOpen) {\n finish();\n return;\n }\n\n let ended = false;\n const end = () => {\n if (ended) return;\n ended = true;\n finish();\n };\n\n drawer.addEventListener(\"transitionend\", end, { once: true });\n setTimeout(end, 360);\n}\n\n/**\n * Fill the drawer's header + body slots. All drawer modes (ticket, project,\n * create) should route through this so the header/title/close/tabs stay\n * structurally consistent. `body` is an HTML string assigned to drawerInner.\n */\nexport function renderDrawerShell({ eyebrow, title, titleAttrs, subtitleHtml, tabs, activeTab, onTabSelect, body, mode }) {\n drawer.classList.toggle(\"is-settings\", mode === \"settings\");\n drawer.classList.toggle(\"is-wide\", mode === \"ticket\" || mode === \"settings\");\n const titleBlockEl = document.getElementById(\"drawerTitleBlock\");\n const tabsEl = document.getElementById(\"drawerTabs\");\n const tabsShellEl = document.getElementById(\"drawerTabsShell\");\n\n // Rebuild the eyebrow / title / subtitle wholesale each render. Like\n // drawerInner.innerHTML below, this means any listeners the caller attached\n // last render (e.g. the inline title editor's click handler) die with the\n // old nodes, instead of stacking on persistent shell elements.\n const extraTitleClass = titleAttrs?.class ? ` ${titleAttrs.class}` : \"\";\n let titleAttrHtml = ` class=\"drawer-title drawer-title-text${extraTitleClass}\"`;\n for (const [key, value] of Object.entries(titleAttrs || {})) {\n if (key === \"class\") continue;\n titleAttrHtml += ` ${key}=\"${escapeHtml(String(value))}\"`;\n }\n const segments = [];\n if (eyebrow) segments.push(`<span class=\"drawer-eyebrow\">${escapeHtml(eyebrow)}</span>`);\n if (title != null && String(title).trim() !== \"\") {\n segments.push(`<h2${titleAttrHtml}>${escapeHtml(title)}</h2>`);\n }\n if (subtitleHtml) segments.push(`<div class=\"drawer-subtitle\">${subtitleHtml}</div>`);\n titleBlockEl.innerHTML = segments.join(\"\");\n\n if (tabs && tabs.length) {\n if (tabsShellEl) tabsShellEl.hidden = false;\n tabsEl.innerHTML = tabs\n .map(\n (t) =>\n `<button type=\"button\" role=\"tab\" class=\"drawer-tab ${\n t.id === activeTab ? \"is-active\" : \"\"\n }\" data-drawer-tab=\"${escapeHtml(t.id)}\" aria-selected=\"${t.id === activeTab}\">${escapeHtml(t.label)}</button>`\n )\n .join(\"\");\n if (typeof onTabSelect === \"function\") {\n tabsEl.querySelectorAll(\".drawer-tab\").forEach((btn) => {\n btn.addEventListener(\"click\", () => onTabSelect(btn.dataset.drawerTab));\n });\n }\n bindDrawerTabsScroll(tabsEl);\n } else {\n if (tabsShellEl) tabsShellEl.hidden = true;\n tabsEl.innerHTML = \"\";\n teardownDrawerTabsScroll();\n }\n\n const archiveBtn = document.getElementById(\"drawerArchiveBtn\");\n if (archiveBtn) archiveBtn.hidden = state.detailMode !== \"ticket\";\n\n drawerInner.innerHTML = body ?? \"\";\n}\n", "// Shared card action menu data, mutations, and desktop context-menu presentation.\n// Mobile can reuse buildCardActionMenu() + createCardActionHandlers() and render\n// the same model as a bottom sheet without duplicating mutation logic.\n//\n// Submenus are reparented to document.body on open so they escape the menu's\n// backdrop-filter containing block (otherwise position: fixed coords would be\n// interpreted relative to the menu instead of the viewport).\n\nimport { api, withBoardQuery } from \"./api.js\";\nimport { state, visibleStatesForProject } from \"./state.js\";\nimport { canonicalTicketType, escapeHtml, priorityLabel, typeLabel } from \"./format.js\";\nimport { toast } from \"./toast.js\";\n\nconst CARD_TYPES = [\"epic\", \"feature\", \"task\", \"bug\"];\nconst PRIORITIES = [0, 1, 2, 3, 4];\nconst MENU_MARGIN = 8;\nconst SUBMENU_GAP = 6;\nconst HOVER_CLOSE_DELAY = 180;\n\nlet openMenu = null;\nlet dragInFlight = false;\nlet dismissController = null;\nlet lastFocusedElement = null;\nconst submenuByItem = new WeakMap();\nconst itemBySubmenu = new WeakMap();\nconst openSubmenus = new Set();\nlet pendingCloseTimer = null;\n\nexport function buildCardActionMenu(ticket, lanes = visibleStatesForProject()) {\n if (!ticket) return [];\n return [\n {\n id: \"move\",\n label: \"Move to\",\n children: lanes.map((lane) => ({\n id: `move:${lane.id}`,\n label: lane.name,\n action: \"move\",\n value: lane.id,\n checked: lane.id === ticket.state_id,\n disabled: lane.id === ticket.state_id\n }))\n },\n {\n id: \"priority\",\n label: \"Priority\",\n children: PRIORITIES.map((priority) => ({\n id: `priority:${priority}`,\n label: priorityLabel(priority),\n action: \"priority\",\n value: priority,\n checked: Number(ticket.priority) === priority,\n disabled: Number(ticket.priority) === priority\n }))\n },\n {\n id: \"type\",\n label: \"Type\",\n children: CARD_TYPES.map((type) => ({\n id: `type:${type}`,\n label: typeLabel(type),\n action: \"type\",\n value: type,\n checked: canonicalTicketType(ticket.type) === type,\n disabled: canonicalTicketType(ticket.type) === type\n }))\n },\n { id: \"open\", label: \"Open\", action: \"open\" },\n { id: \"archive\", label: \"Archive\", action: \"archive\", danger: true }\n ];\n}\n\nexport function calculateMenuPosition({ x, y, menuWidth, menuHeight, viewportWidth, viewportHeight, margin = MENU_MARGIN }) {\n const maxLeft = Math.max(margin, viewportWidth - menuWidth - margin);\n const maxTop = Math.max(margin, viewportHeight - menuHeight - margin);\n const preferredLeft = x + menuWidth + margin > viewportWidth ? x - menuWidth : x;\n const preferredTop = y + menuHeight + margin > viewportHeight ? y - menuHeight : y;\n return {\n left: Math.min(Math.max(margin, preferredLeft), maxLeft),\n top: Math.min(Math.max(margin, preferredTop), maxTop)\n };\n}\n\nexport function calculateSubmenuPosition({\n triggerRect,\n submenuWidth,\n submenuHeight,\n viewportWidth,\n viewportHeight,\n margin = MENU_MARGIN,\n gap = SUBMENU_GAP\n}) {\n const maxLeft = Math.max(margin, viewportWidth - submenuWidth - margin);\n const rightLeft = triggerRect.right + gap;\n const leftLeft = triggerRect.left - submenuWidth - gap;\n const fitsRight = rightLeft + submenuWidth + margin <= viewportWidth;\n const fitsLeft = leftLeft >= margin;\n const preferredLeft = fitsRight || !fitsLeft ? rightLeft : leftLeft;\n const maxHeight = Math.max(0, viewportHeight - margin * 2);\n const boundedHeight = Math.min(submenuHeight, maxHeight);\n const maxTop = Math.max(margin, viewportHeight - boundedHeight - margin);\n const preferredTop = triggerRect.top - gap;\n\n return {\n left: Math.min(Math.max(margin, preferredLeft), maxLeft),\n top: Math.min(Math.max(margin, preferredTop), maxTop),\n maxHeight\n };\n}\n\nexport function createCardActionHandlers({ apiClient = api, navigator = null, confirmer = globalThis.confirm } = {}) {\n async function patchTicket(ticket, body) {\n await apiClient(withBoardQuery(`/api/tickets/${encodeURIComponent(ticket.id)}`), {\n method: \"PATCH\",\n body\n });\n }\n\n return {\n async open(ticket) {\n if (navigator) return navigator({ boardId: state.boardId, view: \"ticket\", ticketId: ticket.id });\n return null;\n },\n async move(ticket, stateId) {\n await patchTicket(ticket, { state_id: stateId });\n },\n async priority(ticket, priority) {\n await patchTicket(ticket, { priority });\n },\n async type(ticket, type) {\n await patchTicket(ticket, { type });\n },\n async archive(ticket) {\n if (typeof confirmer === \"function\" && !confirmer(`Archive \"${ticket.title || \"card\"}\"? You can restore it from Settings \u2192 Card Archive.`)) return false;\n await apiClient(withBoardQuery(`/api/tickets/${encodeURIComponent(ticket.id)}/archive`), { method: \"POST\" });\n toast.removed(`Archived: ${ticket.title || \"card\"}`);\n return true;\n }\n };\n}\n\nexport function setCardActionDragInFlight(value) {\n dragInFlight = Boolean(value);\n}\n\nexport function closeCardActionMenu({ restoreFocus = false } = {}) {\n cancelPendingClose();\n if (dismissController) {\n dismissController.abort();\n dismissController = null;\n }\n for (const submenu of openSubmenus) {\n if (submenu.isConnected) submenu.remove();\n }\n openSubmenus.clear();\n if (openMenu) {\n openMenu.querySelectorAll(\".card-action-menu-item.has-submenu\").forEach((item) => {\n const submenu = submenuByItem.get(item);\n if (submenu?.isConnected) submenu.remove();\n submenuByItem.delete(item);\n });\n openMenu.remove();\n openMenu = null;\n }\n if (restoreFocus && lastFocusedElement?.isConnected) {\n lastFocusedElement.focus({ preventScroll: true });\n }\n lastFocusedElement = null;\n}\n\nexport function openCardActionMenu({ ticket, anchor, x, y, handlers = createCardActionHandlers(), onBeforeOpen = null }) {\n closeCardActionMenu();\n if (!ticket || dragInFlight) return null;\n\n if (typeof onBeforeOpen === \"function\") onBeforeOpen();\n lastFocusedElement = anchor || document.activeElement;\n\n const menu = document.createElement(\"div\");\n menu.className = \"card-action-menu\";\n menu.setAttribute(\"role\", \"menu\");\n menu.setAttribute(\"aria-label\", `Actions for #${ticket.number || \"\"} ${ticket.title || \"card\"}`.trim());\n menu.dataset.ticketId = ticket.id;\n menu.innerHTML = renderMenuItems(buildCardActionMenu(ticket));\n document.body.append(menu);\n openMenu = menu;\n\n // Detach each submenu from its <li> and reparent to document.body. The menu's\n // backdrop-filter creates a containing block, so a nested position:fixed\n // submenu would be positioned relative to the menu, not the viewport.\n menu.querySelectorAll(\".card-action-menu-item.has-submenu\").forEach((item) => {\n const submenu = item.querySelector(\":scope > .card-action-submenu\");\n if (!submenu) return;\n submenu.remove();\n document.body.append(submenu);\n submenuByItem.set(item, submenu);\n itemBySubmenu.set(submenu, item);\n wireSubmenu(submenu, ticket, handlers);\n });\n\n const rect = menu.getBoundingClientRect();\n const position = calculateMenuPosition({\n x,\n y,\n menuWidth: rect.width,\n menuHeight: rect.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight\n });\n menu.style.left = `${position.left}px`;\n menu.style.top = `${position.top}px`;\n\n wireMenu(menu, ticket, handlers);\n const first = firstEnabledItem(menu);\n first?.focus({ preventScroll: true });\n\n dismissController = new AbortController();\n const signal = dismissController.signal;\n requestAnimationFrame(() => {\n document.addEventListener(\"pointerdown\", dismissOnOutsidePointer, { signal, capture: true });\n });\n document.addEventListener(\"keydown\", dismissOnEscape, { signal, capture: true });\n document.addEventListener(\"scroll\", dismissOnScroll, { signal, capture: true, passive: true });\n window.addEventListener(\"resize\", () => closeCardActionMenu(), { signal, passive: true });\n window.addEventListener(\"blur\", () => closeCardActionMenu(), { signal });\n\n return menu;\n}\n\nexport function bindCardContextMenu(card, ticket, { handlers = createCardActionHandlers(), onBeforeOpen = null } = {}) {\n card.addEventListener(\"contextmenu\", (event) => {\n event.preventDefault();\n event.stopPropagation();\n if (dragInFlight) {\n closeCardActionMenu();\n return;\n }\n openCardActionMenu({\n ticket,\n anchor: card,\n x: event.clientX,\n y: event.clientY,\n handlers,\n onBeforeOpen\n });\n });\n}\n\n// Delegated variant: a single listener on the board container resolves the card\n// and its ticket per event. Lets renderBoard() swap innerHTML freely without\n// re-binding a contextmenu listener onto every card on every render.\nexport function bindCardContextMenuDelegated(container, resolveTicket, { handlers = createCardActionHandlers(), onBeforeOpen = null } = {}) {\n container.addEventListener(\"contextmenu\", (event) => {\n const card = event.target instanceof Element ? event.target.closest(\".card\") : null;\n if (!card) return;\n const ticket = resolveTicket(card.dataset.ticketId);\n if (!ticket) return;\n event.preventDefault();\n event.stopPropagation();\n if (dragInFlight) {\n closeCardActionMenu();\n return;\n }\n openCardActionMenu({ ticket, anchor: card, x: event.clientX, y: event.clientY, handlers, onBeforeOpen });\n });\n}\n\nfunction renderMenuItems(items) {\n return `<ul class=\"card-action-menu-list\" role=\"none\">${items.map(renderMenuItem).join(\"\")}</ul>`;\n}\n\nfunction renderMenuItem(item) {\n const hasChildren = Boolean(item.children?.length);\n const classes = [\"card-action-menu-item\"];\n if (hasChildren) classes.push(\"has-submenu\");\n if (item.danger) classes.push(\"is-danger\");\n const check = item.checked ? `<span class=\"card-action-check\" aria-hidden=\"true\">\u2713</span>` : `<span class=\"card-action-check\" aria-hidden=\"true\"></span>`;\n const suffix = hasChildren ? `<span class=\"card-action-arrow\" aria-hidden=\"true\">\u203A</span>` : \"\";\n return `\n <li class=\"${classes.join(\" \")}\" role=\"none\">\n <button type=\"button\"\n class=\"card-action-button\"\n role=\"menuitem${item.checked ? \"checkbox\" : \"\"}\"\n data-action=\"${escapeHtml(item.action || \"\")}\" data-value=\"${escapeHtml(item.value ?? \"\")}\" data-menu-id=\"${escapeHtml(item.id)}\"\n ${item.disabled ? \"disabled\" : \"\"}\n ${item.checked ? 'aria-checked=\"true\"' : \"\"}\n ${hasChildren ? 'aria-haspopup=\"menu\" aria-expanded=\"false\"' : \"\"}>\n ${hasChildren ? \"\" : check}\n <span class=\"card-action-label\">${escapeHtml(item.label)}</span>\n ${suffix}\n </button>\n ${hasChildren ? `<div class=\"card-action-submenu\" role=\"menu\">${renderMenuItems(item.children)}</div>` : \"\"}\n </li>\n `;\n}\n\nfunction wireMenu(menu, ticket, handlers) {\n menu.addEventListener(\"pointerover\", (event) => {\n const item = event.target instanceof Element ? event.target.closest(\".card-action-menu-item\") : null;\n if (!item || !menu.contains(item)) return;\n if (item.classList.contains(\"has-submenu\")) {\n cancelPendingClose();\n openSubmenu(item);\n } else {\n scheduleCloseOtherSubmenus(menu);\n }\n }, true);\n\n menu.addEventListener(\"focusin\", (event) => {\n const item = event.target instanceof Element ? event.target.closest(\".card-action-menu-item\") : null;\n if (!item || !menu.contains(item)) return;\n if (item.classList.contains(\"has-submenu\")) {\n cancelPendingClose();\n openSubmenu(item);\n } else {\n cancelPendingClose();\n closeOpenSubmenus(menu);\n }\n });\n\n menu.addEventListener(\"click\", (event) => handleItemClick(event, menu, ticket, handlers));\n menu.addEventListener(\"keydown\", (event) => handleMenuKeydown(event, menu));\n}\n\nfunction wireSubmenu(submenu, ticket, handlers) {\n // Keep the submenu open while the pointer is inside it.\n submenu.addEventListener(\"pointerenter\", cancelPendingClose);\n submenu.addEventListener(\"pointerover\", (event) => {\n if (event.target instanceof Element && submenu.contains(event.target)) {\n cancelPendingClose();\n }\n }, true);\n\n submenu.addEventListener(\"click\", (event) => {\n if (!openMenu) return;\n handleItemClick(event, openMenu, ticket, handlers, submenu);\n });\n submenu.addEventListener(\"keydown\", (event) => {\n if (!openMenu) return;\n handleMenuKeydown(event, openMenu);\n });\n}\n\nfunction handleItemClick(event, rootMenu, ticket, handlers, container = rootMenu) {\n const button = event.target instanceof Element ? event.target.closest(\"button.card-action-button\") : null;\n if (!button || !container.contains(button) || button.disabled) return;\n event.preventDefault();\n event.stopPropagation();\n\n const parent = button.closest(\".card-action-menu-item\");\n if (parent?.classList.contains(\"has-submenu\")) {\n cancelPendingClose();\n openSubmenu(parent);\n firstEnabledItem(submenuByItem.get(parent))?.focus({ preventScroll: true });\n return;\n }\n\n const action = button.dataset.action;\n const value = button.dataset.value;\n closeCardActionMenu();\n if (action === \"open\") return handlers.open(ticket);\n if (action === \"move\") return handlers.move(ticket, value);\n if (action === \"priority\") return handlers.priority(ticket, Number(value));\n if (action === \"type\") return handlers.type(ticket, value);\n if (action === \"archive\") return handlers.archive(ticket);\n}\n\nfunction handleMenuKeydown(event, rootMenu) {\n const button = event.target instanceof Element ? event.target.closest(\"button.card-action-button\") : null;\n if (!button) return;\n const submenu = button.closest(\".card-action-submenu\");\n const inRoot = rootMenu.contains(button);\n if (!inRoot && !submenu) return;\n\n const currentMenu = button.closest(\".card-action-menu-list\");\n const item = button.closest(\".card-action-menu-item\");\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n if (submenu) {\n const parentItem = itemBySubmenu.get(submenu);\n const parentButton = parentItem?.querySelector(\":scope > .card-action-button\");\n closeSubmenu(parentItem);\n parentButton?.focus({ preventScroll: true });\n } else {\n closeCardActionMenu({ restoreFocus: true });\n }\n return;\n }\n\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n moveFocus(currentMenu, button, event.key === \"ArrowDown\" ? 1 : -1);\n return;\n }\n\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n const enabled = enabledItems(currentMenu);\n enabled[event.key === \"Home\" ? 0 : enabled.length - 1]?.focus({ preventScroll: true });\n return;\n }\n\n if (event.key === \"ArrowRight\" && item?.classList.contains(\"has-submenu\")) {\n event.preventDefault();\n cancelPendingClose();\n openSubmenu(item);\n firstEnabledItem(submenuByItem.get(item))?.focus({ preventScroll: true });\n return;\n }\n\n if (event.key === \"ArrowLeft\" && submenu) {\n const parentItem = itemBySubmenu.get(submenu);\n const parentButton = parentItem?.querySelector(\":scope > .card-action-button\");\n if (parentButton) {\n event.preventDefault();\n closeSubmenu(parentItem);\n parentButton.focus({ preventScroll: true });\n }\n }\n}\n\nfunction dismissOnOutsidePointer(event) {\n if (!openMenu) return;\n if (isEventInsideAnyMenu(event)) return;\n closeCardActionMenu();\n}\n\nfunction dismissOnEscape(event) {\n if (event.key === \"Escape\" && openMenu) {\n event.preventDefault();\n closeCardActionMenu({ restoreFocus: true });\n }\n}\n\nfunction dismissOnScroll(event) {\n if (!openMenu) return;\n if (isEventInsideAnyMenu(event)) return;\n closeCardActionMenu();\n}\n\nfunction isEventInsideAnyMenu(event) {\n const target = event.target;\n if (!(target instanceof Node)) return false;\n if (openMenu?.contains(target)) return true;\n for (const submenu of openSubmenus) {\n if (submenu.contains(target)) return true;\n }\n return false;\n}\n\nfunction openSubmenu(item) {\n const siblings = item.parentElement?.children || [];\n for (const sibling of siblings) {\n if (sibling !== item && sibling.classList?.contains(\"has-submenu\") && sibling.classList.contains(\"is-open\")) {\n closeSubmenu(sibling);\n }\n }\n const submenu = submenuByItem.get(item);\n if (!submenu) return;\n if (item.classList.contains(\"is-open\")) {\n positionSubmenu(item, submenu);\n return;\n }\n item.classList.add(\"is-open\");\n item.querySelector(\":scope > .card-action-button\")?.setAttribute(\"aria-expanded\", \"true\");\n submenu.classList.add(\"is-open\");\n openSubmenus.add(submenu);\n positionSubmenu(item, submenu);\n}\n\nfunction closeSubmenu(item) {\n if (!item) return;\n item.classList.remove(\"is-open\");\n item.querySelector(\":scope > .card-action-button\")?.setAttribute(\"aria-expanded\", \"false\");\n const submenu = submenuByItem.get(item);\n if (!submenu) return;\n submenu.classList.remove(\"is-open\");\n submenu.style.removeProperty(\"left\");\n submenu.style.removeProperty(\"top\");\n submenu.style.removeProperty(\"max-height\");\n openSubmenus.delete(submenu);\n}\n\nfunction closeOpenSubmenus(scope) {\n scope.querySelectorAll(\".card-action-menu-item.has-submenu.is-open\").forEach(closeSubmenu);\n}\n\nfunction scheduleCloseOtherSubmenus(rootMenu) {\n cancelPendingClose();\n pendingCloseTimer = setTimeout(() => {\n pendingCloseTimer = null;\n if (openMenu === rootMenu) closeOpenSubmenus(rootMenu);\n }, HOVER_CLOSE_DELAY);\n}\n\nfunction cancelPendingClose() {\n if (pendingCloseTimer != null) {\n clearTimeout(pendingCloseTimer);\n pendingCloseTimer = null;\n }\n}\n\nfunction positionSubmenu(item, submenu) {\n const trigger = item.querySelector(\":scope > .card-action-button\");\n if (!submenu || !trigger) return;\n\n const availableHeight = Math.max(0, window.innerHeight - MENU_MARGIN * 2);\n submenu.style.maxHeight = `${availableHeight}px`;\n submenu.style.left = \"0px\";\n submenu.style.top = \"0px\";\n\n const submenuRect = submenu.getBoundingClientRect();\n const position = calculateSubmenuPosition({\n triggerRect: trigger.getBoundingClientRect(),\n submenuWidth: submenuRect.width,\n submenuHeight: submenuRect.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight\n });\n\n submenu.style.left = `${position.left}px`;\n submenu.style.top = `${position.top}px`;\n submenu.style.maxHeight = `${position.maxHeight}px`;\n}\n\nfunction enabledItems(scope) {\n if (!scope) return [];\n const list = scope.classList?.contains(\"card-action-menu-list\")\n ? scope\n : scope.querySelector(\":scope > .card-action-menu-list\");\n if (!list) return [];\n return [...list.querySelectorAll(\":scope > .card-action-menu-item > .card-action-button\")].filter((button) => !button.disabled);\n}\n\nfunction firstEnabledItem(scope) {\n return enabledItems(scope)[0] || null;\n}\n\nfunction moveFocus(scope, current, step) {\n const items = enabledItems(scope);\n if (!items.length) return;\n const index = items.indexOf(current);\n const nextIndex = index === -1 ? 0 : (index + step + items.length) % items.length;\n items[nextIndex].focus({ preventScroll: true });\n}\n", "// Per-card \"unread updates\" tracker. Lives client-side in localStorage so\n// no backend changes are needed. Each entry tracks both:\n// readAt \u2014 ISO timestamp the human last acknowledged this card\n// count \u2014 number of foreign-actor events received since that ack\n// Render uses a dot for count===1 and a numeric pill for count>=2.\n//\n// Acknowledgement happens on three paths:\n// - opening the card (renderDetail in ticket-detail.js)\n// - own action via SSE self-event suppression (sse.js)\n// - the one-time per-board seed below, so the very first load doesn't\n// flash badges on every existing card\n\nimport { state } from \"./state.js\";\n\nconst READ_KEY = (boardId) => `mab_card_read:${boardId}`;\nconst SEEDED_KEY = (boardId) => `mab_card_read_seeded:${boardId}`;\n\nconst cache = new Map();\n\n// Normalize a stored value into { readAt, count }. Tolerates the old\n// string-only shape so existing localStorage entries upgrade in place.\nfunction normalize(raw) {\n if (!raw) return { readAt: null, count: 0 };\n if (typeof raw === \"string\") return { readAt: raw, count: 0 };\n return { readAt: raw.readAt || null, count: Number(raw.count) || 0 };\n}\n\nfunction getMap(boardId) {\n if (!boardId) return new Map();\n let m = cache.get(boardId);\n if (m) return m;\n m = new Map();\n try {\n const raw = localStorage.getItem(READ_KEY(boardId));\n if (raw) {\n const obj = JSON.parse(raw);\n for (const [k, v] of Object.entries(obj)) m.set(k, normalize(v));\n }\n } catch { /* ignore */ }\n cache.set(boardId, m);\n return m;\n}\n\nfunction persist(boardId) {\n const m = cache.get(boardId);\n if (!m) return;\n try {\n const obj = {};\n for (const [k, v] of m) obj[k] = v;\n localStorage.setItem(READ_KEY(boardId), JSON.stringify(obj));\n } catch { /* ignore */ }\n}\n\nfunction entryFor(m, ticketId) {\n let e = m.get(ticketId);\n if (!e) {\n e = { readAt: null, count: 0 };\n m.set(ticketId, e);\n }\n return e;\n}\n\nexport function unreadCount(ticket) {\n const boardId = ticket?.board_id || state.boardId;\n if (!boardId || !ticket?.id) return 0;\n const m = getMap(boardId);\n const e = m.get(ticket.id);\n if (!e) {\n // Absence: if seeded, the card appeared post-seed \u2192 flag with count 1.\n // If never seeded, treat as read so first-ever load is quiet.\n return localStorage.getItem(SEEDED_KEY(boardId)) === \"1\" ? 1 : 0;\n }\n return e.count;\n}\n\nexport function isUnread(ticket) {\n return unreadCount(ticket) > 0;\n}\n\nexport function markRead(ticketId, timestamp) {\n const boardId = state.boardId;\n if (!boardId || !ticketId) return;\n const m = getMap(boardId);\n const e = entryFor(m, ticketId);\n if (e.count === 0 && e.readAt && timestamp && e.readAt >= timestamp) return;\n e.count = 0;\n if (timestamp) e.readAt = timestamp;\n persist(boardId);\n}\n\nexport function bumpUnread(ticketId) {\n const boardId = state.boardId;\n if (!boardId || !ticketId) return;\n const m = getMap(boardId);\n const e = entryFor(m, ticketId);\n e.count = (e.count || 0) + 1;\n persist(boardId);\n}\n\nexport function clearUnread(ticketId) {\n const boardId = state.boardId;\n if (!boardId || !ticketId) return;\n const m = getMap(boardId);\n if (!m.has(ticketId)) return;\n m.delete(ticketId);\n persist(boardId);\n}\n\n// One-time per-board seed so existing cards start \"read\" the first time the\n// user runs this version. Runs again per-board the first time each board is\n// visited.\nexport function seedReadIfNeeded(boardId, tickets) {\n if (!boardId) return;\n if (localStorage.getItem(SEEDED_KEY(boardId)) === \"1\") return;\n const m = getMap(boardId);\n for (const t of tickets || []) {\n if (!m.has(t.id) && t.updated_at) m.set(t.id, { readAt: t.updated_at, count: 0 });\n }\n persist(boardId);\n try { localStorage.setItem(SEEDED_KEY(boardId), \"1\"); } catch { /* ignore */ }\n}\n", "// Kanban board rendering plus the drag-to-pan interaction. `renderBoard()`\n// rebuilds every column from current state and rewires drop zones, card\n// click/drag handlers, and the per-column \"+\" button. Card detail is\n// owned by ticket-detail.js.\n\nimport { kanban } from \"./dom.js\";\nimport { state, visibleStatesForProject, ticketsForProject } from \"./state.js\";\nimport {\n escapeHtml,\n ticketLabel,\n canonicalTicketType,\n typeLabel,\n priorityLabel,\n priorityKeyFor,\n renderLabels,\n renderMarkdown\n} from \"./format.js\";\nimport { api, withBoardQuery } from \"./api.js\";\nimport { navigate } from \"./router.js\";\nimport { closeCreateFlyout, openCreateFlyout } from \"./create-card.js\";\nimport { load } from \"./app.js\";\nimport { bindCardContextMenuDelegated, closeCardActionMenu, createCardActionHandlers, setCardActionDragInFlight } from \"./card-actions.js\";\nimport { unreadCount } from \"./unread.js\";\n\n// Lookup for the current board's tickets, keyed by id. Refreshed on every\n// renderBoard() so the single, persistent set of delegated listeners can\n// resolve a card's ticket in O(1) without re-binding anything per render.\nlet boardTicketsById = new Map();\n// Created once (lazily) and reused \u2014 handlers are stateless w.r.t. a given card.\nlet cardActionHandlers = null;\n// HTML5 DnD ends with a synthetic click on the drag source; this flag lets the\n// delegated click handler swallow that one click so a drop doesn't also open\n// the ticket drawer. Module-scoped because there's now one shared listener.\nlet suppressClickAfterDrag = false;\n\n// renderBoard() is hot: it runs on every drag-drop, every SSE board event, and\n// every settings toggle. Keep it to a single innerHTML write plus a Map refresh.\n// All interaction wiring lives in enableKanbanInteractions(), attached ONCE to\n// the persistent `kanban` element (see below), so re-rendering never re-binds\n// per-card/column/button listeners or rescans the ticket list.\nexport function renderBoard() {\n const states = visibleStatesForProject();\n const tickets = ticketsForProject();\n boardTicketsById = new Map(tickets.map((ticket) => [ticket.id, ticket]));\n kanban.innerHTML = states.map((column) => renderColumn(column, tickets)).join(\"\");\n}\n\nfunction toggleCardExpansion(card) {\n if (!card) return;\n const id = card.dataset.ticketId;\n const willExpand = !state.expandedCardIds.has(id);\n if (willExpand) {\n state.expandedCardIds.add(id);\n // Build the expandable body (markdown parse + labels + relations) the first\n // time a card opens. Collapsed cards \u2014 the overwhelming majority on render \u2014\n // never pay this cost. Once built it stays cached in the DOM for re-toggles.\n if (!card.querySelector(\".card-expandable\")) {\n const ticket = boardTicketsById.get(id);\n const meta = card.querySelector(\".card-meta\");\n if (ticket && meta) meta.insertAdjacentHTML(\"afterend\", renderCardExpandable(ticket));\n }\n } else {\n state.expandedCardIds.delete(id);\n }\n card.classList.toggle(\"is-expanded\", willExpand);\n const toggleBtn = card.querySelector(\"button.card-expand-trigger\");\n if (toggleBtn) toggleBtn.setAttribute(\"aria-expanded\", willExpand ? \"true\" : \"false\");\n}\n\n// One-time setup: attach delegated listeners to the persistent board container.\n// Because events bubble to `kanban`, these survive every innerHTML swap, so\n// renderBoard() does zero listener work regardless of card count.\nexport function enableKanbanInteractions() {\n cardActionHandlers = cardActionHandlers || createCardActionHandlers({ navigator: navigate });\n\n // --- Drag & drop (HTML5 DnD events bubble, so one set covers all cards) ---\n let dragOverColumn = null;\n const setDragOverColumn = (column) => {\n if (dragOverColumn === column) return;\n if (dragOverColumn) dragOverColumn.classList.remove(\"drag-over\");\n dragOverColumn = column;\n if (dragOverColumn) dragOverColumn.classList.add(\"drag-over\");\n };\n\n kanban.addEventListener(\"dragstart\", (event) => {\n const card = event.target instanceof Element ? event.target.closest(\".card\") : null;\n if (!card) return;\n closeCardActionMenu();\n setCardActionDragInFlight(true);\n event.dataTransfer.setData(\"text/plain\", card.dataset.ticketId);\n event.dataTransfer.effectAllowed = \"move\";\n });\n\n kanban.addEventListener(\"dragover\", (event) => {\n const column = event.target instanceof Element ? event.target.closest(\".column\") : null;\n if (!column) return;\n event.preventDefault();\n setDragOverColumn(column);\n });\n\n kanban.addEventListener(\"dragend\", () => {\n setCardActionDragInFlight(false);\n setDragOverColumn(null);\n suppressClickAfterDrag = true;\n // If no synthetic click follows (e.g. drag cancelled oddly), don't eat the\n // next real click.\n setTimeout(() => {\n suppressClickAfterDrag = false;\n }, 0);\n });\n\n kanban.addEventListener(\"drop\", async (event) => {\n const column = event.target instanceof Element ? event.target.closest(\".column\") : null;\n if (!column) return;\n event.preventDefault();\n setDragOverColumn(null);\n const ticketId = event.dataTransfer.getData(\"text/plain\");\n if (!ticketId) return;\n closeCreateFlyout();\n await api(withBoardQuery(`/api/tickets/${ticketId}`), {\n method: \"PATCH\",\n body: { state_id: column.dataset.stateId }\n });\n // Refresh board only; do not open the ticket drawer (DnD also fires a\n // synthetic click on the card \u2014 suppressed by suppressClickAfterDrag).\n await load();\n });\n\n // --- Clicks (precedence: add-button > expand toggle > link > epic header > card) ---\n kanban.addEventListener(\"click\", (event) => {\n const target = event.target instanceof Element ? event.target : event.target?.parentElement;\n if (!target) return;\n\n const addBtn = target.closest(\"[data-add-to-state]\");\n if (addBtn) {\n event.stopPropagation();\n openCreateFlyout(addBtn.dataset.addToState || \"\");\n return;\n }\n\n const toggle = target.closest(\"button.card-expand-trigger\");\n if (toggle) {\n event.stopPropagation();\n event.preventDefault();\n toggleCardExpansion(toggle.closest(\".card\"));\n return;\n }\n\n // Anchors inside a card keep their native behavior.\n if (target.closest(\"a\")) {\n event.stopPropagation();\n return;\n }\n\n const epicHeader = target.closest(\".epic-mini-header[data-ticket-id]\");\n if (epicHeader) {\n closeCreateFlyout();\n navigate({ boardId: state.boardId, view: \"ticket\", ticketId: epicHeader.dataset.ticketId });\n return;\n }\n\n const card = target.closest(\".card\");\n if (!card) return;\n if (suppressClickAfterDrag) {\n suppressClickAfterDrag = false;\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n closeCreateFlyout();\n navigate({ boardId: state.boardId, view: \"ticket\", ticketId: card.dataset.ticketId });\n });\n\n // --- Context menu ---\n bindCardContextMenuDelegated(kanban, (id) => boardTicketsById.get(id), {\n handlers: cardActionHandlers,\n onBeforeOpen: closeCreateFlyout\n });\n}\n\nexport function renderBoardSelection() {\n kanban.querySelectorAll(\".card.selected\").forEach((card) => card.classList.remove(\"selected\"));\n if (!state.selectedTicketId) return;\n kanban\n .querySelectorAll(`.card[data-ticket-id=\"${CSS.escape(state.selectedTicketId)}\"]`)\n .forEach((card) => card.classList.add(\"selected\"));\n}\n\nfunction renderEmptyState(columnName) {\n const name = columnName.toLowerCase();\n let flair = {\n icon: `<svg class=\"empty-state-icon\" viewBox=\"0 0 24 24\"><path d=\"M18 6L6 18M6 6l12 12\" opacity=\"0.5\" /></svg>`,\n title: \"Nothing here\",\n subtitle: \"Tasks will appear when ready\"\n };\n\n if (name === \"ai ready\") {\n flair = {\n icon: `<svg class=\"empty-state-icon ai-sparkle\" viewBox=\"0 0 24 24\">\n <path d=\"M12 3L14.5 9L21 11.5L14.5 14L12 20L9.5 14L3 11.5L9.5 9L12 3Z\" fill=\"currentColor\" opacity=\"0.65\" />\n <circle cx=\"12\" cy=\"11.5\" r=\"1.8\" fill=\"#fff\" />\n </svg>`,\n title: \"Ready for agents\",\n subtitle: \"Drop unblocked cards here \u2014 the claim-next tool picks them up\"\n };\n } else if (name.includes(\"progress\")) {\n flair = {\n icon: `<svg class=\"empty-state-icon orbit\" viewBox=\"0 0 100 100\">\n <circle cx=\"50\" cy=\"50\" r=\"10\" fill=\"currentColor\" opacity=\"0.9\" />\n <circle class=\"ring\" cx=\"50\" cy=\"50\" r=\"30\" stroke=\"currentColor\" stroke-dasharray=\"4 6\" />\n <circle class=\"satellite\" cx=\"80\" cy=\"50\" r=\"4\" fill=\"currentColor\" />\n </svg>`,\n title: \"Work in progress\",\n subtitle: \"Active work will appear here\"\n };\n } else if (name.includes(\"review\")) {\n flair = {\n icon: `<svg class=\"empty-state-icon star\" viewBox=\"0 0 24 24\">\n <path d=\"M12 2L14.5 9.5L22 12L14.5 14.5L12 22L9.5 14.5L2 12L9.5 9.5L12 2Z\" fill=\"currentColor\" />\n </svg>`,\n title: \"Under review\",\n subtitle: \"Quality gate before merge\"\n };\n } else if (name.includes(\"todo\") || name.includes(\"backlog\")) {\n flair = {\n icon: `<svg class=\"empty-state-icon ai-sparkle\" viewBox=\"0 0 24 24\">\n <path d=\"M12 3L14.5 9L21 11.5L14.5 14L12 20L9.5 14L3 11.5L9.5 9L12 3Z\" fill=\"currentColor\" opacity=\"0.5\" />\n <path d=\"M19 8L20 10L21 8L20 6L19 8ZM19 16L20 18L21 16L20 14L19 16ZM5 8L6 10L7 8L6 6L5 8Z\" fill=\"currentColor\" />\n </svg>`,\n title: \"Ready for launch\",\n subtitle: \"Create a card manually or task an AI to generate tasks\"\n };\n } else if (name.includes(\"done\") || name.includes(\"finished\")) {\n flair = {\n icon: `<svg class=\"empty-state-icon\" viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 12L11 15L16 9\" />\n </svg>`,\n title: \"Done\",\n subtitle: \"Move completed tickets here\"\n };\n } else if (name.includes(\"cancel\")) {\n flair = {\n icon: `<svg class=\"empty-state-icon\" viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" opacity=\"0.2\" />\n <path d=\"M15 9L9 15M9 9l6 6\" />\n </svg>`,\n title: \"Not moving forward\",\n subtitle: \"Parked or replaced\"\n };\n }\n\n return `\n <div class=\"column-empty-state\">\n <div class=\"empty-state-visual\">\n <div class=\"empty-state-glow\"></div>\n ${flair.icon}\n </div>\n <div class=\"empty-state-title\">${escapeHtml(flair.title)}</div>\n <div class=\"empty-state-subtitle\">${escapeHtml(flair.subtitle)}</div>\n </div>\n `;\n}\n\nfunction renderColumn(column, tickets) {\n const columnTickets = tickets.filter((ticket) => ticket.state_id === column.id);\n const isEmpty = columnTickets.length === 0;\n // The \"AI Ready\" lane is a contract between humans and agents: cards here\n // are the queue the claim-next MCP tool pulls from. Mark it so humans can\n // instantly see where agent-facing staging lives.\n const isAiReady = column.name === \"AI Ready\";\n const columnClasses = [\"column\", \"lane\"];\n if (isAiReady) columnClasses.push(\"column--ai-ready\");\n const accentAttr = isAiReady ? ' data-accent=\"ai-ready\"' : \"\";\n\n return `\n <section class=\"${columnClasses.join(\" \")}\" data-flat${accentAttr} data-state-id=\"${column.id}\" data-state-name=\"${escapeHtml(column.name)}\">\n <div class=\"column-head lane-head\">\n <h2 class=\"lane-title\"${isAiReady ? ' title=\"Agent staging \u2014 cards here are picked up by the claim-next tool when unblocked\"' : \"\"}>\n ${isAiReady ? '<span class=\"agent-dot\" aria-hidden=\"true\"></span>' : \"\"}${escapeHtml(column.name)}\n </h2>\n <div class=\"column-head-actions lane-actions\">\n <button type=\"button\" class=\"column-add-btn\" data-variant=\"plus\" data-add-to-state=\"${escapeHtml(column.id)}\" title=\"New card\">+</button>\n <span class=\"count\">${columnTickets.length}</span>\n </div>\n </div>\n ${isEmpty ? renderEmptyState(column.name) : renderColumnBody(columnTickets, tickets)}\n <button type=\"button\" class=\"add-card-phantom\" data-add-to-state=\"${escapeHtml(column.id)}\">+ Add a card</button>\n </section>\n `;\n}\n\n/**\n * Lay out the cards inside a column with epic-aware grouping. Children of an\n * epic that's also in this column slide under the epic; children whose epic\n * lives in a different column appear under a thin \"mini epic header\" so the\n * relationship is still visible. Children get pulled to their group even if\n * the user dropped them out of order \u2014 the grouping always wins for clarity.\n */\nfunction renderColumnBody(columnTickets, allTickets) {\n const epicById = new Map(\n allTickets\n .filter((t) => canonicalTicketType(t.type) === \"epic\")\n .map((t) => [t.id, t])\n );\n const epicIdsInColumn = new Set(\n columnTickets\n .filter((t) => canonicalTicketType(t.type) === \"epic\")\n .map((t) => t.id)\n );\n const childrenByEpicId = new Map();\n for (const t of columnTickets) {\n if (t.parent_ticket_id && epicById.has(t.parent_ticket_id)) {\n const list = childrenByEpicId.get(t.parent_ticket_id) || [];\n list.push(t);\n childrenByEpicId.set(t.parent_ticket_id, list);\n }\n }\n\n const rendered = new Set();\n const blocks = [];\n for (const t of columnTickets) {\n if (rendered.has(t.id)) continue;\n\n if (canonicalTicketType(t.type) === \"epic\") {\n const children = childrenByEpicId.get(t.id) || [];\n if (children.length) {\n const childrenHtml = children.map((c) => renderCard(c, { asEpicChild: true })).join(\"\");\n blocks.push(`${renderCard(t)}<div class=\"epic-children\">${childrenHtml}</div>`);\n children.forEach((c) => rendered.add(c.id));\n } else {\n blocks.push(renderCard(t));\n }\n rendered.add(t.id);\n continue;\n }\n\n // Defer children whose epic is in this column \u2014 they'll render under the\n // epic when the loop reaches it. Without this skip, a child iterated before\n // its epic would render standalone here, then again inside epic-children\n // (rendered.add happens at the epic, which may come later in updated_at order).\n if (t.parent_ticket_id && epicIdsInColumn.has(t.parent_ticket_id)) {\n continue;\n }\n\n if (t.parent_ticket_id && epicById.has(t.parent_ticket_id) && !epicIdsInColumn.has(t.parent_ticket_id)) {\n const epic = epicById.get(t.parent_ticket_id);\n const siblings = childrenByEpicId.get(t.parent_ticket_id) || [];\n const childrenHtml = siblings.map((c) => renderCard(c, { asEpicChild: true })).join(\"\");\n blocks.push(`${renderEpicMiniHeader(epic)}<div class=\"epic-children\">${childrenHtml}</div>`);\n siblings.forEach((c) => rendered.add(c.id));\n continue;\n }\n\n blocks.push(renderCard(t));\n rendered.add(t.id);\n }\n\n return blocks.join(\"\");\n}\n\nfunction renderEpicMiniHeader(epic) {\n return `\n <div class=\"epic-mini-header\" data-ticket-id=\"${escapeHtml(epic.id)}\" title=\"Open epic\">\n <div class=\"card-type-id type-pill-epic\">\n ${renderTypeIcon(\"epic\")}\n <span class=\"card-type-label\">EPIC</span>\n </div>\n <span class=\"ticket-number\">${escapeHtml(ticketLabel(epic))}</span>\n <span class=\"epic-mini-title\">${escapeHtml(epic.title)}</span>\n </div>\n `;\n}\n\n/** Pill mirroring the structure/feel of the Type pill, colored per priority. */\nexport function renderPriorityPill(priority) {\n const key = priorityKeyFor(priority);\n const label = priorityLabel(priority);\n return `<div class=\"card-priority-id priority-pill\" data-variant=\"${escapeHtml(key)}\"><span class=\"card-priority-label\">${escapeHtml(label)}</span></div>`;\n}\n\nexport function renderTypeIcon(type) {\n const canonical = canonicalTicketType(type);\n let icon = \"\";\n let color = \"currentColor\";\n\n switch (canonical) {\n case \"epic\":\n color = \"#c084fc\"; // Purple\n icon = `<path d=\"M12 2L14.5 9.5L22 12L14.5 14.5L12 22L9.5 14.5L2 12L9.5 9.5L12 2Z\" fill=\"currentColor\" />`;\n break;\n case \"feature\":\n color = \"#4ade80\"; // Green\n icon = `<path d=\"M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2v16z\" fill=\"currentColor\" />`;\n break;\n case \"bug\":\n color = \"#f87171\"; // Red\n icon = `<circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"M12 8v4M12 16h.01\" />`;\n break;\n default: // task\n color = \"#60a5fa\"; // Blue\n icon = `<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" /><path d=\"M9 12l2 2 4-4\" />`;\n }\n\n return `\n <svg class=\"card-type-icon\" viewBox=\"0 0 24 24\" style=\"color: ${color}\">\n ${icon}\n </svg>\n `;\n}\n\nfunction renderCard(ticket, { asEpicChild = false } = {}) {\n const canonicalType = canonicalTicketType(ticket.type);\n const priorityKey = priorityKeyFor(ticket.priority);\n const typeText = typeLabel(ticket.type).toUpperCase();\n const isExpanded = state.expandedCardIds.has(ticket.id);\n const hasDescription = Boolean(String(ticket.description || \"\").trim());\n const hasExpandable = hasDescription || (ticket.labels && ticket.labels.length) || ticket.parent_ticket || ticket.child_count;\n\n const triggerInner = `\n <span class=\"ticket-number\">${escapeHtml(ticketLabel(ticket))}</span>\n <div class=\"card-type-id type-pill-${escapeHtml(canonicalType)}\">\n ${renderTypeIcon(ticket.type)}\n <span class=\"card-type-label\">${escapeHtml(typeText)}</span>\n </div>\n ${state.showPriority ? renderPriorityPill(ticket.priority) : \"\"}\n ${hasExpandable ? `<svg class=\"card-expand-chevron\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\" /></svg>` : \"\"}\n `;\n\n const unreadN = unreadCount(ticket);\n const unreadDot = unreadN === 0\n ? \"\"\n : unreadN === 1\n ? `<span class=\"card-unread-dot\" role=\"status\" aria-label=\"1 unread update\"></span>`\n : `<span class=\"card-unread-dot has-count\" role=\"status\" aria-label=\"${unreadN} unread updates\">${unreadN > 99 ? \"99+\" : unreadN}</span>`;\n\n return `\n <article class=\"card type-${escapeHtml(canonicalType)} priority-${escapeHtml(priorityKey)}${isExpanded ? \" is-expanded\" : \"\"}${asEpicChild ? \" is-epic-child\" : \"\"} ${ticket.id === state.selectedTicketId ? \"selected\" : \"\"}\" data-variant=\"${escapeHtml(canonicalType)}\" draggable=\"true\" data-ticket-id=\"${ticket.id}\">\n ${unreadDot}\n <h3>${escapeHtml(ticket.title)}</h3>\n\n <div class=\"card-meta\">\n ${hasExpandable\n ? `<button type=\"button\" class=\"card-expand-trigger\" data-variant=\"card-accordion\" data-card-toggle aria-expanded=\"${isExpanded ? \"true\" : \"false\"}\">${triggerInner}</button>`\n : `<div class=\"card-expand-trigger card-expand-trigger--static\">${triggerInner}</div>`}\n </div>\n\n ${hasExpandable && isExpanded ? renderCardExpandable(ticket) : \"\"}\n </article>\n `;\n}\n\n// The expandable body holds the only genuinely expensive per-card work: a full\n// markdown parse of the description. It's rendered eagerly only for cards that\n// are already expanded; collapsed cards get it injected on first open (see\n// toggleCardExpansion). Kept as its own function so both paths share one source.\nfunction renderCardExpandable(ticket) {\n const hasDescription = Boolean(String(ticket.description || \"\").trim());\n return `\n <div class=\"card-expandable\">\n ${hasDescription ? `<div class=\"card-description markdown-body\">${renderMarkdown(ticket.description)}</div>` : \"\"}\n ${renderLabels(ticket.labels)}\n ${ticket.parent_ticket ? `<div class=\"parent-line\">-> ${escapeHtml(ticketLabel(ticket.parent_ticket))}</div>` : \"\"}\n ${ticket.child_count ? `<div class=\"child-count\">${ticket.child_count} feature${ticket.child_count === 1 ? \"\" : \"s\"} inside</div>` : \"\"}\n </div>\n `;\n}\n\n/**\n * Click-and-drag horizontal panning on the kanban container.\n * Skipped when the pointer starts on a .card (cards own their own click + HTML5 DnD),\n * or on any interactive control inside a column head.\n */\nexport function enableKanbanDragScroll() {\n const DRAG_THRESHOLD = 4; // px before we consider it a real drag (avoids eating clicks)\n const LINE_SCROLL_PX = 16;\n const PAGE_SCROLL_PX = () => Math.max(kanban.clientWidth, 1);\n let active = false;\n let dragged = false;\n let startX = 0;\n let startScroll = 0;\n let pointerId = 0;\n\n const shouldIgnore = (target) => {\n if (!(target instanceof Element)) return false;\n // Let cards keep their click/drag behavior untouched.\n if (target.closest(\".card\")) return true;\n // Don't hijack interactive controls that might land in the board area later.\n if (target.closest(\"a, button, input, select, textarea, [draggable='true']\")) return true;\n return false;\n };\n\n const wheelPixels = (value, mode) => {\n if (mode === WheelEvent.DOM_DELTA_LINE) return value * LINE_SCROLL_PX;\n if (mode === WheelEvent.DOM_DELTA_PAGE) return value * PAGE_SCROLL_PX();\n return value;\n };\n\n kanban.addEventListener(\n \"wheel\",\n (event) => {\n if (event.defaultPrevented || event.ctrlKey) return;\n const horizontalDelta = event.deltaX || (event.shiftKey ? event.deltaY : 0);\n if (!horizontalDelta) return;\n const horizontal = Math.abs(horizontalDelta) >= Math.abs(event.deltaY) || event.shiftKey;\n if (!horizontal || kanban.scrollWidth <= kanban.clientWidth) return;\n\n event.preventDefault();\n kanban.scrollLeft += wheelPixels(horizontalDelta, event.deltaMode);\n },\n { passive: false }\n );\n\n kanban.addEventListener(\"pointerdown\", (event) => {\n if (event.button !== 0) return;\n // Clear stale drag-click suppression on any fresh primary press \u2014 even over\n // a card \u2014 so a both-button / two-finger pan that emitted no trailing click\n // can't swallow the next genuine click.\n dragged = false;\n if (shouldIgnore(event.target)) return;\n\n active = true;\n pointerId = event.pointerId;\n startX = event.clientX;\n startScroll = kanban.scrollLeft;\n kanban.classList.add(\"is-grabbing\");\n });\n\n kanban.addEventListener(\"pointermove\", (event) => {\n if (!active || event.pointerId !== pointerId) return;\n const delta = event.clientX - startX;\n if (!dragged && Math.abs(delta) > DRAG_THRESHOLD) {\n dragged = true;\n // Capture so movement outside the element still pans smoothly.\n try {\n kanban.setPointerCapture(pointerId);\n } catch {\n /* no-op: some browsers can't capture here */\n }\n }\n if (dragged) {\n event.preventDefault();\n kanban.scrollLeft = startScroll - delta;\n }\n });\n\n const endDrag = (event) => {\n if (!active || (event && event.pointerId !== pointerId)) return;\n active = false;\n kanban.classList.remove(\"is-grabbing\");\n try {\n kanban.releasePointerCapture(pointerId);\n } catch {\n /* no-op */\n }\n };\n\n kanban.addEventListener(\"pointerup\", endDrag);\n kanban.addEventListener(\"pointercancel\", endDrag);\n kanban.addEventListener(\"pointerleave\", endDrag);\n\n // Suppress the synthetic click at the end of a real drag so empty-area panning\n // doesn't accidentally trigger downstream click handlers.\n kanban.addEventListener(\n \"click\",\n (event) => {\n if (dragged) {\n event.stopPropagation();\n event.preventDefault();\n dragged = false;\n }\n },\n true\n );\n\n // --- Both-button mouse drag + two-finger touch drag -----------------------\n // A second panning affordance that works ANYWHERE on the board, including\n // directly over cards. A plain left-click / single-finger tap is left to the\n // cards (so they still open + drag); holding *both* mouse buttons, or dragging\n // with *two fingers*, pans the board horizontally without engaging a card.\n let bothBtnPanning = false;\n let bothBtnLastX = 0;\n let suppressContextMenu = false;\n\n // Pressing the second mouse button (buttons bitmask 1|2 === 3) arms the pan\n // and cancels any single-button drag already in flight (see `active` above).\n kanban.addEventListener(\"pointerdown\", (event) => {\n if (event.pointerType !== \"mouse\" || (event.buttons & 3) !== 3) return;\n bothBtnPanning = true;\n bothBtnLastX = event.clientX;\n suppressContextMenu = true;\n active = false; // hand control off from the left-button drag\n kanban.classList.add(\"is-grabbing\");\n });\n\n kanban.addEventListener(\"pointermove\", (event) => {\n if (event.pointerType !== \"mouse\") return;\n const bothDown = (event.buttons & 3) === 3;\n if (bothDown) {\n event.preventDefault();\n if (!bothBtnPanning) {\n bothBtnPanning = true;\n bothBtnLastX = event.clientX;\n suppressContextMenu = true;\n active = false;\n kanban.classList.add(\"is-grabbing\");\n return;\n }\n const delta = event.clientX - bothBtnLastX;\n if (delta) {\n kanban.scrollLeft -= delta;\n bothBtnLastX = event.clientX;\n dragged = true; // eat the trailing synthetic click\n }\n } else if (bothBtnPanning) {\n bothBtnPanning = false;\n kanban.classList.remove(\"is-grabbing\");\n }\n });\n\n kanban.addEventListener(\"pointerup\", (event) => {\n if (event.pointerType === \"mouse\" && bothBtnPanning && (event.buttons & 3) !== 3) {\n bothBtnPanning = false;\n kanban.classList.remove(\"is-grabbing\");\n }\n });\n\n // Right-click handling on the board:\n // - after a both-button pan, swallow the trailing context menu;\n // - otherwise suppress the native browser menu everywhere EXCEPT over a card,\n // which owns its own context menu (see bindCardContextMenuDelegated).\n kanban.addEventListener(\"contextmenu\", (event) => {\n if (suppressContextMenu) {\n event.preventDefault();\n event.stopPropagation();\n suppressContextMenu = false;\n return;\n }\n const onCard = event.target instanceof Element && event.target.closest(\".card\");\n if (!onCard) {\n event.preventDefault();\n event.stopPropagation();\n }\n });\n\n // Two-finger touch pan. Touch events (not pointer events) are used here so we\n // can reliably preventDefault the browser's native two-finger scroll/zoom.\n let touchPanning = false;\n let touchPanLastX = 0;\n const twoFingerCentroidX = (touches) => (touches[0].clientX + touches[1].clientX) / 2;\n\n kanban.addEventListener(\n \"touchstart\",\n (event) => {\n // Fresh gesture \u2014 clear any leftover drag-click suppression so a real tap\n // is never swallowed when the prior two-finger pan emitted no click.\n dragged = false;\n if (event.touches.length === 2) {\n touchPanning = true;\n touchPanLastX = twoFingerCentroidX(event.touches);\n active = false; // cancel any single-finger drag that started\n kanban.classList.add(\"is-grabbing\");\n } else {\n touchPanning = false;\n }\n },\n { passive: true }\n );\n\n kanban.addEventListener(\n \"touchmove\",\n (event) => {\n if (!touchPanning || event.touches.length !== 2) return;\n const x = twoFingerCentroidX(event.touches);\n const delta = x - touchPanLastX;\n if (delta) {\n event.preventDefault();\n kanban.scrollLeft -= delta;\n touchPanLastX = x;\n dragged = true; // eat the trailing tap so a card doesn't open\n }\n },\n { passive: false }\n );\n\n const endTouchPan = (event) => {\n if (event.touches.length < 2 && touchPanning) {\n touchPanning = false;\n kanban.classList.remove(\"is-grabbing\");\n }\n };\n kanban.addEventListener(\"touchend\", endTouchPan, { passive: true });\n kanban.addEventListener(\"touchcancel\", endTouchPan, { passive: true });\n}\n", "// Edition + feature flags. The build script replaces `__ORBIT_EDITION__`\n// via esbuild --define when producing dist/preview; in dev (raw modules\n// served from public/) the identifier is undefined and we fall back to\n// \"full\". `typeof` is the safe probe \u2014 bare reads of an undefined global\n// would throw.\n\nlet resolvedEdition = \"full\";\nif (typeof __ORBIT_EDITION__ !== \"undefined\") {\n resolvedEdition = __ORBIT_EDITION__;\n}\n\nexport const edition = resolvedEdition; // \"full\" | \"preview\"\n\nexport const features = {\n sse: edition === \"full\",\n ai: edition === \"full\",\n multiBoard: edition === \"full\",\n tokenAuth: edition === \"full\",\n attachments: edition === \"full\"\n};\n", "export const FONT_STORAGE_KEY = \"orbit_font_preferences\";\nexport const FONT_CHANGE_EVENT = \"orbit:font-preference-change\";\n\n// Inter is the default site font and for most categories; badges default to\n// Orbitron. The site font drives global font metrics such as size, spacing,\n// and line-height.\nexport const DEFAULT_SITE_FONT = \"inter\";\nexport const DEFAULT_BADGE_FONT = \"orbitron\";\nexport const DEFAULT_USER_SCALE = 1;\nexport const USER_SCALE_MIN = 0.85;\nexport const USER_SCALE_MAX = 1.3;\nexport const USER_SCALE_STEP = 0.05;\n\nexport const SITE_FONT_OPTIONS = Object.freeze([\n \"inter\",\n \"openSans\",\n \"jetBrainsMono\",\n \"chakraPetch\",\n \"orbitron\",\n \"rajdhani\",\n \"runescapeUF\",\n \"openRing\"\n]);\n\nexport const FONT_OPTIONS = Object.freeze({\n inter: {\n label: \"Inter\",\n stack: \"\\\"Orbit Inter\\\", \\\"Inter\\\", \\\"Segoe UI Variable\\\", \\\"Segoe UI\\\", Arial, sans-serif\",\n className: \"font-inter\"\n },\n openSans: {\n label: \"Open Sans\",\n stack: \"\\\"Orbit Open Sans\\\", \\\"Open Sans\\\", \\\"Segoe UI Variable\\\", \\\"Segoe UI\\\", Arial, sans-serif\",\n className: \"font-open-sans\"\n },\n jetBrainsMono: {\n label: \"JetBrains Mono\",\n stack: \"\\\"Orbit JetBrains Mono\\\", \\\"JetBrains Mono\\\", \\\"Cascadia Mono\\\", \\\"SFMono-Regular\\\", Consolas, monospace\",\n className: \"font-jetbrains-mono\"\n },\n chakraPetch: {\n label: \"Chakra Petch\",\n stack: \"\\\"Orbit Chakra Petch\\\", \\\"Chakra Petch\\\", \\\"Segoe UI Variable\\\", \\\"Segoe UI\\\", Arial, sans-serif\",\n className: \"font-chakra-petch\"\n },\n orbitron: {\n label: \"Orbitron\",\n stack: \"\\\"Orbit Orbitron\\\", \\\"Orbitron\\\", \\\"Segoe UI Variable\\\", \\\"Segoe UI\\\", Arial, sans-serif\",\n className: \"font-orbitron\"\n },\n rajdhani: {\n label: \"Rajdhani\",\n stack: \"\\\"Orbit Rajdhani\\\", \\\"Rajdhani\\\", \\\"Segoe UI Variable\\\", \\\"Segoe UI\\\", Arial, sans-serif\",\n className: \"font-rajdhani\"\n },\n runescapeUF: {\n label: \"Runescape UF\",\n stack: \"\\\"Orbit Runescape UF\\\", \\\"Cascadia Mono\\\", monospace\",\n className: \"font-runescape-uf\"\n },\n openRing: {\n label: \"Open Ring\",\n stack: \"\\\"Orbit Open Ring\\\", \\\"Segoe UI Variable\\\", \\\"Segoe UI\\\", Arial, sans-serif\",\n className: \"font-open-ring\"\n }\n});\n\n// Per-category overrides shown in the Appearance grid. Body text is not a\n// target: it always follows the primary font (`site`), so it drives\n// --orbit-font-body directly in applyFontPreferences instead.\nexport const FONT_TARGETS = Object.freeze({\n heading: {\n label: \"Headings\",\n cssVar: \"--orbit-font-heading\",\n dataAttr: \"fontHeading\"\n },\n control: {\n label: \"Controls\",\n cssVar: \"--orbit-font-control\",\n dataAttr: \"fontControl\"\n },\n label: {\n label: \"Labels\",\n cssVar: \"--orbit-font-label\",\n dataAttr: \"fontLabel\"\n },\n badge: {\n label: \"Badges\",\n cssVar: \"--orbit-font-badge\",\n dataAttr: \"fontBadge\"\n }\n});\n\nexport const LEGACY_FONT_TARGET_ALIASES = Object.freeze({\n ui: \"control\"\n});\n\nexport const DEFAULT_FONT_TARGET_PREFERENCES = Object.freeze({\n control: DEFAULT_SITE_FONT,\n heading: DEFAULT_SITE_FONT,\n label: DEFAULT_SITE_FONT,\n badge: DEFAULT_BADGE_FONT\n});\n\nexport const DEFAULT_FONT_PREFERENCES = Object.freeze({\n ...DEFAULT_FONT_TARGET_PREFERENCES,\n // Primary font: drives body text and the default for every override category.\n site: DEFAULT_SITE_FONT,\n // User size slider multiplier (drives --type-user-scale).\n userScale: DEFAULT_USER_SCALE\n});\n\nfunction hasOwn(object, key) {\n return Object.prototype.hasOwnProperty.call(object, key);\n}\n\nexport function clampUserScale(value) {\n const number = Number(value);\n if (!Number.isFinite(number)) return DEFAULT_USER_SCALE;\n return Math.min(USER_SCALE_MAX, Math.max(USER_SCALE_MIN, number));\n}\n\nexport function normalizeFontPreferences(value) {\n const input = value && typeof value === \"object\" ? value : {};\n const normalized = { ...DEFAULT_FONT_PREFERENCES };\n const explicitTargets = new Set();\n for (const key of Object.keys(FONT_TARGETS)) {\n if (typeof input[key] === \"string\" && hasOwn(FONT_OPTIONS, input[key])) {\n normalized[key] = input[key];\n explicitTargets.add(key);\n }\n }\n for (const [legacyKey, target] of Object.entries(LEGACY_FONT_TARGET_ALIASES)) {\n if (!explicitTargets.has(target) && typeof input[legacyKey] === \"string\" && hasOwn(FONT_OPTIONS, input[legacyKey])) {\n normalized[target] = input[legacyKey];\n }\n }\n if (typeof input.site === \"string\" && hasOwn(FONT_OPTIONS, input.site)) {\n normalized.site = input.site;\n }\n if (input.userScale !== undefined) {\n normalized.userScale = clampUserScale(input.userScale);\n }\n // Before the split, one \"label\" target drove both categories. Preserve a\n // customized label choice for badges unless badge was saved separately.\n if (!hasOwn(input, \"badge\") && hasOwn(input, \"label\") && input.label !== DEFAULT_SITE_FONT) {\n normalized.badge = normalized.label;\n }\n return normalized;\n}\n\nexport function storedFontPreferences(storage = globalThis.localStorage) {\n if (!storage) return { ...DEFAULT_FONT_PREFERENCES };\n try {\n const raw = storage.getItem(FONT_STORAGE_KEY);\n if (!raw) return { ...DEFAULT_FONT_PREFERENCES };\n return normalizeFontPreferences(JSON.parse(raw));\n } catch {\n return { ...DEFAULT_FONT_PREFERENCES };\n }\n}\n\nexport function fontStackFor(optionId) {\n return FONT_OPTIONS[optionId]?.stack || FONT_OPTIONS[DEFAULT_SITE_FONT].stack;\n}\n\nexport function applyFontPreferences(preferences = storedFontPreferences(), { doc = globalThis.document } = {}) {\n const normalized = normalizeFontPreferences(preferences);\n const root = doc?.documentElement;\n if (!root) return normalized;\n\n for (const [target, config] of Object.entries(FONT_TARGETS)) {\n const optionId = normalized[target];\n root.style?.setProperty?.(config.cssVar, fontStackFor(optionId));\n root.setAttribute?.(`data-${config.dataAttr.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}`, optionId);\n }\n\n // Body text (paragraphs, card titles, long-form prose, editors) always tracks\n // the primary font rather than being an independent category.\n root.style?.setProperty?.(\"--orbit-font-body\", fontStackFor(normalized.site));\n // The only size lever is the Appearance slider; font family no longer changes size.\n root.style?.setProperty?.(\"--type-user-scale\", String(normalized.userScale));\n root.setAttribute?.(\"data-font-site\", normalized.site);\n return normalized;\n}\n\nexport function setFontPreferences(preferences, {\n doc = globalThis.document,\n storage = globalThis.localStorage,\n eventTarget = globalThis.window\n} = {}) {\n const normalized = normalizeFontPreferences(preferences);\n storage?.setItem?.(FONT_STORAGE_KEY, JSON.stringify(normalized));\n applyFontPreferences(normalized, { doc });\n eventTarget?.dispatchEvent?.(new CustomEvent(FONT_CHANGE_EVENT, { detail: { preferences: normalized } }));\n return normalized;\n}\n\nexport function resetFontPreferences(options = {}) {\n options.storage?.removeItem?.(FONT_STORAGE_KEY);\n return setFontPreferences(DEFAULT_FONT_PREFERENCES, options);\n}\n\nexport function setFontPreference(target, optionId, options = {}) {\n if (!hasOwn(FONT_TARGETS, target)) throw new Error(`Unknown font target: ${target}`);\n if (!hasOwn(FONT_OPTIONS, optionId)) throw new Error(`Unknown font option: ${optionId}`);\n return setFontPreferences({ ...storedFontPreferences(options.storage), [target]: optionId }, options);\n}\n\n// Swap the whole site to a primary font: sets every target plus the `site`\n// driver. Per-target overrides can be applied afterward via setFontPreference.\nexport function setSiteFont(optionId, options = {}) {\n if (!hasOwn(FONT_OPTIONS, optionId)) throw new Error(`Unknown font option: ${optionId}`);\n const next = { ...storedFontPreferences(options.storage) };\n for (const target of Object.keys(FONT_TARGETS)) next[target] = optionId;\n next.site = optionId;\n return setFontPreferences(next, options);\n}\n\nexport function setUserScale(value, options = {}) {\n return setFontPreferences(\n { ...storedFontPreferences(options.storage), userScale: clampUserScale(value) },\n options\n );\n}\n\nexport function applyStoredFontPreferences(options = {}) {\n return applyFontPreferences(storedFontPreferences(options.storage), options);\n}\n", "// Board snapshot export: builds a ZIP of every board's `.orbit.json` and\n// triggers a browser download. Extracted from board-menu.js so both the Board\n// flyout's \"Export All\" and Settings \u2192 Appearance's \"Back up all boards\" can\n// reuse the exact same archive without importing the heavier board-menu module\n// (which would create a settings \u2194 board-menu import cycle). Depends only on\n// state/api/toast, so it stays safe to import from anywhere.\n\nimport { state } from \"./state.js\";\nimport { api } from \"./api.js\";\nimport { toast } from \"./toast.js\";\n\nconst crcTable = Array.from({ length: 256 }, (_, index) => {\n let crc = index;\n for (let bit = 0; bit < 8; bit += 1) {\n crc = crc & 1 ? 0xedb88320 ^ (crc >>> 1) : crc >>> 1;\n }\n return crc >>> 0;\n});\n\nfunction crc32(bytes) {\n let crc = 0xffffffff;\n for (const byte of bytes) crc = crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8);\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nfunction writeUint16(bytes, value) {\n bytes.push(value & 0xff, (value >>> 8) & 0xff);\n}\n\nfunction writeUint32(bytes, value) {\n bytes.push(value & 0xff, (value >>> 8) & 0xff, (value >>> 16) & 0xff, (value >>> 24) & 0xff);\n}\n\nfunction zipDateTime(date = new Date()) {\n return {\n time:\n ((date.getHours() & 0x1f) << 11) |\n ((date.getMinutes() & 0x3f) << 5) |\n (Math.floor(date.getSeconds() / 2) & 0x1f),\n date:\n (((date.getFullYear() - 1980) & 0x7f) << 9) |\n (((date.getMonth() + 1) & 0xf) << 5) |\n (date.getDate() & 0x1f)\n };\n}\n\nexport function createZip(files) {\n const encoder = new TextEncoder();\n const localParts = [];\n const centralParts = [];\n let offset = 0;\n const timestamp = zipDateTime();\n\n files.forEach((file) => {\n const nameBytes = encoder.encode(file.name);\n const dataBytes = encoder.encode(file.content);\n const checksum = crc32(dataBytes);\n const localHeader = [];\n writeUint32(localHeader, 0x04034b50);\n writeUint16(localHeader, 20);\n writeUint16(localHeader, 0x0800);\n writeUint16(localHeader, 0);\n writeUint16(localHeader, timestamp.time);\n writeUint16(localHeader, timestamp.date);\n writeUint32(localHeader, checksum);\n writeUint32(localHeader, dataBytes.length);\n writeUint32(localHeader, dataBytes.length);\n writeUint16(localHeader, nameBytes.length);\n writeUint16(localHeader, 0);\n localParts.push(new Uint8Array(localHeader), nameBytes, dataBytes);\n\n const centralHeader = [];\n writeUint32(centralHeader, 0x02014b50);\n writeUint16(centralHeader, 20);\n writeUint16(centralHeader, 20);\n writeUint16(centralHeader, 0x0800);\n writeUint16(centralHeader, 0);\n writeUint16(centralHeader, timestamp.time);\n writeUint16(centralHeader, timestamp.date);\n writeUint32(centralHeader, checksum);\n writeUint32(centralHeader, dataBytes.length);\n writeUint32(centralHeader, dataBytes.length);\n writeUint16(centralHeader, nameBytes.length);\n writeUint16(centralHeader, 0);\n writeUint16(centralHeader, 0);\n writeUint16(centralHeader, 0);\n writeUint16(centralHeader, 0);\n writeUint32(centralHeader, 0);\n writeUint32(centralHeader, offset);\n centralParts.push(new Uint8Array(centralHeader), nameBytes);\n\n offset += localHeader.length + nameBytes.length + dataBytes.length;\n });\n\n const centralOffset = offset;\n const centralSize = centralParts.reduce((sum, part) => sum + part.length, 0);\n const endHeader = [];\n writeUint32(endHeader, 0x06054b50);\n writeUint16(endHeader, 0);\n writeUint16(endHeader, 0);\n writeUint16(endHeader, files.length);\n writeUint16(endHeader, files.length);\n writeUint32(endHeader, centralSize);\n writeUint32(endHeader, centralOffset);\n writeUint16(endHeader, 0);\n\n return new Blob([...localParts, ...centralParts, new Uint8Array(endHeader)], { type: \"application/zip\" });\n}\n\nexport function downloadBlob(filename, blob) {\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = filename;\n document.body.append(anchor);\n anchor.click();\n anchor.remove();\n URL.revokeObjectURL(url);\n}\n\nexport function safeExportName(board, usedNames) {\n const base = String(board?.slug || board?.name || board?.id || \"board\")\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\") || \"board\";\n let name = `${base}.orbit.json`;\n let suffix = 2;\n while (usedNames.has(name)) {\n name = `${base}-${suffix}.orbit.json`;\n suffix += 1;\n }\n usedNames.add(name);\n return name;\n}\n\n/** Export every board the actor can see as a single ZIP of `.orbit.json`\n * snapshots. Resolves `true` once the download starts, `false` if there are\n * no boards. Throws on a failed export request so callers can surface it. */\nexport async function exportAllBoards({ includeAttachments = false } = {}) {\n const boards = state.data?.boards || [];\n if (!boards.length) {\n toast.error(\"No boards to export\");\n return false;\n }\n const suffix = includeAttachments ? \"?include_attachments=true\" : \"\";\n const usedNames = new Set();\n const files = [];\n for (const board of boards) {\n const snapshot = await api(`/api/boards/${encodeURIComponent(board.id)}/export${suffix}`);\n files.push({\n name: safeExportName(board, usedNames),\n content: JSON.stringify(snapshot, null, 2)\n });\n }\n const archive = createZip(files);\n const date = new Date().toISOString().slice(0, 10);\n downloadBlob(`orbit-boards-${date}${includeAttachments ? \".with-images\" : \"\"}.zip`, archive);\n toast.success(`Exported ${files.length} board${files.length === 1 ? \"\" : \"s\"}`);\n return true;\n}\n", "// Client-side update awareness. On boot we ask the server (GET /api/version)\n// whether a newer Orbit exists; if so we light a dot on the Settings button and\n// show a one-time toast. The Settings \u2192 Data \"Version & Updates\" card\n// reuses fetchVersionInfo/getUpdateInfo/syncUpdateBadge for \"Check now\".\n//\n// Only the server-backed \"full\" edition has /api/version; the preview edition\n// (IndexedDB, no server) and any fetch failure are swallowed silently \u2014 same\n// best-effort posture as help-menu.js's version pill.\n\nimport { toast } from \"./toast.js\";\nimport { navigate } from \"./router.js\";\nimport { state } from \"./state.js\";\nimport { edition } from \"./config.js\";\n\nconst TOAST_SEEN_KEY = \"orbit:updateToastSeen\";\n\nlet cachedInfo = null;\n\n/** Last /api/version payload (or null if not checked / unavailable). */\nexport function getUpdateInfo() {\n return cachedInfo;\n}\n\n/** Fetch version info. `force` adds ?refresh=1 so the server re-hits GitHub. */\nexport async function fetchVersionInfo({ force = false } = {}) {\n try {\n const res = await fetch(`./api/version${force ? \"?refresh=1\" : \"\"}`, { cache: \"no-store\" });\n if (!res.ok) return null;\n cachedInfo = await res.json();\n return cachedInfo;\n } catch {\n return null;\n }\n}\n\n/** Toggle the Settings-button dot to match the latest known state. */\nexport function syncUpdateBadge() {\n const show = Boolean(cachedInfo?.updateAvailable);\n const btn = document.getElementById(\"settingsBtn\");\n if (!btn) return;\n btn.classList.toggle(\"has-update\", show);\n const dot = btn.querySelector(\".topbar-update-dot\");\n if (dot) dot.hidden = !show;\n}\n\n/** Run once on boot: check, badge, and toast (deduped per detected version). */\nexport async function checkForUpdate() {\n if (edition !== \"full\") return;\n const info = await fetchVersionInfo();\n syncUpdateBadge();\n if (!info?.updateAvailable || !info.latest) return;\n\n if (localStorage.getItem(TOAST_SEEN_KEY) === info.latest) return;\n localStorage.setItem(TOAST_SEEN_KEY, info.latest);\n toast(`Orbit v${info.latest} is available \u2192`, \"info\", 8000, {\n onClick: () => navigate({ boardId: state.boardId, view: \"settings\", tab: \"data\" })\n });\n}\n", "// Project settings drawer (the cog/settings icon). Tabs: Lanes, Appearance,\n// Card Archive, Notes, Journal, AI, Repository. Owns lane CRUD/reorder, the\n// archive list, project context/notes form persistence, and per-tab handler wiring.\n\nimport { state, getSettingsTab, statesForProject, ticketsForProject, currentBoard } from \"./state.js\";\nimport { drawerInner, $ } from \"./dom.js\";\nimport { escapeHtml, formatDate, renderPreservedText, cleanText } from \"./format.js\";\nimport { api, withBoardQuery } from \"./api.js\";\nimport { toast, downloadJson } from \"./toast.js\";\nimport { renderDrawerShell } from \"./drawer.js\";\nimport { navigate } from \"./router.js\";\nimport { renderBoard } from \"./kanban.js\";\nimport { renderDetailCard, startInlineEdit } from \"./ticket-detail.js\";\nimport { load } from \"./app.js\";\nimport { features } from \"./config.js\";\nimport {\n applyReducedMotionPreference,\n browserPrefersReducedMotion,\n effectiveReducedMotionPreference,\n setReducedMotionPreference,\n storedReducedMotionPreference\n} from \"./motion-preference.js\";\nimport { currentTheme, toggleThemePreference } from \"./theme-preference.js\";\nimport {\n FONT_OPTIONS,\n FONT_TARGETS,\n SITE_FONT_OPTIONS,\n USER_SCALE_MIN,\n USER_SCALE_MAX,\n USER_SCALE_STEP,\n storedFontPreferences,\n setSiteFont,\n setUserScale,\n setFontPreference\n} from \"./font-preference.js\";\nimport { closeIconSvg } from \"./icons.js\";\nimport { exportAllBoards } from \"./board-export.js\";\nimport { getUpdateInfo, fetchVersionInfo, syncUpdateBadge } from \"./update-check.js\";\n\nconst repositoryDelete = {\n boardId: \"\",\n step: \"idle\",\n exported: false\n};\n\n/** @starlove/ui slider: WebKit fill reads --value (0\u2013100), set from min/max/value. */\nfunction syncSliderValue(input) {\n const min = Number(input.min) || 0;\n const max = Number(input.max) || 100;\n const value = Number(input.value);\n const span = max - min;\n const pct = span <= 0 ? 0 : ((value - min) / span) * 100;\n input.style.setProperty(\"--value\", String(pct));\n}\n\nfunction bindSliders(root) {\n root.querySelectorAll('input[type=\"range\"].slider').forEach((slider) => {\n syncSliderValue(slider);\n slider.addEventListener(\"input\", () => syncSliderValue(slider));\n });\n}\n\nexport async function renderProjectDetail() {\n const context = await api(`/api/boards/${state.boardId}/context?include_struck=true`);\n const bootstrapBoard = currentBoard();\n const project = {\n ...context.board,\n // `/api/boards/:id/context` is agent-safe and intentionally omits\n // human-only project notes. The Settings UI gets those notes from the\n // human bootstrap payload instead, so Notes can reload without turning\n // board_context/MCP into a notes surface.\n ...(bootstrapBoard?.id === context.board?.id ? { project_notes: bootstrapBoard.project_notes || \"\" } : {})\n };\n context.board = project;\n const activeTab = getSettingsTab();\n\n const tabs = [\n { id: \"lanes\", label: \"Lanes\" },\n { id: \"appearance\", label: \"Appearance\" },\n { id: \"archive\", label: \"Card Archive\" },\n { id: \"notes\", label: \"Notes\" },\n { id: \"journal\", label: \"Journal\" },\n ...(features.ai ? [{ id: \"ai\", label: \"AI\" }] : []),\n { id: \"data\", label: \"Data\" }\n ];\n\n const resolvedTab = activeTab === \"ai\" && !features.ai ? \"lanes\" : activeTab;\n\n renderDrawerShell({\n eyebrow: \"SETTINGS\",\n mode: \"settings\",\n tabs,\n activeTab: resolvedTab,\n onTabSelect: async (id) => {\n navigate({\n boardId: state.boardId,\n view: \"settings\",\n tab: id\n });\n },\n body: renderProjectTabBody(context, resolvedTab)\n });\n\n bindProjectTabHandlers(context, resolvedTab);\n}\n\nfunction renderProjectTabBody(context, tab) {\n switch (tab) {\n case \"notes\":\n return renderNotesSettingsTab(context);\n case \"lanes\":\n return renderProjectLanesTab();\n case \"appearance\":\n return renderProjectAppearanceTab();\n case \"ai\":\n return features.ai ? renderProjectAiTab(context) : renderProjectLanesTab();\n case \"journal\":\n return renderProjectJournalTab(context);\n case \"archive\":\n return renderProjectArchiveTab();\n case \"data\":\n default:\n return renderProjectDataTab(context);\n }\n}\n\nconst MCP_OS_OPTIONS = {\n windows: {\n label: \"Windows\",\n shell: \"PowerShell\",\n serverPath: \"C:\\\\Path\\\\To\\\\StarscapeOrbit\\\\src\\\\mcp-server.js\"\n },\n macos: {\n label: \"macOS\",\n shell: \"Terminal\",\n serverPath: \"/Users/you/apps/starscape-orbit/src/mcp-server.js\"\n },\n linux: {\n label: \"Linux\",\n shell: \"Terminal\",\n serverPath: \"/home/you/apps/starscape-orbit/src/mcp-server.js\"\n }\n};\n\nconst MCP_CLIENTS = {\n \"claude-code\": {\n label: \"Claude Code\",\n format: \"CLI command\",\n helper: \"Run this command once. Claude Code records the local Orbit tool server for the project.\"\n },\n codex: {\n label: \"Codex\",\n format: \"config.toml\",\n helper: \"Paste this TOML into Codex config. Project-local config may require the project to be trusted.\"\n },\n cursor: {\n label: \"Cursor\",\n format: \"MCP JSON\",\n helper: \"Paste this JSON into Cursor MCP settings. Cursor starts Orbit when an agent needs the tools.\"\n },\n vscode: {\n label: \"VS Code\",\n format: \"mcp.json\",\n helper: \"Paste this JSON into VS Code's user or workspace MCP configuration.\"\n },\n opencode: {\n label: \"OpenCode\",\n format: \"opencode.json\",\n helper: \"Paste this into OpenCode config under the local MCP server list.\"\n },\n openclaw: {\n label: \"OpenClaw\",\n format: \"MCP JSON\",\n helper: \"Paste this JSON into OpenClaw's MCP server list. OpenClaw will spawn Orbit on demand.\"\n },\n generic: {\n label: \"Other MCP app\",\n format: \"MCP JSON\",\n helper: \"Most MCP clients accept this JSON shape for local stdio servers.\"\n }\n};\n\nfunction renderProjectAiTab(context) {\n const project = context.board;\n const aiEnabled = project.ai_enabled !== 0;\n const agentContextSetup = aiEnabled ? renderAgentContextSection(project) : \"\";\n const helperFilesSetup = aiEnabled && features.multiBoard ? renderHelperFilesSection(project) : \"\";\n const mcpSetup = aiEnabled ? renderMcpSetupSection(context) : \"\";\n\n return `\n <div class=\"settings-stack\">\n <section class=\"settings-card\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">AI</h3>\n </header>\n <div class=\"settings-card-body\">\n <label class=\"orbit-check settings-toggle\" for=\"aiEnabledToggle\">\n <input\n type=\"checkbox\"\n id=\"aiEnabledToggle\"\n ${aiEnabled ? \"checked\" : \"\"}\n />\n <span class=\"orbit-check-box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" class=\"orbit-check-tick\"><path d=\"M3.5 8.5l3 3 6-7\" /></svg>\n </span>\n <span class=\"settings-toggle-text\">\n <span class=\"settings-row-title\">Enable AI</span>\n <span class=\"description\">Provisions the <strong>AI Ready</strong>, <strong>In Progress</strong>, and <strong>Review</strong> lanes if missing, surfaces agent context fields, and exposes the MCP setup snippet. Disabling AI hides the AI Ready column but keeps its cards in place.</span>\n </span>\n </label>\n </div>\n </section>\n ${agentContextSetup}\n ${helperFilesSetup}\n ${mcpSetup}\n </div>\n `;\n}\n\nfunction renderAgentContextSection(project) {\n const instructionsPlaceholder =\n \"This project is about\u2026\\n\\nHow any AI agent should use this board and work in this repo.\";\n const instructions = project.agent_instructions || \"\";\n const hasInstructions = Boolean(instructions.trim());\n const placeholderClass = hasInstructions ? \"\" : \"is-placeholder\";\n const inner = hasInstructions ? renderPreservedText(instructions) : escapeHtml(instructionsPlaceholder);\n return `\n <section class=\"settings-card ai-context-setup\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Agent Instructions</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row\">\n <p class=\"description\">This project-level context is provided to agents when they work on tickets.</p>\n <div class=\"inline-md-field\">\n <div\n class=\"inline-md-field-body preserved-text-body editable-field settings-agent-instructions-body ${placeholderClass}\"\n data-edit-field=\"agent_instructions\"\n tabindex=\"0\"\n title=\"Click to edit\"\n role=\"button\"\n aria-label=\"Edit Agent Instructions\"\n >${inner}</div>\n </div>\n </div>\n </div>\n </section>\n `;\n}\n\nfunction renderMcpSetupSection(context) {\n const osId = detectedMcpOs();\n const clientId = \"claude-code\";\n const paths = mcpDetectedPaths(context, osId);\n const configText = mcpConfigText(clientId, paths);\n const commandText = mcpRunCommand(osId, paths);\n const client = MCP_CLIENTS[clientId];\n return `\n <details class=\"settings-card settings-card--collapsible mcp-setup\" data-mcp-setup>\n <summary class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Connect Your Agent to MCP</h3>\n <svg class=\"settings-card-chevron\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\" /></svg>\n </summary>\n <div class=\"settings-card-body\">\n <div class=\"settings-row\">\n <p class=\"description\">A tiny service running on your computer alongside your AI agent, providing it with tools and context to collaborate with you more effectively. Tell your AI to use the snippet below, it knows what MCP is.</p>\n <div class=\"control-grid\">\n <label class=\"control-field\">\n <span class=\"control-field-label\">Operating system</span>\n <select id=\"mcpOsSelect\" class=\"select-chevron-field\">\n ${Object.entries(MCP_OS_OPTIONS)\n .map(([id, option]) => `<option value=\"${id}\" ${id === osId ? \"selected\" : \"\"}>${escapeHtml(option.label)}</option>`)\n .join(\"\")}\n </select>\n </label>\n <label class=\"control-field\">\n <span class=\"control-field-label\">Agent app</span>\n <select id=\"mcpClientSelect\" class=\"select-chevron-field\">\n ${Object.entries(MCP_CLIENTS)\n .map(([id, option]) => `<option value=\"${id}\" ${id === clientId ? \"selected\" : \"\"}>${escapeHtml(option.label)}</option>`)\n .join(\"\")}\n </select>\n </label>\n </div>\n <div class=\"control-grid control-grid--single mcp-path-grid\">\n <label class=\"control-field\">\n <span class=\"control-field-label\">Orbit MCP server file</span>\n <input id=\"mcpServerPathInput\" value=\"${escapeHtml(paths.serverPath)}\" />\n </label>\n </div>\n </div>\n\n <div class=\"settings-row\">\n <div class=\"mcp-options-stack\">\n <div class=\"mcp-option-card\">\n <div class=\"mcp-option-card-head\">\n <div>\n <strong data-mcp-output-title>${escapeHtml(client.label)} setup</strong>\n <p class=\"description\" data-mcp-helper>${escapeHtml(client.helper)}</p>\n </div>\n <button type=\"button\" data-variant=\"secondary\" data-copy-mcp=\"config\">Copy setup</button>\n </div>\n <div class=\"mcp-terminal\">\n <div class=\"mcp-terminal-chrome\" aria-hidden=\"true\"><span></span><span></span><span></span></div>\n <pre class=\"mcp-snippet\"><code data-mcp-config>${escapeHtml(configText)}</code></pre>\n </div>\n </div>\n\n <div class=\"mcp-or-divider\" aria-hidden=\"true\"><span>OR</span></div>\n\n <div class=\"mcp-option-card\">\n <div class=\"mcp-option-card-head\">\n <div>\n <strong>Manual run command</strong>\n <p class=\"description\">Use this only when an app asks you to start the MCP server yourself.</p>\n </div>\n <button type=\"button\" data-variant=\"secondary\" data-copy-mcp=\"command\">Copy command</button>\n </div>\n <div class=\"mcp-terminal\">\n <div class=\"mcp-terminal-chrome\" aria-hidden=\"true\"><span></span><span></span><span></span></div>\n <pre class=\"mcp-snippet mcp-snippet--compact\"><code data-mcp-command>${escapeHtml(commandText)}</code></pre>\n </div>\n </div>\n </div>\n </div>\n </div>\n </details>\n `;\n}\n\nfunction detectedMcpOs() {\n const platform = String(navigator.userAgentData?.platform || navigator.platform || navigator.userAgent || \"\").toLowerCase();\n if (platform.includes(\"win\")) return \"windows\";\n if (platform.includes(\"mac\")) return \"macos\";\n return \"linux\";\n}\n\nfunction mcpDefaultPaths(osId) {\n const option = MCP_OS_OPTIONS[osId] || MCP_OS_OPTIONS.linux;\n return {\n serverPath: option.serverPath\n };\n}\n\nfunction mcpDetectedPaths(context, osId) {\n const template = mcpDefaultPaths(osId);\n const deployment = context.deployment || {};\n return {\n serverPath: deployment.mcp_server_path || template.serverPath\n };\n}\n\nfunction mcpPathsFromForm() {\n return {\n serverPath: $(\"#mcpServerPathInput\")?.value || \"\"\n };\n}\n\nfunction mcpConfigText(clientId, paths) {\n if (clientId === \"claude-code\") return claudeCodeMcpCommand(paths);\n if (clientId === \"codex\") return codexMcpToml(paths);\n if (clientId === \"opencode\") return opencodeMcpJson(paths);\n if (clientId === \"vscode\") return vscodeMcpJson(paths);\n\n const config = {\n mcpServers: {\n \"starscape-orbit\": {\n command: \"node\",\n args: [paths.serverPath]\n }\n }\n };\n return JSON.stringify(config, null, 2);\n}\n\nfunction opencodeMcpJson(paths) {\n return JSON.stringify(\n {\n $schema: \"https://opencode.ai/config.json\",\n mcp: {\n \"starscape-orbit\": {\n type: \"local\",\n command: [\"node\", paths.serverPath],\n enabled: true\n }\n }\n },\n null,\n 2\n );\n}\n\nfunction vscodeMcpJson(paths) {\n return JSON.stringify(\n {\n servers: {\n starscapeOrbit: {\n type: \"stdio\",\n command: \"node\",\n args: [paths.serverPath]\n }\n }\n },\n null,\n 2\n );\n}\n\nfunction codexMcpToml(paths) {\n return `[mcp_servers.starscape-orbit]\ncommand = \"node\"\nargs = [\"${escapeToml(paths.serverPath)}\"]\nenabled = true`;\n}\n\nfunction claudeCodeMcpCommand(paths) {\n return [\"claude mcp add starscape-orbit\", \"--\", \"node\", shellQuote(paths.serverPath)].join(\" \");\n}\n\nfunction mcpRunCommand(osId, paths) {\n return `node ${shellQuote(paths.serverPath)}`;\n}\n\nfunction shellQuote(value) {\n return `\"${String(value || \"\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nfunction escapeToml(value) {\n return String(value || \"\").replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n}\n\nfunction renderProjectArchiveTab() {\n return `\n <p class=\"description\">Archived cards are hidden from the kanban, search, and agent claim-next. Restore to put a card back on the board, or delete to permanently remove it.</p>\n <div class=\"section\">\n <div id=\"archiveList\" class=\"archive-list\">Loading\u2026</div>\n </div>\n `;\n}\n\nfunction renderProjectDataTab(context) {\n const project = context.board;\n if (repositoryDelete.boardId !== project.id) {\n repositoryDelete.boardId = project.id;\n repositoryDelete.step = \"idle\";\n repositoryDelete.exported = false;\n }\n const repoMeta = features.multiBoard\n ? \"\"\n : `\n <section class=\"settings-card\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Data</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row\">\n <p class=\"description\">This board lives in your browser only. Export a snapshot if you want to move it to a real Orbit install, or import one to seed this preview.</p>\n </div>\n </div>\n </section>`;\n return `\n <div class=\"settings-stack\">\n ${renderUpdateCard()}\n\n ${repoMeta}\n\n ${features.multiBoard ? renderBoardRenameSection(project) : \"\"}\n\n <section class=\"settings-card\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Board Snapshot</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row\">\n <p class=\"description\">Import accepts Orbit snapshots or Trello board JSON exports. The default import creates a separate board and leaves this board untouched.</p>\n ${features.attachments ? `\n <label class=\"orbit-check settings-toggle\">\n <input type=\"checkbox\" id=\"exportProjectImages\" />\n <span class=\"orbit-check-box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" class=\"orbit-check-tick\"><path d=\"M3.5 8.5l3 3 6-7\" /></svg>\n </span>\n <span class=\"settings-toggle-text\">\n <span class=\"settings-row-title\">Include attached images</span>\n </span>\n </label>\n ` : \"\"}\n <div class=\"deployment-actions\">\n <button type=\"button\" data-variant=\"primary\" id=\"exportProject\">Export</button>\n <input type=\"file\" id=\"importSnapshotAsNewFile\" class=\"import-file-input\" accept=\".orbit.json,.json,application/json\" />\n <button type=\"button\" data-variant=\"primary\" id=\"importSnapshotAsNewButton\">Import as New Board</button>\n </div>\n </div>\n </div>\n </section>\n\n <section class=\"settings-card settings-card--danger\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Replace Current Board</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row\">\n <p class=\"description\">Advanced: replace this board from an Orbit snapshot or Trello export after making the normal pre-import backup. Type <strong>${escapeHtml(project.slug || \"\")}</strong> to enable replacement.</p>\n <label class=\"control-field repository-confirm-field\">\n <span class=\"control-field-label\">Board slug</span>\n <input id=\"replaceImportConfirmInput\" autocomplete=\"off\" spellcheck=\"false\" placeholder=\"${escapeHtml(project.slug || \"\")}\" />\n </label>\n <div class=\"deployment-actions\">\n <input type=\"file\" id=\"replaceCurrentBoardImportFile\" class=\"import-file-input\" accept=\".orbit.json,.json,application/json\" disabled />\n <button type=\"button\" data-variant=\"primary\" data-arc=\"danger\" id=\"replaceCurrentBoardImportButton\" disabled>Replace Current Board</button>\n </div>\n </div>\n </div>\n </section>\n\n ${features.multiBoard ? renderDeleteBoardSection(project) : \"\"}\n </div>\n `;\n}\n\nfunction renderHelperFilesSection(project) {\n const hasFolder = Boolean(project.system_path);\n const managed = Boolean(project.manage_helper_files);\n return `\n <section class=\"settings-card helper-files-section\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">AI Helper Files</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row\">\n <p class=\"description\">Orbit can keep <code>SKILL-ORBIT.md</code> and <code>AGENTS.md</code> in this board's coding project folder so your AI agent knows how to use Orbit.${hasFolder ? \"\" : \" Link a folder to enable this.\"}</p>\n <div class=\"folder-picker-field helper-files-folder\">\n <input id=\"helperFolderInput\" type=\"text\" readonly placeholder=\"No folder linked\" value=\"${escapeHtml(project.system_path || \"\")}\" />\n <button type=\"button\" id=\"helperPickFolderBtn\">${hasFolder ? \"Change\" : \"Browse\"}</button>\n </div>\n <label class=\"orbit-check settings-toggle\">\n <input type=\"checkbox\" id=\"manageHelperFilesToggle\" ${managed ? \"checked\" : \"\"} ${hasFolder ? \"\" : \"disabled\"} />\n <span class=\"orbit-check-box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" class=\"orbit-check-tick\"><path d=\"M3.5 8.5l3 3 6-7\" /></svg>\n </span>\n <span class=\"settings-toggle-text\">\n <span class=\"settings-row-title\">Generate &amp; maintain helper files in this folder</span>\n </span>\n </label>\n </div>\n </div>\n </section>\n `;\n}\n\nfunction renderBoardRenameSection(project) {\n return `\n <section class=\"settings-card board-rename-section\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Board Name</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row\">\n <p class=\"description\">Rename the board display name only. The canonical URL slug stays <strong>${escapeHtml(project.slug || \"\")}</strong>, so existing board links keep working.</p>\n <form id=\"boardRenameForm\" class=\"field-form\">\n <label class=\"control-field\">\n <span class=\"control-field-label\">Display name</span>\n <input name=\"name\" value=\"${escapeHtml(project.name || \"\")}\" maxlength=\"120\" required />\n </label>\n <button type=\"submit\" data-variant=\"primary\">Rename Board</button>\n </form>\n </div>\n </div>\n </section>\n `;\n}\n\nfunction renderDeleteBoardSection(project) {\n const slug = escapeHtml(project.slug || \"\");\n if (repositoryDelete.step === \"choice\") {\n return `\n <section class=\"settings-card settings-card--danger\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Delete Board</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row\">\n <p class=\"description\">Delete this board from Orbit and remove its repo-local Orbit files. Export a snapshot first if you may need this board again.</p>\n <div class=\"repository-delete-actions\">\n <button type=\"button\" data-variant=\"primary\" id=\"deleteBoardExportFirst\">Export first</button>\n <button type=\"button\" data-variant=\"primary\" data-arc=\"danger\" id=\"deleteBoardSkipExport\">Delete without exporting</button>\n <button type=\"button\" data-variant=\"ghost\" id=\"deleteBoardCancel\">Cancel</button>\n </div>\n </div>\n </div>\n </section>\n `;\n }\n\n if (repositoryDelete.step === \"confirm\") {\n const exportedCopy = repositoryDelete.exported\n ? \"Snapshot exported. Type the board slug to confirm permanent deletion.\"\n : \"Type the board slug to confirm permanent deletion.\";\n return `\n <section class=\"settings-card settings-card--danger is-confirming\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Delete Board</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row\">\n <p class=\"description\">${escapeHtml(exportedCopy)}</p>\n <label class=\"control-field repository-confirm-field\">\n <span class=\"control-field-label\">Board slug</span>\n <strong>${slug}</strong>\n <input id=\"deleteBoardConfirmInput\" autocomplete=\"off\" spellcheck=\"false\" placeholder=\"${slug}\" autofocus />\n </label>\n <div class=\"repository-delete-actions\">\n <button type=\"button\" data-variant=\"primary\" data-arc=\"danger\" id=\"deleteBoardConfirm\" disabled>Delete board permanently</button>\n <button type=\"button\" data-variant=\"ghost\" id=\"deleteBoardCancel\">Cancel</button>\n </div>\n </div>\n </div>\n </section>\n `;\n }\n\n return `\n <section class=\"settings-card settings-card--danger\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Delete Board</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row\">\n <p class=\"description\">Remove this board from Orbit and delete its repo-local Orbit files. This cannot be undone without an exported snapshot.</p>\n <button type=\"button\" data-variant=\"primary\" data-arc=\"danger\" id=\"deleteBoardStart\">Delete Board</button>\n </div>\n </div>\n </section>\n `;\n}\n\nfunction renderNotesSettingsTab(context) {\n const project = context.board;\n const notesPlaceholder =\n \"Remember to mention SKILL-ORBIT.md to my AI agents if they get confused\";\n const notes = project.project_notes || \"\";\n const hasNotes = Boolean(notes.trim());\n const placeholderClass = hasNotes ? \"\" : \"is-placeholder\";\n const inner = hasNotes ? renderPreservedText(notes) : escapeHtml(notesPlaceholder);\n return `\n <div class=\"section settings-notes-section\">\n <div class=\"inline-md-field\">\n <span class=\"inline-md-field-label font-orbitron\">Notes For You</span>\n <div\n class=\"inline-md-field-body preserved-text-body editable-field settings-notes-body ${placeholderClass}\"\n data-edit-field=\"project_notes\"\n tabindex=\"0\"\n title=\"Click to edit\"\n role=\"button\"\n aria-label=\"Edit Notes For You\"\n >${inner}</div>\n </div>\n </div>\n `;\n}\n\nfunction renderProjectLanesTab() {\n const showPriority = state.showPriority;\n return `\n <div class=\"section\">\n <label class=\"orbit-check settings-toggle\" for=\"showPriorityToggle\">\n <input\n type=\"checkbox\"\n id=\"showPriorityToggle\"\n ${showPriority ? \"checked\" : \"\"}\n />\n <span class=\"orbit-check-box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" class=\"orbit-check-tick\"><path d=\"M3.5 8.5l3 3 6-7\" /></svg>\n </span>\n <span class=\"settings-toggle-text\">\n <span class=\"settings-row-title\">Show priority label on cards</span>\n </span>\n </label>\n <p class=\"description lanes-description\">Rename, reorder, add, or remove lanes.</p>\n ${renderLaneManager()}\n <form id=\"laneCreateForm\" class=\"lane-create-form\">\n <input name=\"name\" placeholder=\"New lane name...\" required />\n <button type=\"submit\" data-variant=\"primary\">Add Lane</button>\n </form>\n </div>\n `;\n}\n\nconst UPDATE_INSTRUCTIONS = {\n source: \"git pull\\npnpm install\\npnpm run build:bundle\\n# then restart Orbit\",\n docker: \"git pull\\ndocker compose build\\ndocker compose up -d\",\n dist: \"npm install -g @starlove/orbit@latest\\n# then restart Orbit\"\n};\n\nconst UPDATE_MODE_LABEL = {\n source: \"local / server\",\n docker: \"Docker\",\n dist: \"npm\"\n};\n\nconst updateCheckGlyph = `<svg viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" d=\"M16.7 5.3a1 1 0 0 1 0 1.4l-7.5 7.5a1 1 0 0 1-1.4 0L4.3 10.7a1 1 0 1 1 1.4-1.4l2.8 2.8 6.8-6.8a1 1 0 0 1 1.4 0z\" clip-rule=\"evenodd\"/></svg>`;\n\n// \"Version & Updates\" card (top of the Data tab). Reads the cached /api/version\n// payload (populated by the boot-time check in update-check.js); renders\n// neutrally when it's missing (preview edition / check disabled). The whole\n// card gains an accent when an update is available so it reads at a glance.\nfunction renderUpdateCard() {\n const info = getUpdateInfo();\n const mode = info?.deployMode || \"source\";\n const available = Boolean(info?.updateAvailable);\n const current = info?.current ? `v${escapeHtml(info.current)}` : \"\u2014\";\n const showSelfUpdate = Boolean(info?.selfUpdate && available);\n\n const chip = !info\n ? `<span class=\"update-status-chip update-status-chip--idle\">Not checked</span>`\n : info.error\n ? `<span class=\"update-status-chip update-status-chip--warn\">Couldn't check</span>`\n : available\n ? `<span class=\"update-status-chip update-status-chip--available\"><span class=\"update-status-dot\" aria-hidden=\"true\"></span>Update available</span>`\n : `<span class=\"update-status-chip update-status-chip--current\">${updateCheckGlyph} Up to date</span>`;\n\n const statusLine = !info\n ? \"Check whether a newer version of Orbit has shipped.\"\n : info.error\n ? `Couldn't reach GitHub (${escapeHtml(info.error)}). Try again in a moment.`\n : available\n ? \"Back up your boards, then update with the steps below.\"\n : \"You have the latest version of Orbit.\";\n\n const versionBlock = available\n ? `<span class=\"update-version-now\">${current}</span>\n <span class=\"update-version-arrow\" aria-hidden=\"true\">\u2192</span>\n <span class=\"update-version-next\">v${escapeHtml(info.latest)}</span>`\n : `<span class=\"update-version-now\">${current}</span>`;\n\n const howto = available\n ? `\n <details class=\"update-howto\" open>\n <summary>How to update <span class=\"update-howto-mode\">${escapeHtml(UPDATE_MODE_LABEL[mode] || mode)}</span></summary>\n <pre class=\"update-commands\"><code id=\"updateCommands\">${escapeHtml(UPDATE_INSTRUCTIONS[mode] || UPDATE_INSTRUCTIONS.source)}</code></pre>\n <div class=\"update-howto-foot\">\n <button type=\"button\" data-variant=\"ghost\" id=\"updateCopyCommands\">Copy commands</button>\n ${info.changesUrl ? `<a class=\"update-changes-link\" href=\"${escapeHtml(info.changesUrl)}\" target=\"_blank\" rel=\"noopener\">View changes \u2197</a>` : \"\"}\n </div>\n </details>`\n : \"\";\n\n return `\n <section class=\"settings-card update-card${available ? \" update-card--available\" : \"\"}\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Version &amp; Updates</h3>\n ${chip}\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row update-row\">\n <div class=\"update-version-line\">${versionBlock}</div>\n <p class=\"description\" id=\"updateStatusLine\">${statusLine}</p>\n <div class=\"deployment-actions update-actions\">\n <button type=\"button\" data-variant=\"${available ? \"secondary\" : \"primary\"}\" id=\"updateCheckNow\">Check now</button>\n <button type=\"button\" data-variant=\"secondary\" id=\"updateBackupBoards\">Back up all boards</button>\n ${showSelfUpdate ? `<button type=\"button\" data-variant=\"primary\" id=\"updateRunNow\">Update now</button>` : \"\"}\n </div>\n ${howto}\n <p class=\"description update-docs-hint\">Full guide: <a href=\"https://github.com/brucestarlove/ss-orbit/blob/master/docs/UPDATING.md\" target=\"_blank\" rel=\"noopener\">docs/UPDATING.md</a></p>\n </div>\n </div>\n </section>`;\n}\n\nfunction renderProjectAppearanceTab() {\n const theme = currentTheme();\n const reduceMotion = effectiveReducedMotionPreference();\n const storedMotion = storedReducedMotionPreference();\n const browserDefault = browserPrefersReducedMotion();\n const sourceLabel = storedMotion === null\n ? `Using browser default (${browserDefault ? \"reduced motion\" : \"motion allowed\"}).`\n : \"Using your saved preference.\";\n\n return `\n <div class=\"settings-stack appearance-settings\">\n <section class=\"settings-card\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Theme</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-toggle\">\n <button\n type=\"button\"\n class=\"topbar-btn topbar-ctl-shrink\"\n data-variant=\"theme\"\n id=\"appearanceThemeToggle\"\n aria-label=\"Toggle theme\"\n >\n <svg class=\"topbar-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\">${themeIconMarkup(theme)}</svg>\n </button>\n <span class=\"settings-toggle-text\">\n <span class=\"settings-row-title\" id=\"appearanceThemeLabel\">${theme === \"dark\" ? \"Dark\" : \"Light\"}</span>\n <span class=\"description\">Tap to switch between the light and dark theme used across the app.</span>\n </span>\n </div>\n <div class=\"settings-toggle\">\n <button\n type=\"button\"\n class=\"topbar-btn topbar-ctl-shrink motion-toggle\"\n data-variant=\"theme\"\n id=\"appearanceMotionToggle\"\n aria-pressed=\"${reduceMotion ? \"true\" : \"false\"}\"\n aria-label=\"Toggle reduced theme motion\"\n >\n ${motionIconMarkup()}\n </button>\n <span class=\"settings-toggle-text\">\n <span class=\"settings-row-title\">Reduce theme motion</span>\n <span class=\"description\">Turns off the animated starfield, meteors, and theme animations. ${escapeHtml(sourceLabel)}</span>\n </span>\n </div>\n </div>\n </section>\n ${renderTypographyControls()}\n </div>\n `;\n}\n\nfunction renderTypographyControls() {\n const prefs = storedFontPreferences();\n const siteOptions = SITE_FONT_OPTIONS\n .map((id) => `<option value=\"${id}\"${id === prefs.site ? \" selected\" : \"\"}>${escapeHtml(FONT_OPTIONS[id]?.label || id)}</option>`)\n .join(\"\");\n const overrideSelects = Object.entries(FONT_TARGETS).map(([target, config]) => {\n const current = prefs[target];\n const options = Object.entries(FONT_OPTIONS)\n .map(([id, font]) => `<option value=\"${id}\"${id === current ? \" selected\" : \"\"}>${escapeHtml(font.label)}</option>`)\n .join(\"\");\n return `\n <label class=\"control-field\">\n <span class=\"control-field-label\">${escapeHtml(config.label)}</span>\n <select class=\"select-chevron-field\" data-font-target=\"${target}\">${options}</select>\n </label>\n `;\n }).join(\"\");\n\n return `\n <section class=\"settings-card appearance-typography-card\">\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">Typography</h3>\n </header>\n <div class=\"settings-card-body\">\n <div class=\"settings-row settings-slider-row\">\n <span class=\"control-field-label\">Text size</span>\n <input type=\"range\" class=\"slider\" id=\"fontScaleSlider\" min=\"${USER_SCALE_MIN}\" max=\"${USER_SCALE_MAX}\" step=\"${USER_SCALE_STEP}\" value=\"${prefs.userScale}\" aria-label=\"Text size\" />\n <output id=\"fontScaleValue\" class=\"control-value\">${Math.round(prefs.userScale * 100)}%</output>\n </div>\n <div class=\"settings-row\">\n <label class=\"control-field\">\n <span class=\"control-field-label\">Primary Font</span>\n <select class=\"select-chevron-field\" id=\"siteFontSelect\">${siteOptions}</select>\n </label>\n </div>\n <div class=\"settings-row\">\n <div class=\"control-grid typography-overrides\">${overrideSelects}</div>\n </div>\n </div>\n </section>\n `;\n}\n\n// Mirrors the topbar theme toggle: moon when dark is active, sun when light.\nfunction themeIconMarkup(theme) {\n return theme === \"dark\"\n ? '<path d=\"M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z\" />'\n : '<circle cx=\"12\" cy=\"12\" r=\"5\" /><path d=\"M12 1v2m0 18v2M4.2 4.2l1.4 1.4m12.8 12.8l1.4 1.4M1 12h2m18 0h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4\" />';\n}\n\n// Twinkling starfield for the motion toggle. Stars shimmer (CSS) while motion\n// is allowed and freeze when the button is pressed (reduced). Each star's\n// --d staggers its animation so the field reads as alive, not pulsing in unison.\nfunction motionIconMarkup() {\n const stars = [\n { cx: 6, cy: 7, r: 1.1, d: \"0s\" },\n { cx: 17.5, cy: 6, r: 1.5, d: \"0.5s\" },\n { cx: 12, cy: 12, r: 1, d: \"0.9s\" },\n { cx: 7.5, cy: 17, r: 1.4, d: \"0.25s\" },\n { cx: 18, cy: 16.5, r: 1.1, d: \"0.7s\" }\n ]\n .map((s) => `<circle class=\"motion-star\" cx=\"${s.cx}\" cy=\"${s.cy}\" r=\"${s.r}\" style=\"animation-delay:${s.d}\" />`)\n .join(\"\");\n return `<svg class=\"topbar-icon motion-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" aria-hidden=\"true\">${stars}</svg>`;\n}\n\nfunction renderProjectJournalTab(context) {\n const aiEnabled = context.board?.ai_enabled !== 0;\n return `\n ${aiEnabled ? `<p class=\"description\">Agent-facing project memory: decisions to follow and lessons to apply. Struck entries stay visible here but are excluded from agent context.</p>` : \"\"}\n <div class=\"section\">\n ${renderProjectEntries(context.entries, aiEnabled)}\n <form id=\"projectEntryForm\" class=\"comment-form project-entry-form\">\n <div class=\"project-entry-form-header\">Add entry</div>\n <select name=\"type\" class=\"select-chevron-field\" aria-label=\"Entry type\">\n <option value=\"decision\">Decision</option>\n <option value=\"lesson\">Lesson</option>\n </select>\n <input name=\"title\" placeholder=\"Entry title...\" required />\n <textarea name=\"body\" placeholder=\"Decision rationale or lesson: do X instead of Y when working with Z.\" required></textarea>\n <button type=\"submit\" data-variant=\"primary\">Add Entry</button>\n </form>\n </div>\n `;\n}\n\nfunction parseImportSnapshotText(text) {\n const trimmed = String(text || \"\").trimStart();\n if (trimmed.startsWith(\"<\")) {\n throw new Error(\"That file looks like an HTML page instead of JSON. In Trello, use Export JSON/download the board JSON, not Save Page As.\");\n }\n try {\n return JSON.parse(text);\n } catch (error) {\n throw new Error(error?.message || \"invalid JSON\");\n }\n}\n\nfunction bindProjectTabHandlers(context, tab) {\n const project = context.board;\n\n if (tab === \"data\") {\n const exportSnapshot = async (includeAttachments = Boolean($(\"#exportProjectImages\")?.checked)) => {\n const suffix = includeAttachments ? \"?include_attachments=true\" : \"\";\n const snapshot = await api(`/api/boards/${encodeURIComponent(project.id)}/export${suffix}`);\n const filename = includeAttachments ? `${project.slug}.with-images.orbit.json` : `${project.slug}.orbit.json`;\n downloadJson(filename, snapshot);\n };\n\n $(\"#exportProject\")?.addEventListener(\"click\", async () => {\n await exportSnapshot();\n });\n\n $(\"#boardRenameForm\")?.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n const nextName = String(form.get(\"name\") || \"\").trim();\n if (!nextName || nextName === project.name) return;\n await api(`/api/boards/${encodeURIComponent(project.id)}`, {\n method: \"PATCH\",\n body: { name: nextName }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(`Renamed board to ${nextName}. Canonical slug unchanged: ${project.slug}`);\n });\n\n const importSnapshotFile = async (file, bodyForSnapshot) => {\n const text = await file.text();\n const snapshot = parseImportSnapshotText(text);\n return api(\"/api/admin/import\", {\n method: \"POST\",\n body: bodyForSnapshot(snapshot)\n });\n };\n\n const importSnapshotAsNewFile = $(\"#importSnapshotAsNewFile\");\n $(\"#importSnapshotAsNewButton\")?.addEventListener(\"click\", () => {\n importSnapshotAsNewFile?.click();\n });\n\n importSnapshotAsNewFile?.addEventListener(\"change\", async (event) => {\n const input = event.currentTarget;\n const file = input.files?.[0];\n if (!file) return;\n try {\n const result = await importSnapshotFile(file, (snapshot) => ({ snapshot, create_new: true, board_id: project.id }));\n state.boardId = result.imported_board_id;\n state.boardSlug = result.imported_board_slug;\n state.detailMode = \"empty\";\n await load();\n await navigate({ boardId: result.imported_board_id, view: \"board\" });\n const counts = result.imported_counts || {};\n const cardCount = Number.isFinite(Number(counts.tickets)) ? ` (${counts.tickets} cards)` : \"\";\n toast.success(result.source_format === \"trello-board-export\" ? `Trello board imported as new board${cardCount}` : \"Board imported as new board\");\n } catch (err) {\n toast.error(`Import failed: ${err?.message || \"invalid JSON\"}`);\n } finally {\n input.value = \"\";\n }\n });\n\n const replaceImportConfirmInput = $(\"#replaceImportConfirmInput\");\n const replaceCurrentBoardImportFile = $(\"#replaceCurrentBoardImportFile\");\n const replaceCurrentBoardImportButton = $(\"#replaceCurrentBoardImportButton\");\n replaceImportConfirmInput?.addEventListener(\"input\", () => {\n const disabled = replaceImportConfirmInput.value.trim() !== project.slug;\n if (replaceCurrentBoardImportFile) replaceCurrentBoardImportFile.disabled = disabled;\n if (replaceCurrentBoardImportButton) replaceCurrentBoardImportButton.disabled = disabled;\n });\n\n replaceCurrentBoardImportButton?.addEventListener(\"click\", () => {\n if (replaceCurrentBoardImportButton.disabled || replaceCurrentBoardImportFile?.disabled) return;\n replaceCurrentBoardImportFile?.click();\n });\n\n replaceCurrentBoardImportFile?.addEventListener(\"change\", async (event) => {\n const input = event.currentTarget;\n const file = input.files?.[0];\n if (!file) return;\n if (replaceImportConfirmInput.value.trim() !== project.slug) {\n toast.error(\"Type the board slug before replacing this board.\");\n input.value = \"\";\n return;\n }\n try {\n const result = await importSnapshotFile(file, (snapshot) => ({ snapshot, replace_existing: true, board_id: project.id }));\n await load();\n state.detailMode = \"settings\";\n const counts = result.imported_counts || {};\n const cardCount = Number.isFinite(Number(counts.tickets)) ? ` (${counts.tickets} cards)` : \"\";\n toast.success(result.source_format === \"trello-board-export\" ? `Trello board replaced from Trello import${cardCount}` : \"Board replaced from snapshot\");\n } catch (err) {\n toast.error(`Import failed: ${err?.message || \"invalid JSON\"}`);\n } finally {\n input.value = \"\";\n }\n });\n\n $(\"#deleteBoardStart\")?.addEventListener(\"click\", async () => {\n repositoryDelete.step = \"choice\";\n repositoryDelete.exported = false;\n await renderProjectDetail();\n });\n\n $(\"#deleteBoardExportFirst\")?.addEventListener(\"click\", async () => {\n await exportSnapshot();\n repositoryDelete.step = \"confirm\";\n repositoryDelete.exported = true;\n await renderProjectDetail();\n });\n\n $(\"#deleteBoardSkipExport\")?.addEventListener(\"click\", async () => {\n repositoryDelete.step = \"confirm\";\n repositoryDelete.exported = false;\n await renderProjectDetail();\n });\n\n $(\"#deleteBoardCancel\")?.addEventListener(\"click\", async () => {\n repositoryDelete.step = \"idle\";\n repositoryDelete.exported = false;\n await renderProjectDetail();\n });\n\n const confirmInput = $(\"#deleteBoardConfirmInput\");\n const confirmButton = $(\"#deleteBoardConfirm\");\n confirmInput?.addEventListener(\"input\", () => {\n if (confirmButton) confirmButton.disabled = confirmInput.value.trim() !== project.slug;\n });\n confirmButton?.addEventListener(\"click\", async () => {\n await api(`/api/boards/${encodeURIComponent(project.id)}`, {\n method: \"DELETE\",\n body: { confirm_slug: project.slug, delete_files: true }\n });\n repositoryDelete.step = \"idle\";\n repositoryDelete.exported = false;\n await load();\n toast.success(`Deleted board: ${project.name}`);\n navigate({ boardId: state.boardId, view: \"board\" }, { replace: true });\n });\n\n // Version & Updates card (top of the Data tab).\n $(\"#updateCheckNow\")?.addEventListener(\"click\", async () => {\n const btn = $(\"#updateCheckNow\");\n btn.disabled = true;\n btn.textContent = \"Checking\u2026\";\n await fetchVersionInfo({ force: true });\n syncUpdateBadge();\n state.detailMode = \"settings\";\n await renderProjectDetail();\n });\n\n $(\"#updateBackupBoards\")?.addEventListener(\"click\", async () => {\n const btn = $(\"#updateBackupBoards\");\n const orig = btn.textContent;\n btn.disabled = true;\n btn.textContent = \"Backing up\u2026\";\n try {\n await exportAllBoards();\n } catch (error) {\n toast.error(`Backup failed: ${error?.message || \"request failed\"}`);\n } finally {\n btn.disabled = false;\n btn.textContent = orig;\n }\n });\n\n $(\"#updateCopyCommands\")?.addEventListener(\"click\", async () => {\n const text = $(\"#updateCommands\")?.textContent || \"\";\n try {\n await navigator.clipboard.writeText(text);\n toast.success(\"Update commands copied\");\n } catch {\n toast.error(\"Couldn't copy \u2014 select the commands manually\");\n }\n });\n\n $(\"#updateRunNow\")?.addEventListener(\"click\", async () => {\n const ok = window.confirm(\n \"Update Orbit now? It will pull the latest code, rebuild, and restart. Back up your boards first.\"\n );\n if (!ok) return;\n const btn = $(\"#updateRunNow\");\n btn.disabled = true;\n btn.textContent = \"Updating\u2026\";\n try {\n await api(\"/api/update\", { method: \"POST\" });\n toast.success(\"Update started \u2014 Orbit will restart shortly. Reload in a minute.\", 9000);\n } catch (error) {\n toast.error(`Update failed to start: ${error?.message || \"request failed\"}`);\n btn.disabled = false;\n btn.textContent = \"Update now\";\n }\n });\n }\n\n if (tab === \"notes\") {\n const notesEl = drawerInner.querySelector('[data-edit-field=\"project_notes\"]');\n if (notesEl) {\n const edit = () =>\n startInlineEdit(notesEl, {\n fieldName: \"project_notes\",\n multiline: true,\n initialValue: project.project_notes || \"\",\n ariaLabel: \"Edit Notes For You\",\n rerender: async () => {\n state.detailMode = \"settings\";\n await renderProjectDetail();\n },\n commit: async (next) => {\n await api(`/api/boards/${project.id}`, {\n method: \"PATCH\",\n body: { project_notes: cleanText(next) }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Saved\");\n }\n });\n notesEl.addEventListener(\"click\", (event) => {\n event.preventDefault();\n edit();\n });\n notesEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n edit();\n }\n });\n }\n }\n\n if (tab === \"lanes\") {\n drawerInner.querySelectorAll(\"[data-lane-action]\").forEach((button) => {\n button.addEventListener(\"click\", async () => {\n await handleLaneAction(button);\n });\n });\n\n drawerInner.querySelectorAll(\".lane-row input, .lane-row select\").forEach((field) => {\n field.addEventListener(\"change\", async () => {\n await updateLane(field.closest(\".lane-row\"));\n });\n });\n\n $(\"#laneCreateForm\")?.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n await api(`/api/boards/${project.id}/states`, {\n method: \"POST\",\n body: Object.fromEntries(form.entries())\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Lane added\");\n });\n\n $(\"#showPriorityToggle\")?.addEventListener(\"change\", (event) => {\n state.showPriority = !!event.currentTarget.checked;\n localStorage.setItem(\"mab_show_priority\", state.showPriority ? \"true\" : \"false\");\n renderBoard();\n });\n }\n\n if (tab === \"appearance\") {\n const themeToggleBtn = $(\"#appearanceThemeToggle\");\n if (themeToggleBtn) {\n const themeLabel = $(\"#appearanceThemeLabel\");\n const themeIcon = themeToggleBtn.querySelector(\".topbar-icon\");\n themeToggleBtn.addEventListener(\"click\", () => {\n const theme = toggleThemePreference();\n if (themeIcon) themeIcon.innerHTML = themeIconMarkup(theme);\n if (themeLabel) themeLabel.textContent = theme === \"dark\" ? \"Dark\" : \"Light\";\n toast.success(theme === \"dark\" ? \"Dark theme enabled\" : \"Light theme enabled\");\n });\n }\n\n const motionToggleBtn = $(\"#appearanceMotionToggle\");\n motionToggleBtn?.addEventListener(\"click\", () => {\n const reduce = motionToggleBtn.getAttribute(\"aria-pressed\") !== \"true\";\n motionToggleBtn.setAttribute(\"aria-pressed\", reduce ? \"true\" : \"false\");\n setReducedMotionPreference(reduce);\n applyReducedMotionPreference();\n window.dispatchEvent(new CustomEvent(\"orbit:motion-preference-change\", { detail: { reduce } }));\n toast.success(reduce ? \"Theme motion reduced\" : \"Theme motion enabled\");\n });\n\n // Primary font swap resets every override, so reflect that in the category\n // selects without re-fetching/re-rendering the whole drawer.\n $(\"#siteFontSelect\")?.addEventListener(\"change\", (event) => {\n const next = setSiteFont(event.currentTarget.value);\n drawerInner.querySelectorAll(\"select[data-font-target]\").forEach((select) => {\n select.value = next[select.dataset.fontTarget];\n });\n toast.success(`Primary font: ${FONT_OPTIONS[next.site]?.label || \"updated\"}`);\n });\n\n const fontScaleSlider = $(\"#fontScaleSlider\");\n if (fontScaleSlider) {\n const scaleValue = $(\"#fontScaleValue\");\n fontScaleSlider.addEventListener(\"input\", (event) => {\n const next = setUserScale(event.currentTarget.value);\n if (scaleValue) scaleValue.textContent = `${Math.round(next.userScale * 100)}%`;\n });\n }\n\n bindSliders(drawerInner);\n\n drawerInner.querySelectorAll(\"select[data-font-target]\").forEach((select) => {\n select.addEventListener(\"change\", (event) => {\n setFontPreference(event.currentTarget.dataset.fontTarget, event.currentTarget.value);\n });\n });\n }\n\n if (tab === \"ai\") {\n const updateMcpPreview = () => {\n const osId = $(\"#mcpOsSelect\")?.value || detectedMcpOs();\n const clientId = $(\"#mcpClientSelect\")?.value || \"claude-code\";\n const client = MCP_CLIENTS[clientId] || MCP_CLIENTS.generic;\n const paths = mcpPathsFromForm();\n const configText = mcpConfigText(clientId, paths);\n const commandText = mcpRunCommand(osId, paths);\n\n const osNote = drawerInner.querySelector(\"[data-mcp-os-note]\");\n if (osNote) osNote.textContent = `Detected: ${MCP_OS_OPTIONS[detectedMcpOs()]?.label || \"Linux\"}`;\n\n const format = drawerInner.querySelector(\"[data-mcp-client-format]\");\n if (format) format.textContent = client.format;\n\n const title = drawerInner.querySelector(\"[data-mcp-output-title]\");\n if (title) title.textContent = `${client.label} setup`;\n\n const helper = drawerInner.querySelector(\"[data-mcp-helper]\");\n if (helper) helper.textContent = client.helper;\n\n const configEl = drawerInner.querySelector(\"[data-mcp-config]\");\n if (configEl) configEl.textContent = configText;\n\n const commandEl = drawerInner.querySelector(\"[data-mcp-command]\");\n if (commandEl) commandEl.textContent = commandText;\n };\n\n $(\"#mcpOsSelect\")?.addEventListener(\"change\", () => updateMcpPreview());\n $(\"#mcpClientSelect\")?.addEventListener(\"change\", () => updateMcpPreview());\n [\"#mcpServerPathInput\"].forEach((selector) => {\n $(selector)?.addEventListener(\"input\", () => updateMcpPreview());\n });\n\n drawerInner.querySelectorAll(\"[data-copy-mcp]\").forEach((button) => {\n button.addEventListener(\"click\", async () => {\n const osId = $(\"#mcpOsSelect\")?.value || detectedMcpOs();\n const clientId = $(\"#mcpClientSelect\")?.value || \"claude-code\";\n const paths = mcpPathsFromForm();\n const value = button.dataset.copyMcp === \"command\" ? mcpRunCommand(osId, paths) : mcpConfigText(clientId, paths);\n await copyText(value);\n toast.success(button.dataset.copyMcp === \"command\" ? \"MCP command copied\" : \"MCP config copied\");\n });\n });\n\n const instructionsEl = drawerInner.querySelector('[data-edit-field=\"agent_instructions\"]');\n if (instructionsEl) {\n const edit = () =>\n startInlineEdit(instructionsEl, {\n fieldName: \"agent_instructions\",\n multiline: true,\n initialValue: project.agent_instructions || \"\",\n ariaLabel: \"Edit Agent Instructions\",\n rerender: async () => {\n state.detailMode = \"settings\";\n await renderProjectDetail();\n },\n commit: async (next) => {\n await api(`/api/boards/${project.id}`, {\n method: \"PATCH\",\n body: { agent_instructions: cleanText(next) }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Saved\");\n }\n });\n instructionsEl.addEventListener(\"click\", (event) => {\n event.preventDefault();\n edit();\n });\n instructionsEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n edit();\n }\n });\n }\n\n $(\"#aiEnabledToggle\")?.addEventListener(\"change\", async (event) => {\n const enabled = !!event.currentTarget.checked;\n await api(`/api/boards/${project.id}`, {\n method: \"PATCH\",\n body: { ai_enabled: enabled }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(enabled ? \"AI features enabled \u2014 agent lanes provisioned\" : \"AI features disabled \u2014 AI Ready hidden\");\n });\n\n const helperPickFolderBtn = $(\"#helperPickFolderBtn\");\n helperPickFolderBtn?.addEventListener(\"click\", async () => {\n helperPickFolderBtn.disabled = true;\n try {\n const result = await api(\"/api/system/pick-folder\", { method: \"POST\" });\n if (!result.path) return;\n await api(`/api/boards/${encodeURIComponent(project.id)}`, {\n method: \"PATCH\",\n body: { system_path: result.path }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Linked coding project folder updated\");\n } catch (error) {\n toast.error(error?.message || \"Folder picker unavailable\");\n } finally {\n helperPickFolderBtn.disabled = false;\n }\n });\n\n const manageHelperFilesToggle = $(\"#manageHelperFilesToggle\");\n manageHelperFilesToggle?.addEventListener(\"change\", async () => {\n const enabled = manageHelperFilesToggle.checked;\n manageHelperFilesToggle.disabled = true;\n try {\n await api(`/api/boards/${encodeURIComponent(project.id)}`, {\n method: \"PATCH\",\n body: { manage_helper_files: enabled }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\n enabled\n ? \"Generated SKILL-ORBIT.md and AGENTS.md \u2014 Orbit will keep them in sync\"\n : \"Stopped maintaining helper files (existing files left in place)\"\n );\n } catch (error) {\n manageHelperFilesToggle.checked = !enabled;\n manageHelperFilesToggle.disabled = false;\n toast.error(error?.message || \"Could not update helper files setting\");\n }\n });\n\n }\n\n if (tab === \"archive\") {\n const listEl = $(\"#archiveList\");\n if (listEl) {\n const refresh = async () => {\n try {\n const result = await api(`/api/boards/${encodeURIComponent(project.id)}/archive`);\n const tickets = result.tickets || [];\n if (tickets.length === 0) {\n listEl.innerHTML = `<p class=\"description\">No archived cards yet. Click the trash icon in the card detail header to archive a card.</p>`;\n return;\n }\n listEl.innerHTML = `<div class=\"detail-card-grid\">${tickets\n .map((t) => renderDetailCard(t, { archive: { id: t.id }, disableOpen: true }))\n .join(\"\")}</div>`;\n } catch (err) {\n listEl.innerHTML = `<p class=\"description\">Could not load archive: ${escapeHtml(err?.message || \"unknown error\")}</p>`;\n }\n };\n\n refresh();\n\n listEl.addEventListener(\"click\", async (event) => {\n const restoreBtn = event.target.closest(\"[data-archive-restore]\");\n const deleteBtn = event.target.closest(\"[data-archive-delete]\");\n if (!restoreBtn && !deleteBtn) return;\n event.stopPropagation();\n const card = (restoreBtn || deleteBtn).closest(\"article\");\n const cardTitle = card?.querySelector(\"h3\")?.textContent || \"card\";\n if (restoreBtn) {\n const id = restoreBtn.dataset.archiveRestore;\n await api(withBoardQuery(`/api/tickets/${encodeURIComponent(id)}/restore`), { method: \"POST\" });\n toast.success(`Restored: ${cardTitle}`);\n await load();\n await refresh();\n return;\n }\n if (deleteBtn) {\n const id = deleteBtn.dataset.archiveDelete;\n if (!confirm(`Permanently delete \"${cardTitle}\"? This cannot be undone.`)) return;\n await api(withBoardQuery(`/api/tickets/${encodeURIComponent(id)}`), { method: \"DELETE\" });\n toast.removed(`Deleted: ${cardTitle}`);\n await refresh();\n }\n });\n }\n }\n\n if (tab === \"journal\") {\n drawerInner.querySelectorAll(\"[data-entry-action='toggle-struck']\").forEach((button) => {\n button.addEventListener(\"click\", async () => {\n await api(withBoardQuery(`/api/board-entries/${button.dataset.entryId}`), {\n method: \"PATCH\",\n body: { struck: button.dataset.struck !== \"true\" }\n });\n await load();\n state.detailMode = \"settings\";\n toast.info(button.dataset.struck === \"true\" ? \"Project entry restored\" : \"Project entry struck\");\n });\n });\n\n $(\"#projectEntryForm\")?.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n await api(`/api/boards/${project.id}/entries`, {\n method: \"POST\",\n body: Object.fromEntries(form.entries())\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Project entry added\");\n });\n }\n}\n\nasync function copyText(value) {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(value);\n return;\n }\n\n const textArea = document.createElement(\"textarea\");\n textArea.value = value;\n textArea.setAttribute(\"readonly\", \"\");\n textArea.style.position = \"fixed\";\n textArea.style.left = \"-9999px\";\n document.body.append(textArea);\n textArea.select();\n document.execCommand(\"copy\");\n textArea.remove();\n}\n\nfunction renderProjectEntries(entries = [], aiEnabled = false) {\n if (!entries.length) return `<p class=\"description\">No project entries yet.</p>`;\n return entries\n .map(\n (entry) => {\n const isStruck = Boolean(entry.struck_at);\n const showStruckState = aiEnabled && isStruck;\n return `\n <div class=\"comment project-entry ${escapeHtml(entry.type)} ${showStruckState ? \"is-struck\" : \"\"}\">\n <div class=\"comment-head\">\n <div class=\"comment-head-main\">\n <div class=\"comment-head-title\">\n <span class=\"entry-type-pill ${escapeHtml(entry.type)}\">${escapeHtml(entry.type)}</span>\n <strong class=\"entry-title\">${escapeHtml(entry.title)}</strong>\n </div>\n ${showStruckState ? `<span class=\"project-entry-status\">Excluded from agent context</span>` : \"\"}\n </div>\n </div>\n <div class=\"comment-body\">${escapeHtml(entry.body)}</div>\n <div class=\"comment-footer\">\n <span class=\"comment-footer-meta\">${escapeHtml(entry.created_by)} \u00B7 ${formatDate(entry.created_at)}</span>\n ${\n aiEnabled\n ? `<button\n type=\"button\"\n data-variant=\"ghost\"\n class=\"project-entry-strike detail-action-btn\"\n data-entry-action=\"toggle-struck\"\n data-entry-id=\"${escapeHtml(entry.id)}\"\n data-struck=\"${isStruck ? \"true\" : \"false\"}\"\n aria-pressed=\"${isStruck ? \"true\" : \"false\"}\"\n >${isStruck ? \"Restore\" : \"Strike\"}</button>`\n : \"\"\n }\n </div>\n </div>\n `;\n }\n )\n .join(\"\");\n}\n\n// In Progress and Review are core kanban lanes \u2014 undeletable regardless of\n// AI. AI Ready is only locked while AI is enabled; disabling AI hides it from\n// the board without moving its cards.\nconst CORE_LANE_ROLES = new Set([\"in_progress\", \"review\"]);\n\n/** A lane can't be deleted if it has cards (orphan risk), if it's the default\n * \"new cards land here\" lane (every project must keep exactly one), if it's\n * a core kanban lane (in_progress / review), or if it's the AI Ready lane\n * while AI is enabled. */\nfunction deleteDisabled(lane, counts, aiEnabled) {\n if (counts.get(lane.id)) return true;\n if (lane.is_default) return true;\n if (CORE_LANE_ROLES.has(lane.role)) return true;\n if (aiEnabled && lane.role === \"ai_ready\") return true;\n return false;\n}\n\nfunction deleteTitle(lane, counts, aiEnabled) {\n const count = counts.get(lane.id) || 0;\n if (count > 0) {\n return `Cannot delete \u2014 ${count} card${count === 1 ? \"\" : \"s\"} in this lane`;\n }\n if (lane.is_default) {\n return \"Cannot delete \u2014 default lane for new cards (move it first)\";\n }\n if (CORE_LANE_ROLES.has(lane.role)) {\n return \"Cannot delete \u2014 core kanban lane\";\n }\n if (aiEnabled && lane.role === \"ai_ready\") {\n return \"Cannot delete \u2014 required by agent flow while AI is enabled\";\n }\n return \"Delete lane\";\n}\n\nfunction renderLaneManager() {\n const lanes = statesForProject();\n const aiEnabled = currentBoard()?.ai_enabled !== 0;\n const counts = new Map();\n for (const ticket of ticketsForProject()) {\n counts.set(ticket.state_id, (counts.get(ticket.state_id) || 0) + 1);\n }\n\n return `\n <div class=\"lane-list\">\n ${lanes\n .map((lane, index) => {\n const isAiReady = lane.role === \"ai_ready\";\n const nameTitle = isAiReady\n ? \"AI Ready lane name is locked \u2014 disable AI to hide this column\"\n : \"\";\n return `\n <div class=\"lane-row${isAiReady ? \" lane-row--locked\" : \"\"}\" data-lane-id=\"${lane.id}\">\n <button type=\"button\" data-variant=\"ghost\" class=\"settings-lane-icon-btn\" data-lane-action=\"up\" ${index === 0 ? \"disabled\" : \"\"} title=\"Move lane left\" aria-label=\"Move lane left\">\u2191</button>\n <button type=\"button\" data-variant=\"ghost\" class=\"settings-lane-icon-btn\" data-lane-action=\"down\" ${index === lanes.length - 1 ? \"disabled\" : \"\"} title=\"Move lane right\" aria-label=\"Move lane right\">\u2193</button>\n <input name=\"name\" value=\"${escapeHtml(lane.name)}\" aria-label=\"Lane name\" ${isAiReady ? `readonly title=\"${escapeHtml(nameTitle)}\"` : \"\"} />\n <button type=\"button\" data-variant=\"${lane.is_default ? \"secondary\" : \"ghost\"}\" class=\"settings-lane-new-toggle ${lane.is_default ? \"is-on\" : \"\"}\" data-lane-action=\"toggle-default\" aria-pressed=\"${lane.is_default ? \"true\" : \"false\"}\" title=\"${lane.is_default ? \"Default lane for new cards \u2014 click another lane to move it\" : \"Make this the default lane for new cards\"}\" aria-label=\"Default lane for new cards\">\n <span class=\"lane-new-sun\" aria-hidden=\"true\"></span>\n <span class=\"lane-new-label\">New</span>\n </button>\n <button type=\"button\" data-variant=\"ghost\" class=\"settings-lane-delete-btn danger-button\" data-lane-action=\"delete\" ${deleteDisabled(lane, counts, aiEnabled) ? \"disabled\" : \"\"} title=\"${deleteTitle(lane, counts, aiEnabled)}\" aria-label=\"Delete lane\">${closeIconSvg}</button>\n </div>\n `;\n })\n .join(\"\")}\n </div>\n `;\n}\n\nasync function handleLaneAction(button) {\n const row = button.closest(\".lane-row\");\n const laneId = row.dataset.laneId;\n const action = button.dataset.laneAction;\n if (action === \"delete\") {\n await api(withBoardQuery(`/api/states/${laneId}`), { method: \"DELETE\" });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Lane deleted\");\n return;\n }\n\n if (action === \"toggle-default\") {\n // Radio-style: one lane is always the default. Clicking the current\n // default is a no-op \u2014 to move it you click a different lane. This\n // guarantees new-card creation always has somewhere to land.\n const wasOn = button.getAttribute(\"aria-pressed\") === \"true\";\n if (wasOn) return;\n drawerInner.querySelectorAll('[data-lane-action=\"toggle-default\"]').forEach((btn) => {\n btn.setAttribute(\"aria-pressed\", \"false\");\n btn.setAttribute(\"data-variant\", \"ghost\");\n btn.classList.remove(\"is-on\");\n });\n button.setAttribute(\"aria-pressed\", \"true\");\n button.setAttribute(\"data-variant\", \"secondary\");\n button.classList.add(\"is-on\");\n await updateLane(row, { silent: true });\n toast.success(\"Default lane updated\");\n return;\n }\n\n const lanes = statesForProject().map((lane) => lane.id);\n const index = lanes.indexOf(laneId);\n const swapWith = action === \"up\" ? index - 1 : index + 1;\n if (swapWith < 0 || swapWith >= lanes.length) return;\n [lanes[index], lanes[swapWith]] = [lanes[swapWith], lanes[index]];\n await api(`/api/boards/${state.boardId}/states`, {\n method: \"PATCH\",\n body: { state_ids: lanes }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Lanes reordered\");\n}\n\nasync function updateLane(row, { silent = false } = {}) {\n const name = row.querySelector('input[name=\"name\"]').value;\n const toggle = row.querySelector('[data-lane-action=\"toggle-default\"]');\n const isDefault = toggle?.getAttribute(\"aria-pressed\") === \"true\";\n\n await api(withBoardQuery(`/api/states/${row.dataset.laneId}`), {\n method: \"PATCH\",\n body: {\n name,\n is_default: isDefault\n }\n });\n await load();\n state.detailMode = \"settings\";\n if (!silent) toast.success(\"Lane updated\");\n}\n", "// Human-facing actor labels for ticket activity. The storage layer keeps\n// compact/internal identifiers such as \"local\" and \"local-agent\"; the drawer\n// should translate those into labels that explain who acted without exposing\n// implementation details or blaming agent actions on the current user.\n\nconst INTERNAL_LOCAL_NAMES = new Set([\"local\", \"local-owner\", \"owner\"]);\nconst GENERIC_AGENT_NAMES = new Set([\"agent\", \"local-agent\", \"orbit-agent\"]);\nconst AGENT_COMMENT_KINDS = new Set([\"agent_note\", \"checkpoint\", \"completion\"]);\n\nfunction clean(value) {\n return String(value || \"\").trim();\n}\n\nfunction humanizeIdentifier(value) {\n const raw = clean(value);\n if (!raw) return \"\";\n return raw\n .replace(/^@+/, \"\")\n .replace(/[-_]+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim()\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n}\n\nfunction agentNameFrom({ actor, actorId } = {}) {\n const name = clean(actor);\n const id = clean(actorId);\n const lowerName = name.toLowerCase();\n const lowerId = id.toLowerCase();\n\n if (name && !INTERNAL_LOCAL_NAMES.has(lowerName) && !GENERIC_AGENT_NAMES.has(lowerName)) {\n return humanizeIdentifier(name);\n }\n if (id && !INTERNAL_LOCAL_NAMES.has(lowerId) && !GENERIC_AGENT_NAMES.has(lowerId)) {\n return humanizeIdentifier(id);\n }\n return \"\";\n}\n\nexport function formatActorLabel({ actor, actorType, actorId } = {}) {\n const type = clean(actorType).toLowerCase();\n const name = clean(actor);\n const lowerName = name.toLowerCase();\n\n if (type === \"agent\") {\n const agentName = agentNameFrom({ actor: name, actorId });\n return agentName ? `Agent \u00B7 ${agentName}` : \"Agent\";\n }\n\n if (!name || INTERNAL_LOCAL_NAMES.has(lowerName)) return \"You\";\n return humanizeIdentifier(name);\n}\n\nexport function formatCommentAuthor(comment = {}) {\n const kind = clean(comment.kind).toLowerCase();\n const author = clean(comment.author);\n const isAgentKind = AGENT_COMMENT_KINDS.has(kind) || (kind && kind !== \"human_comment\");\n\n if (isAgentKind) {\n const agentName = agentNameFrom({ actor: author });\n return agentName ? `Agent \u00B7 ${agentName}` : \"Agent\";\n }\n\n return formatActorLabel({ actor: author, actorType: \"human\" });\n}\n", "import { api, withBoardQuery } from \"./api.js\";\nimport { escapeHtml, renderMarkdown } from \"./format.js\";\nimport { toast } from \"./toast.js\";\n\nconst backdrop = document.getElementById(\"artifactDrawerBackdrop\");\nconst drawer = document.getElementById(\"artifactDrawer\");\nconst titleEl = document.getElementById(\"artifactDrawerTitle\");\nconst metaEl = document.getElementById(\"artifactDrawerMeta\");\nconst bodyEl = document.getElementById(\"artifactDrawerBody\");\nconst closeBtn = document.getElementById(\"artifactDrawerCloseBtn\");\n\nfunction setOpen(open) {\n if (!drawer || !backdrop) return;\n drawer.hidden = false;\n backdrop.hidden = false;\n requestAnimationFrame(() => {\n drawer.classList.toggle(\"is-open\", open);\n backdrop.classList.toggle(\"is-visible\", open);\n });\n if (!open) {\n setTimeout(() => {\n if (drawer.classList.contains(\"is-open\")) return;\n drawer.hidden = true;\n backdrop.hidden = true;\n if (bodyEl) bodyEl.innerHTML = \"\";\n }, 260);\n }\n}\n\nexport function closeArtifactDrawer() {\n setOpen(false);\n}\n\nfunction localPathHint(path, error) {\n const code = error?.payload?.error || error?.message || \"Unable to load artifact\";\n const parts = [escapeHtml(code)];\n if (code === \"artifact_path_outside_allowed_roots\" || code === \"artifact_not_found\") {\n parts.push(\"<br><br>The Orbit server could not read that artifact path. If this webapp is hosted on another machine, the file needs to be stored on the hosted Orbit server or linked as a server-readable/repo-relative path.\");\n }\n const mntDrive = String(path || \"\").match(/^\\/mnt\\/([a-z])\\/(.+)$/i);\n const slashDrive = String(path || \"\").match(/^\\/([a-z])\\/Users\\/(.+)$/i);\n if (mntDrive) {\n const drive = mntDrive[1].toUpperCase();\n parts.push(`<br><br>Windows spelling for this WSL path: <code>${escapeHtml(`${drive}:\\\\${mntDrive[2].replace(/\\//g, \"\\\\\")}`)}</code>`);\n } else if (slashDrive) {\n const drive = slashDrive[1].toUpperCase();\n parts.push(`<br><br>Windows spelling for this path: <code>${escapeHtml(`${drive}:\\\\Users\\\\${slashDrive[2].replace(/\\//g, \"\\\\\")}`)}</code>`);\n }\n return parts.join(\"\");\n}\n\nexport async function openArtifactDrawer({ ticketId, path, title = \"Linked artifact\" }) {\n if (!ticketId || !path) return false;\n if (!drawer || !bodyEl || !titleEl || !metaEl) return false;\n titleEl.textContent = title;\n metaEl.textContent = path;\n bodyEl.innerHTML = `<p class=\"artifact-drawer-loading\">Loading artifact\u2026</p>`;\n setOpen(true);\n\n try {\n const result = await api(\n withBoardQuery(`/api/tickets/${encodeURIComponent(ticketId)}/artifacts/markdown?path=${encodeURIComponent(path)}`),\n );\n titleEl.textContent = title;\n metaEl.textContent = result.path || path;\n bodyEl.innerHTML = `<article class=\"markdown-body artifact-markdown-body\">${renderMarkdown(result.content || \"\") || `<p>${escapeHtml(\"Empty artifact.\")}</p>`}</article>`;\n return true;\n } catch (err) {\n bodyEl.innerHTML = `<p class=\"artifact-drawer-error\">${localPathHint(path, err)}</p>`;\n toast.error(\"Artifact could not be opened\");\n return false;\n }\n}\n\ncloseBtn?.addEventListener(\"click\", closeArtifactDrawer);\nbackdrop?.addEventListener(\"click\", closeArtifactDrawer);\ndocument.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Escape\" && drawer && !drawer.hidden) closeArtifactDrawer();\n});\n", "// Reusable settings-style \"panel\" primitives shared by the project settings\n// drawer and the ticket detail drawer. A panel is a bordered card with a\n// tinted header strip (small-caps title) and a padded body \u2014 the same visual\n// language used across the Appearance / AI / Data settings tabs. The\n// collapsible variant turns the header into a <details>/<summary> toggle with a\n// chevron that flips when open, so any surface can drop in a togglable section\n// without re-deriving the markup. These intentionally emit the .settings-card\n// class family (documented in styles.css as a reusable @starlove/ui primitive).\n\nimport { escapeHtml } from \"./format.js\";\n\nconst panelChevronSvg = `<svg class=\"settings-card-chevron\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\" /></svg>`;\n\n/**\n * Static panel: bordered card with a header title and a padded body.\n *\n * Options:\n * - title: heading text shown in the small-caps header strip.\n * - body: raw HTML for the card body (already escaped by the caller).\n * - className: extra classes appended to the .settings-card element.\n * - attrs: extra attributes string placed on the <section> (e.g. data-*).\n * - headExtra: raw HTML appended after the title inside the header (actions).\n */\nexport function renderPanel({ title, body = \"\", className = \"\", attrs = \"\", headExtra = \"\" } = {}) {\n const classAttr = className ? ` ${className}` : \"\";\n const extraAttrs = attrs ? ` ${attrs}` : \"\";\n return `\n <section class=\"settings-card${classAttr}\"${extraAttrs}>\n <header class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">${escapeHtml(title)}</h3>\n ${headExtra}\n </header>\n <div class=\"settings-card-body\">${body}</div>\n </section>\n `;\n}\n\n/**\n * Collapsible panel: same chrome as renderPanel but the header doubles as a\n * <details>/<summary> toggle with a flipping chevron.\n *\n * Options mirror renderPanel, plus:\n * - open: whether the section starts expanded.\n */\nexport function renderTogglePanel({ title, body = \"\", open = false, className = \"\", attrs = \"\", headExtra = \"\" } = {}) {\n const classAttr = className ? ` ${className}` : \"\";\n const extraAttrs = attrs ? ` ${attrs}` : \"\";\n return `\n <details class=\"settings-card settings-card--collapsible${classAttr}\"${open ? \" open\" : \"\"}${extraAttrs}>\n <summary class=\"settings-card-head\">\n <h3 class=\"settings-card-title\">${escapeHtml(title)}</h3>\n ${headExtra}\n ${panelChevronSvg}\n </summary>\n <div class=\"settings-card-body\">${body}</div>\n </details>\n `;\n}\n", "// Custom typeahead dropdown for the ticket-detail drawer inputs (Add label,\n// Set parent epic, Add related ticket). Replaces the native <datalist>, which\n// browsers render in their own un-styleable popup, with a results list that\n// reuses the topbar search styling (bold label + title + state badge). The\n// component only fills the input on selection \u2014 the surrounding form's Add/Set\n// button and Enter handler still own the actual mutation, so swapping the\n// datalist for this is a pure presentation change.\n\nconst ACTIVE_CLASS = \"is-active\";\n\n/**\n * Wire a styled suggestion dropdown onto a text input.\n *\n * Options:\n * - getItems(): returns the full candidate list (re-read on each keystroke).\n * - match(item, q): whether an item matches the lowercased query string.\n * - renderItem(item): inner HTML for the .search-hit row.\n * - valueOf(item): string written into the input when the item is chosen.\n * - onSelect(item): optional hook fired after the value is filled.\n * - emptyText: message shown when a non-empty query matches nothing.\n * - minChars: minimum query length before the list opens (default 0).\n * - maxItems: cap on rendered rows (default 8).\n *\n * Returns a teardown function (rarely needed \u2014 the drawer is re-rendered wholesale).\n */\nexport function attachTypeahead(\n input,\n {\n getItems,\n match,\n renderItem,\n valueOf,\n onSelect,\n emptyText = \"No matches\",\n minChars = 0,\n maxItems = 8,\n },\n) {\n if (!input) return () => {};\n\n // Appended to <body> (not the input's wrapper) so the ancestor\n // .settings-card overflow:hidden can't clip it; positioned as fixed from the\n // input's viewport rect and re-anchored on scroll/resize while open.\n const list = document.createElement(\"div\");\n list.className = \"search-results typeahead-results\";\n list.hidden = true;\n list.setAttribute(\"role\", \"listbox\");\n list._ownerInput = input;\n document.body.appendChild(list);\n\n // The drawer re-renders wholesale, detaching the old inputs but leaving their\n // body-level dropdowns behind. Sweep those orphans (owner no longer in the\n // document) whenever a fresh typeahead mounts.\n for (const el of document.querySelectorAll(\".typeahead-results\")) {\n if (el !== list && el._ownerInput && !el._ownerInput.isConnected) {\n el.remove();\n }\n }\n\n let visible = [];\n let activeIndex = -1;\n let blurTimer = 0;\n\n const position = () => {\n const r = input.getBoundingClientRect();\n list.style.left = `${r.left}px`;\n list.style.width = `${r.width}px`;\n list.style.top = `${r.bottom + 4}px`;\n };\n\n const onReposition = () => {\n if (list.hidden) return;\n position();\n };\n\n const close = () => {\n list.hidden = true;\n list.innerHTML = \"\";\n visible = [];\n activeIndex = -1;\n window.removeEventListener(\"scroll\", onReposition, true);\n window.removeEventListener(\"resize\", onReposition);\n };\n\n const open = () => {\n if (!list.hidden) return;\n list.hidden = false;\n window.addEventListener(\"scroll\", onReposition, true);\n window.addEventListener(\"resize\", onReposition);\n };\n\n const render = () => {\n const query = input.value.trim().toLowerCase();\n if (query.length < minChars) {\n close();\n return;\n }\n const all = getItems() || [];\n visible = (query ? all.filter((item) => match(item, query)) : all).slice(\n 0,\n maxItems,\n );\n if (visible.length === 0) {\n // Only surface the empty state once the user has typed something \u2014\n // an empty focused field just shows the full (capped) list below.\n if (query) {\n open();\n list.innerHTML = `<div class=\"search-hit typeahead-empty\">${emptyText}</div>`;\n position();\n } else {\n close();\n }\n return;\n }\n activeIndex = -1;\n open();\n list.innerHTML = visible\n .map(\n (item, i) =>\n `<div class=\"search-hit\" role=\"option\" data-index=\"${i}\">${renderItem(item)}</div>`,\n )\n .join(\"\");\n position();\n };\n\n const setActive = (next) => {\n const rows = list.querySelectorAll(\"[data-index]\");\n if (!rows.length) return;\n activeIndex = (next + rows.length) % rows.length;\n rows.forEach((row, i) => {\n const on = i === activeIndex;\n row.classList.toggle(ACTIVE_CLASS, on);\n if (on) row.scrollIntoView({ block: \"nearest\" });\n });\n };\n\n const choose = (item) => {\n if (!item) return;\n input.value = valueOf(item);\n // Let the host form react (e.g. the clear-button has-value toggle).\n input.dispatchEvent(new Event(\"input\", { bubbles: true }));\n close();\n input.focus();\n if (onSelect) onSelect(item);\n };\n\n const onInput = () => render();\n const onFocus = () => render();\n\n const onKeydown = (event) => {\n if (list.hidden) return;\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setActive(activeIndex + 1);\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActive(activeIndex - 1);\n } else if (event.key === \"Enter\") {\n // Only swallow Enter when a suggestion is highlighted; otherwise let the\n // form submit the typed value as before.\n if (activeIndex >= 0 && visible[activeIndex]) {\n event.preventDefault();\n // stopImmediatePropagation so a sibling keydown listener on the same\n // input (e.g. the label field's add-on-Enter) doesn't also fire.\n event.stopImmediatePropagation();\n choose(visible[activeIndex]);\n }\n } else if (event.key === \"Escape\") {\n if (!list.hidden) {\n event.stopPropagation();\n close();\n }\n }\n };\n\n const onBlur = () => {\n blurTimer = window.setTimeout(close, 120);\n };\n\n // mousedown beats the input's blur, so the row click registers before close().\n const onMouseDown = (event) => {\n const row = event.target.closest(\"[data-index]\");\n if (!row) return;\n event.preventDefault();\n window.clearTimeout(blurTimer);\n choose(visible[Number(row.dataset.index)]);\n };\n\n input.addEventListener(\"input\", onInput);\n input.addEventListener(\"focus\", onFocus);\n input.addEventListener(\"keydown\", onKeydown);\n input.addEventListener(\"blur\", onBlur);\n list.addEventListener(\"mousedown\", onMouseDown);\n\n return () => {\n window.clearTimeout(blurTimer);\n window.removeEventListener(\"scroll\", onReposition, true);\n window.removeEventListener(\"resize\", onReposition);\n input.removeEventListener(\"input\", onInput);\n input.removeEventListener(\"focus\", onFocus);\n input.removeEventListener(\"keydown\", onKeydown);\n input.removeEventListener(\"blur\", onBlur);\n list.removeEventListener(\"mousedown\", onMouseDown);\n list.remove();\n };\n}\n", "// Shared ticket typeahead: the styled suggestion dropdown used wherever a\n// ticket is picked by typing (ticket-detail's Related / parent-epic / add-child\n// fields and the New-card flyout's parent-epic field). Rows mirror the topbar\n// search results \u2014 bold #number, title, type badge, state badge \u2014 and selecting\n// a row fills the input with the canonical \"#12 \u2014 Title\" label so the host\n// form's resolve-on-submit logic keeps working unchanged.\n\nimport { escapeHtml, ticketLabel, stateClassFor, typeLabel, canonicalTicketType } from \"./format.js\";\nimport { attachTypeahead } from \"./typeahead.js\";\n\n// Canonical \"#12 \u2014 Title\" label the resolve-on-submit logic expects.\nexport function ticketCanonicalLabel(t) {\n return `#${t.number} \u2014 ${t.title}`;\n}\n\n// A typeahead row for a ticket: bold #number, title, then trailing type and\n// state badges \u2014 the same shape as the topbar search results.\nexport function renderTicketHitRow(t) {\n const type = canonicalTicketType(t.type);\n return `\n <span class=\"search-hit-main\">\n <strong>${escapeHtml(ticketLabel(t))}</strong>\n <span class=\"search-hit-title\">${escapeHtml(t.title)}</span>\n </span>\n <span class=\"search-hit-type type-pill-${escapeHtml(type)}\">${escapeHtml(typeLabel(t.type))}</span>\n <span class=\"search-hit-state\" data-variant=\"${escapeHtml(stateClassFor(t))}\">${escapeHtml(t.state_name || \"State\")}</span>\n `;\n}\n\n// Matches a ticket against a query by number (\"12\", \"#12\") or title substring.\nexport function ticketMatchesQuery(t, query) {\n const q = query.replace(/^#/, \"\");\n return String(t.number).startsWith(q) || t.title.toLowerCase().includes(query);\n}\n\n// Wire the styled typeahead onto a ticket-picker input. `getCandidates` returns\n// the eligible tickets; `onSelect` (optional) fires after the value is filled,\n// e.g. to record the chosen ticket's id in a hidden field.\nexport function attachTicketTypeahead(input, getCandidates, { onSelect } = {}) {\n if (!input) return;\n attachTypeahead(input, {\n getItems: getCandidates,\n match: ticketMatchesQuery,\n renderItem: renderTicketHitRow,\n valueOf: ticketCanonicalLabel,\n onSelect,\n emptyText: \"No matching tickets\",\n });\n}\n", "// Ticket detail drawer: renders the full ticket pane (header meta, AI plan,\n// status history, comments) and wires every editable surface \u2014 inline title\n// and description editors, meta selects, label management, parent epic, and\n// related cards. Also owns the small render helpers (status history,\n// comments, detail-card) that are only used inside the drawer.\n\nimport {\n state,\n ticketsForProject,\n selectableStatesForProject,\n boardLabelCatalog,\n currentBoard,\n upsertTicket,\n} from \"./state.js\";\nimport { drawerInner, drawer, $ } from \"./dom.js\";\nimport {\n escapeHtml,\n formatDate,\n formatDateDetail,\n ticketLabel,\n canonicalTicketType,\n typeLabel,\n typeLabelLong,\n priorityLabel,\n priorityKeyFor,\n renderPreservedText,\n stateClassFor,\n cleanText,\n} from \"./format.js\";\nimport { renderTypeIcon, renderPriorityPill, renderBoard } from \"./kanban.js\";\nimport { renderDrawerShell, openDrawer, closeDrawer } from \"./drawer.js\";\nimport { navigate } from \"./router.js\";\nimport { api, withBoardQuery } from \"./api.js\";\nimport { features } from \"./config.js\";\nimport { toast } from \"./toast.js\";\n// `load()` is intentionally not used for drawer-local mutations. Reloading\n// /api/bootstrap rebuilds the whole app; these helpers patch the local ticket\n// cache and refresh only the surfaces that actually changed.\nimport { renderProjectDetail } from \"./settings.js\";\nimport { unreadCount, markRead } from \"./unread.js\";\nimport { formatActorLabel, formatCommentAuthor } from \"./actor-labels.js\";\nimport { openArtifactDrawer } from \"./artifact-drawer.js\";\nimport { closeIconSvg } from \"./icons.js\";\nimport { handleTextareaIndentationKeydown } from \"./text-editing.js\";\nimport { renderPanel, renderTogglePanel } from \"./panel.js\";\nimport { attachTypeahead } from \"./typeahead.js\";\nimport { attachTicketTypeahead } from \"./ticket-typeahead.js\";\n\n/**\n * Refresh the open drawer from the focused ticket context endpoint. When the\n * board card itself changed, also rebuild the board from the patched local\n * cache; otherwise leave the board DOM alone.\n */\nasync function refreshTicketDetail(\n ticketId,\n { renderBoardAfter = false } = {},\n) {\n const [context, statusHistory, commentsResult] = await Promise.all([\n api(withBoardQuery(`/api/tickets/${ticketId}/context?depth=1`)),\n api(withBoardQuery(`/api/tickets/${ticketId}/history`)),\n api(withBoardQuery(`/api/tickets/${ticketId}/comments`)),\n ]);\n if (context.ticket?.id !== ticketId) return;\n upsertTicket(context.ticket);\n if (renderBoardAfter) renderBoard();\n if (state.detailMode !== \"ticket\" || state.selectedTicketId !== ticketId)\n return;\n await renderDetail({\n context,\n statusHistory,\n comments: commentsResult.comments || [],\n });\n}\n\n/**\n * PATCH a ticket then refresh only the board/detail surfaces that depend on\n * the changed ticket. This avoids the previous full /api/bootstrap reload for\n * every drawer edit.\n */\nasync function patchTicket(ticketId, body) {\n await api(withBoardQuery(`/api/tickets/${ticketId}`), {\n method: \"PATCH\",\n body,\n });\n await refreshTicketDetail(ticketId, { renderBoardAfter: true });\n}\n\n/**\n * Replace a static node with an inline editor; commit on Enter / blur, cancel on Esc.\n * For multi-line fields, Ctrl/Cmd+Enter commits and plain Enter inserts a newline.\n *\n * Options:\n * - fieldName: short identifier used for aria-label / data attribute (e.g. \"title\").\n * - multiline: true for <textarea> + Ctrl+Enter commit; false for <input> + Enter commit.\n * - initialValue: text shown in the editor on open.\n * - ariaLabel: full label for screen readers.\n * - emptyMessage: if set, an empty trimmed value triggers a warning toast and cancels.\n * - sourceEvent: optional pointer/click event used to seed the textarea caret near the clicked text.\n * - rerender: async fn called on cancel / no-change to put the static node back.\n * - commit: async fn called with the new value when the user accepts a real change.\n * Receives the *raw* editor value; the caller is responsible for any\n * trimming, cleanText, or PATCH wiring.\n */\nfunction inlineTextOffsetFromPoint(node, sourceEvent, maxLength) {\n if (\n !node ||\n !sourceEvent ||\n typeof sourceEvent.clientX !== \"number\" ||\n typeof sourceEvent.clientY !== \"number\"\n )\n return null;\n\n let range = null;\n if (document.caretPositionFromPoint) {\n const position = document.caretPositionFromPoint(\n sourceEvent.clientX,\n sourceEvent.clientY,\n );\n if (\n position?.offsetNode &&\n (position.offsetNode === node || node.contains(position.offsetNode))\n ) {\n range = document.createRange();\n range.setStart(node, 0);\n range.setEnd(position.offsetNode, position.offset);\n }\n } else if (document.caretRangeFromPoint) {\n const caretRange = document.caretRangeFromPoint(\n sourceEvent.clientX,\n sourceEvent.clientY,\n );\n if (\n caretRange?.startContainer &&\n (caretRange.startContainer === node ||\n node.contains(caretRange.startContainer))\n ) {\n range = document.createRange();\n range.setStart(node, 0);\n range.setEnd(caretRange.startContainer, caretRange.startOffset);\n }\n }\n\n if (!range) return null;\n return Math.max(0, Math.min(maxLength, range.toString().length));\n}\n\nfunction captureInlineEditScrollState(node) {\n const scrollContainer = node?.closest?.(\".drawer-inner\");\n if (!scrollContainer) return null;\n return {\n scrollContainer,\n nodeRect: node.getBoundingClientRect(),\n scrollTop: scrollContainer.scrollTop,\n };\n}\n\nfunction restoreInlineEditScroll(scrollState, editor) {\n if (!scrollState?.scrollContainer || !editor?.isConnected) return;\n const editorRect = editor.getBoundingClientRect();\n const nextScrollTop = Math.max(\n 0,\n scrollState.scrollContainer.scrollTop +\n (editorRect.top - scrollState.nodeRect.top),\n );\n if (Number.isFinite(nextScrollTop))\n scrollState.scrollContainer.scrollTop = nextScrollTop;\n else scrollState.scrollContainer.scrollTop = scrollState.scrollTop;\n}\n\nfunction focusWithoutScrolling(editor) {\n try {\n editor.focus({ preventScroll: true });\n } catch {\n editor.focus();\n }\n}\n\nexport function startInlineEdit(node, opts) {\n if (!node || node.dataset.editing === \"true\") return;\n const {\n fieldName,\n multiline = true,\n initialValue = \"\",\n ariaLabel,\n emptyMessage,\n sourceEvent,\n rerender,\n commit: commitHandler,\n } = opts;\n\n const scrollState = multiline ? captureInlineEditScrollState(node) : null;\n const initialString = String(initialValue);\n const clickedCaretOffset = multiline\n ? inlineTextOffsetFromPoint(node, sourceEvent, initialString.length)\n : null;\n\n node.dataset.editing = \"true\";\n\n const editor = document.createElement(multiline ? \"textarea\" : \"input\");\n editor.className = multiline ? \"inline-desc-editor\" : \"inline-title-editor\";\n editor.value = initialString;\n if (fieldName) editor.setAttribute(\"data-editing-field\", fieldName);\n if (ariaLabel) editor.setAttribute(\"aria-label\", ariaLabel);\n if (!multiline) {\n editor.type = \"text\";\n editor.maxLength = 500;\n editor.autocomplete = \"off\";\n editor.spellcheck = true;\n } else {\n editor.rows = Math.max(3, initialString.split(\"\\n\").length + 1);\n const sourceHeight = node.getBoundingClientRect().height;\n if (Number.isFinite(sourceHeight) && sourceHeight > 0) {\n editor.style.minHeight = `${Math.ceil(sourceHeight)}px`;\n }\n }\n\n node.replaceWith(editor);\n focusWithoutScrolling(editor);\n if (!multiline) {\n editor.select();\n } else {\n const selectionStart = clickedCaretOffset ?? 0;\n editor.setSelectionRange(selectionStart, selectionStart);\n restoreInlineEditScroll(scrollState, editor);\n }\n\n let done = false;\n\n const stopWatchingOutsideClicks = () => {\n document.removeEventListener(\"pointerdown\", handleOutsidePointerDown, true);\n };\n\n // If a downstream render rebuilds the title block while the editor is open,\n // the editor is dropped along with everything else; only restore the saved\n // node when our editor is still connected to the DOM.\n const restoreNode = () => {\n if (editor.isConnected) editor.replaceWith(node);\n delete node.dataset.editing;\n };\n\n const finish = () => {\n done = true;\n stopWatchingOutsideClicks();\n restoreNode();\n };\n\n function handleOutsidePointerDown(event) {\n if (done || event.target === editor || editor.contains(event.target))\n return;\n // Some drawer/header surfaces are not focusable, so clicking them does not\n // reliably blur the input in every browser. Force the blur path used on\n // commit so the edit styling cannot get stuck.\n editor.blur();\n }\n\n document.addEventListener(\"pointerdown\", handleOutsidePointerDown, true);\n\n const commit = async () => {\n if (done) return;\n const next = multiline ? editor.value : editor.value.trim();\n finish();\n if (String(next) === String(initialValue)) {\n if (rerender) await rerender();\n return;\n }\n if (emptyMessage && !next.trim()) {\n toast.warning(emptyMessage);\n if (rerender) await rerender();\n return;\n }\n if (commitHandler) await commitHandler(next);\n };\n\n const cancel = async () => {\n if (done) return;\n finish();\n if (rerender) await rerender();\n };\n\n editor.addEventListener(\"blur\", commit);\n editor.addEventListener(\"keydown\", (event) => {\n if (multiline && handleTextareaIndentationKeydown(event, editor)) return;\n if (event.key === \"Escape\") {\n event.preventDefault();\n void cancel();\n return;\n }\n if (event.key === \"Enter\") {\n if (!multiline) {\n event.preventDefault();\n void commit();\n } else if (event.metaKey || event.ctrlKey) {\n event.preventDefault();\n void commit();\n }\n }\n });\n}\n\nfunction promptArtifactPath({ currentPath = \"\", label = \"Artifact\" } = {}) {\n const next = window.prompt(\n `Local markdown/text path for ${label} (example: docs/test.md or ./docs/test.md)`,\n currentPath || \"docs/\",\n );\n if (next === null) return null;\n return cleanText(next).trim();\n}\n\nasync function promptAndSaveArtifactPath({ ticketId, fieldName, currentPath, label }) {\n if (!ticketId || !fieldName) return null;\n const next = promptArtifactPath({ currentPath, label });\n if (next === null) return null;\n await patchTicket(ticketId, { [fieldName]: next });\n await refreshTicketDetail(ticketId);\n toast.success(next ? \"Artifact path updated\" : \"Artifact path cleared\");\n return next;\n}\n\n/** Wire inline editors on the ticket detail header (meta fields, labels). */\nfunction wireTicketDetailEditors(ticket, context) {\n const ticketId = ticket.id;\n\n const editTitle = () =>\n startInlineEdit(titleEl, {\n fieldName: \"title\",\n multiline: false,\n initialValue: ticket.title || \"\",\n ariaLabel: \"Edit ticket title\",\n emptyMessage: \"Title cannot be empty\",\n rerender: () => renderDetail(),\n commit: (next) => patchTicket(ticketId, { title: next }),\n });\n\n const titleEl = drawer.querySelector('[data-edit-field=\"title\"]');\n if (titleEl) {\n titleEl.addEventListener(\"click\", editTitle);\n titleEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n editTitle();\n }\n });\n }\n\n const descEl = drawerInner.querySelector('[data-edit-field=\"description\"]');\n const editDescription = (sourceEvent) =>\n startInlineEdit(descEl, {\n fieldName: \"description\",\n multiline: true,\n initialValue: ticket.description || \"\",\n ariaLabel: \"Edit ticket description\",\n sourceEvent,\n rerender: () => renderDetail(),\n commit: (next) => patchTicket(ticketId, { description: cleanText(next) }),\n });\n\n if (descEl) {\n descEl.addEventListener(\"click\", (event) => {\n event.preventDefault();\n editDescription(event);\n });\n descEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n editDescription();\n }\n });\n }\n\n // AI Plan / Implementation fields: each becomes its own click-to-edit\n // surface so they save independently on blur / Ctrl+Enter, matching the\n // description field. The \"ai_plan\" / \"implementation_summary\" /\n // \"implementation_updates\" data-edit-field selectors are emitted by the\n // detail body template below.\n const AI_FIELDS = [\n { key: \"ai_plan\", label: \"AI Plan\" },\n { key: \"implementation_summary\", label: \"Work Summary\" },\n {\n key: \"implementation_updates\",\n label: \"Revisions\",\n }\n ];\n for (const { key, label } of AI_FIELDS) {\n const fieldEl = drawerInner.querySelector(`[data-edit-field=\"${key}\"]`);\n if (!fieldEl) continue;\n const edit = (sourceEvent) =>\n startInlineEdit(fieldEl, {\n fieldName: key,\n multiline: true,\n initialValue: ticket[key] || \"\",\n ariaLabel: `Edit ${label}`,\n sourceEvent,\n rerender: () => renderDetail(),\n commit: (next) => patchTicket(ticketId, { [key]: cleanText(next) }),\n });\n fieldEl.addEventListener(\"click\", (event) => {\n event.preventDefault();\n edit(event);\n });\n fieldEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n edit();\n }\n });\n }\n\n drawer.querySelectorAll(\".meta-select[data-meta-field]\").forEach((select) => {\n select.addEventListener(\"change\", async () => {\n const field = select.dataset.metaField;\n if (field === \"type\") {\n await patchTicket(ticketId, { type: select.value });\n return;\n }\n if (field === \"state_id\") {\n await patchTicket(ticketId, { state_id: select.value });\n return;\n }\n if (field === \"parent_ticket_id\") {\n await patchTicket(ticketId, { parent_ticket_id: select.value || null });\n return;\n }\n if (field === \"priority\") {\n await patchTicket(ticketId, { priority: Number(select.value) });\n }\n });\n });\n\n const applyLabelPatch = async (nextNames) => {\n await patchTicket(ticketId, { labels: nextNames });\n };\n\n drawerInner.querySelectorAll(\"[data-remove-label]\").forEach((btn) => {\n btn.addEventListener(\"click\", async () => {\n const removeName = btn.getAttribute(\"data-remove-label\");\n const names = (ticket.labels || [])\n .map((l) => l.name)\n .filter((n) => n !== removeName);\n await applyLabelPatch(names);\n });\n });\n\n const addLabel = async () => {\n const input = drawerInner.querySelector(\"[data-label-input]\");\n if (!input) return;\n const name = input.value.trim();\n if (!name) return;\n const names = (ticket.labels || []).map((l) => l.name);\n if (names.includes(name)) {\n input.value = \"\";\n return;\n }\n names.push(name);\n input.value = \"\";\n await applyLabelPatch(names);\n };\n\n drawerInner\n .querySelector(\"[data-label-add]\")\n ?.addEventListener(\"click\", () => {\n void addLabel();\n });\n // Attach the typeahead first so its Enter handler runs before the add-on-Enter\n // handler below; when a suggestion is highlighted it stops propagation so the\n // partial typed text isn't added instead.\n attachLabelTypeahead(drawerInner.querySelector(\"[data-label-input]\"), ticket);\n drawerInner\n .querySelector(\"[data-label-input]\")\n ?.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n void addLabel();\n }\n });\n}\n\nexport async function renderDetail(options = {}) {\n if (state.detailMode === \"settings\") {\n await renderProjectDetail();\n openDrawer();\n return;\n }\n\n if (!state.selectedTicketId) {\n closeDrawer();\n return;\n }\n\n const requestedTicketId = state.selectedTicketId;\n const hasOption = (key) => Object.prototype.hasOwnProperty.call(options, key);\n const [context, statusHistory, comments, attachmentList] = await Promise.all([\n hasOption(\"context\")\n ? Promise.resolve(options.context)\n : api(\n withBoardQuery(`/api/tickets/${requestedTicketId}/context?depth=1`),\n ),\n hasOption(\"statusHistory\")\n ? Promise.resolve(options.statusHistory)\n : api(withBoardQuery(`/api/tickets/${requestedTicketId}/history`)),\n hasOption(\"comments\")\n ? Promise.resolve(options.comments)\n : api(withBoardQuery(`/api/tickets/${requestedTicketId}/comments`)).then(\n (result) => result.comments || [],\n ),\n hasOption(\"attachmentList\")\n ? Promise.resolve(options.attachmentList)\n : features.attachments\n ? api(\n withBoardQuery(`/api/tickets/${requestedTicketId}/attachments`),\n ).catch(() => ({ attachments: [] }))\n : Promise.resolve({ attachments: [] }),\n ]);\n if (\n state.detailMode !== \"ticket\" ||\n state.selectedTicketId !== requestedTicketId\n )\n return;\n if (context.ticket?.id !== requestedTicketId) return;\n const ticket = context.ticket;\n // Acknowledge the read receipt: clear the unread dot on this card.\n // Also wipe the dot from the already-rendered card in the board so the\n // user doesn't see it lingering until the next full re-render.\n markRead(ticket.id, ticket.updated_at);\n document\n .querySelector(\n `.card[data-ticket-id=\"${CSS.escape(ticket.id)}\"] .card-unread-dot`,\n )\n ?.remove();\n const states = selectableStatesForProject(ticket.state_id);\n\n // Ordered by the canonical hierarchy so the dropdown visually reinforces scale:\n // Epic (biggest) \u2192 Feature \u2192 Task \u2192 Bug.\n const typeOptions = [\"epic\", \"feature\", \"task\", \"bug\"]\n .map(\n (value) =>\n `<option value=\"${escapeHtml(value)}\" ${canonicalTicketType(ticket.type) === value ? \"selected\" : \"\"}>${escapeHtml(typeLabelLong(value))}</option>`,\n )\n .join(\"\");\n\n const stateOptions = states\n .map(\n (s) =>\n `<option value=\"${escapeHtml(s.id)}\" ${s.id === ticket.state_id ? \"selected\" : \"\"}>${escapeHtml(s.name)}</option>`,\n )\n .join(\"\");\n\n const priorityOptions = [4, 3, 2, 1, 0]\n .map(\n (p) =>\n `<option value=\"${p}\" ${Number(ticket.priority) === p ? \"selected\" : \"\"}>${escapeHtml(priorityLabel(p))}</option>`,\n )\n .join(\"\");\n\n const labelPills = (ticket.labels || [])\n .map(\n (label) => `\n <span class=\"label-pill-removable\" style=\"--label-color: ${escapeHtml(label.color)}\">\n ${escapeHtml(label.name)}\n <button type=\"button\" class=\"label-pill-remove\" data-remove-label=\"${escapeHtml(label.name)}\" title=\"Remove label\" aria-label=\"Remove label\">${closeIconSvg}</button>\n </span>`,\n )\n .join(\"\");\n\n const detailCanonicalType = canonicalTicketType(ticket.type);\n const priorityKey = priorityKeyFor(ticket.priority);\n const currentState = states.find((s) => s.id === ticket.state_id);\n const stateClass = stateClassFor(currentState);\n const descriptionHtml = ticket.description\n ? renderPreservedText(ticket.description)\n : escapeHtml(\"No description yet.\");\n const descriptionClass = ticket.description\n ? \"description preserved-text-body editable-field detail-description-body\"\n : \"description editable-field detail-description-body is-placeholder\";\n const detailSubtitleHtml = `\n <span class=\"ticket-number\">${escapeHtml(ticketLabel(ticket))}</span>\n <div class=\"detail-meta-badge-row\" aria-label=\"Ticket metadata controls\">\n <select class=\"detail-meta-badge detail-state-badge meta-select\" data-variant=\"${escapeHtml(stateClass)}\" data-meta-field=\"state_id\" aria-label=\"Ticket state\">${stateOptions}</select>\n <select class=\"detail-meta-badge detail-type-badge type-pill-${escapeHtml(detailCanonicalType)} meta-select\" data-meta-field=\"type\" aria-label=\"Ticket type\">${typeOptions}</select>\n <select class=\"detail-meta-badge detail-priority-badge priority-pill meta-select\" data-variant=\"${escapeHtml(priorityKey)}\" data-meta-field=\"priority\" aria-label=\"Ticket priority\">${priorityOptions}</select>\n </div>\n `;\n\n renderDrawerShell({\n mode: \"ticket\",\n title: ticket.title,\n titleAttrs: {\n class: \"editable-field\",\n \"data-edit-field\": \"title\",\n role: \"button\",\n tabindex: \"0\",\n title: \"Click or press Enter to edit ticket title\",\n \"aria-label\": \"Edit ticket title\",\n },\n subtitleHtml: detailSubtitleHtml,\n body: `\n <div class=\"detail-head\">\n <p class=\"detail-updated\" title=\"Last saved change\">Updated ${escapeHtml(formatDateDetail(ticket.updated_at))}</p>\n <div class=\"${descriptionClass}\" data-edit-field=\"description\" tabindex=\"0\" title=\"Click to edit\">${descriptionHtml}</div>\n </div>\n\n <div class=\"settings-stack detail-section-stack\">\n ${renderPanel({\n title: \"Labels\",\n body: `\n <div class=\"settings-row\">\n <div class=\"label-pills-row\" data-other-labels>${labelPills}</div>\n <div class=\"label-add-row\">\n <div class=\"label-add-input-wrap\">\n <input type=\"text\" class=\"label-add-input meta-inline-input\" data-label-input autocomplete=\"off\" placeholder=\"Add label\u2026\" aria-label=\"Add label\" />\n </div>\n <button type=\"button\" class=\"meta-add-btn detail-action-btn\" data-variant=\"ghost\" data-label-add>Add</button>\n </div>\n </div>\n `,\n })}\n\n ${renderHierarchySection(ticket, context)}\n\n ${features.attachments ? renderAttachmentSection(ticket, attachmentList.attachments || []) : \"\"}\n\n ${renderParentEpicSection(ticket, context)}\n\n ${renderPanel({\n title: \"Related\",\n body: `<div class=\"settings-row\">${renderRelated(context.relations, ticket)}</div>`,\n })}\n\n ${\n currentBoard()?.ai_enabled !== 0\n ? renderTogglePanel({\n title: \"AI Plan / Implementation Record\",\n open: aiPlanOpen(ticket.id),\n attrs: `data-ai-plan-toggle data-ticket-id=\"${escapeHtml(ticket.id)}\"`,\n body: `\n <div class=\"ai-fields-grid\">\n ${renderInlinePreservedTextField({\n fieldName: \"ai_plan\",\n label: \"AI Plan\",\n value: ticket.ai_plan,\n placeholder: \"What to do: \",\n ticketId: ticket.id,\n artifactPath: ticket.plan_artifact_path,\n artifactFieldName: \"plan_artifact_path\",\n artifactLabel: \"Open full handoff\",\n })}\n ${renderInlinePreservedTextField({\n fieldName: \"implementation_summary\",\n label: \"Work Summary\",\n value: ticket.implementation_summary,\n placeholder: \"What was done: \",\n ticketId: ticket.id,\n artifactPath: ticket.implementation_artifact_path,\n artifactFieldName: \"implementation_artifact_path\",\n artifactLabel: \"Open full report\",\n })}\n ${renderInlinePreservedTextField({\n fieldName: \"implementation_updates\",\n label: \"Revisions\",\n value: ticket.implementation_updates,\n placeholder: \"Changes since initial implementation: \",\n })}\n </div>`,\n })\n : \"\"\n }\n\n ${renderPanel({\n title: \"Status History\",\n body: `<div class=\"settings-row\">${renderStatusHistory(statusHistory)}</div>`,\n })}\n\n ${renderPanel({\n title: \"Comments\",\n body: `\n <div class=\"settings-row\">\n ${comments.map(renderComment).join(\"\") || `<p class=\"description\">No comments yet.</p>`}\n <form class=\"comment-form\" id=\"detailCommentForm\">\n <textarea name=\"body\" placeholder=\"Add a comment, decision, or instruction...\" required></textarea>\n <button type=\"submit\" class=\"detail-action-btn\" data-variant=\"ghost\">Comment</button>\n </form>\n </div>\n `,\n })}\n </div>\n `,\n });\n\n wireTicketDetailEditors(ticket, context);\n if (features.attachments) wireAttachmentControls(ticket);\n\n const commentTextarea = $(\"#detailCommentForm textarea\");\n commentTextarea?.addEventListener(\"keydown\", (event) => {\n handleTextareaIndentationKeydown(event, commentTextarea);\n });\n\n $(\"#detailCommentForm\").addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const body = cleanText(\n new FormData(event.currentTarget).get(\"body\"),\n ).trim();\n if (!body) return;\n await api(withBoardQuery(`/api/tickets/${ticket.id}/comments`), {\n method: \"POST\",\n body: { body },\n });\n await refreshTicketDetail(ticket.id);\n });\n\n drawerInner.querySelectorAll(\"[data-comment-action='toggle-ai-omission']\").forEach((button) => {\n button.addEventListener(\"click\", async () => {\n const commentId = button.dataset.commentId;\n if (!commentId) return;\n const omittedForAi = button.dataset.omittedForAi !== \"true\";\n await api(withBoardQuery(`/api/tickets/${ticket.id}/comments/${commentId}`), {\n method: \"PATCH\",\n body: { omitted_for_ai: omittedForAi },\n });\n toast.info(omittedForAi ? \"Comment omitted from AI context\" : \"Comment included in AI context\");\n await refreshTicketDetail(ticket.id);\n });\n });\n\n drawerInner.querySelectorAll(\"[data-open-ticket]\").forEach((card) => {\n card.addEventListener(\"click\", async (event) => {\n if (\n event.target.closest(\n \"[data-detach-child],[data-detach-parent],[data-detach-relation]\",\n )\n )\n return;\n navigate({\n boardId: state.boardId,\n view: \"ticket\",\n ticketId: card.dataset.openTicket,\n });\n });\n });\n\n drawerInner.querySelectorAll(\"[data-detach-child]\").forEach((btn) => {\n btn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n const childId = btn.dataset.detachChild;\n try {\n await api(withBoardQuery(`/api/tickets/${childId}`), {\n method: \"PATCH\",\n body: { parent_ticket_id: null },\n });\n } catch (err) {\n toast.error(err.message || \"Failed to remove child\");\n return;\n }\n await refreshTicketDetail(ticket.id, { renderBoardAfter: true });\n toast.success(\"Removed from epic\");\n });\n });\n\n drawerInner.querySelectorAll(\"[data-detach-parent]\").forEach((btn) => {\n btn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n try {\n await api(withBoardQuery(`/api/tickets/${ticket.id}`), {\n method: \"PATCH\",\n body: { parent_ticket_id: null },\n });\n } catch (err) {\n toast.error(err.message || \"Failed to remove parent\");\n return;\n }\n await refreshTicketDetail(ticket.id, { renderBoardAfter: true });\n toast.success(\"Parent epic removed\");\n });\n });\n\n drawerInner.querySelectorAll(\"[data-detach-relation]\").forEach((btn) => {\n btn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n const relationId = btn.dataset.detachRelation;\n try {\n await api(withBoardQuery(`/api/relations/${relationId}`), {\n method: \"DELETE\",\n });\n } catch (err) {\n toast.error(err.message || \"Failed to remove relation\");\n return;\n }\n await refreshTicketDetail(ticket.id);\n toast.success(\"Relation removed\");\n });\n });\n\n const aiPlanEl = drawerInner.querySelector(\"[data-ai-plan-toggle]\");\n if (aiPlanEl) {\n aiPlanEl.addEventListener(\"toggle\", () => {\n const id = aiPlanEl.dataset.ticketId;\n if (aiPlanEl.open) localStorage.setItem(`mab_ai_plan_open:${id}`, \"1\");\n else localStorage.removeItem(`mab_ai_plan_open:${id}`);\n });\n }\n\n drawerInner.querySelectorAll(\"[data-open-artifact]\").forEach((btn) => {\n btn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n const artifactFieldName = btn.dataset.artifactField;\n const artifactTitle = btn.dataset.artifactTitle || \"Linked artifact\";\n const artifactTicketId = btn.dataset.artifactTicketId || ticket.id;\n const currentPath = String(btn.dataset.openArtifact || \"\").trim();\n if (!currentPath) {\n await promptAndSaveArtifactPath({\n ticketId: artifactTicketId,\n fieldName: artifactFieldName,\n currentPath,\n label: artifactTitle,\n });\n return;\n }\n const opened = await openArtifactDrawer({\n ticketId: artifactTicketId,\n path: currentPath,\n title: artifactTitle,\n });\n if (opened === false && artifactFieldName) {\n await promptAndSaveArtifactPath({\n ticketId: artifactTicketId,\n fieldName: artifactFieldName,\n currentPath,\n label: artifactTitle,\n });\n }\n });\n });\n\n const parentEpicForm = drawerInner.querySelector(\"#parentEpicForm\");\n if (parentEpicForm) {\n const parentInput = parentEpicForm.querySelector(\"[name=target]\");\n const parentClear = parentEpicForm.querySelector(\n \"[data-parent-epic-clear]\",\n );\n attachTicketTypeahead(parentInput, () => epicCandidates(ticket));\n const syncParentClear = () => {\n parentEpicForm.classList.toggle(\n \"has-value\",\n parentInput.value.length > 0,\n );\n };\n parentInput.addEventListener(\"input\", syncParentClear);\n syncParentClear();\n parentClear.addEventListener(\"click\", () => {\n parentInput.value = \"\";\n syncParentClear();\n parentInput.focus();\n });\n parentEpicForm.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const targetLabel = String(\n new FormData(event.currentTarget).get(\"target\") || \"\",\n ).trim();\n if (!targetLabel) return;\n const targetId = resolveTicketIdFromLabel(targetLabel, ticket.id);\n if (!targetId) {\n toast.warning(\"Pick an epic from the suggestions\");\n return;\n }\n const target = ticketsForProject().find((t) => t.id === targetId);\n if (!target || canonicalTicketType(target.type) !== \"epic\") {\n toast.warning(\"Parent must be an epic\");\n return;\n }\n try {\n await api(withBoardQuery(`/api/tickets/${ticket.id}`), {\n method: \"PATCH\",\n body: { parent_ticket_id: targetId },\n });\n } catch (err) {\n toast.error(err.message || \"Failed to set parent epic\");\n return;\n }\n await refreshTicketDetail(ticket.id, { renderBoardAfter: true });\n toast.success(\"Parent epic set\");\n });\n }\n\n const relatedAddForm = drawerInner.querySelector(\"#relatedAddForm\");\n if (relatedAddForm) {\n const relatedInput = relatedAddForm.querySelector(\"[name=target]\");\n const relatedClear = relatedAddForm.querySelector(\"[data-related-clear]\");\n attachTicketTypeahead(relatedInput, () =>\n relatedTicketCandidates(context.relations, ticket),\n );\n const syncRelatedClear = () => {\n relatedAddForm.classList.toggle(\n \"has-value\",\n relatedInput.value.length > 0,\n );\n };\n relatedInput.addEventListener(\"input\", syncRelatedClear);\n syncRelatedClear();\n relatedClear.addEventListener(\"click\", () => {\n relatedInput.value = \"\";\n syncRelatedClear();\n relatedInput.focus();\n });\n relatedAddForm.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n const targetLabel = String(form.get(\"target\") || \"\").trim();\n const relationType = String(form.get(\"type\") || \"relates_to\");\n if (!targetLabel) return;\n const targetId = resolveTicketIdFromLabel(targetLabel, ticket.id);\n if (!targetId) {\n toast.warning(\"Pick a ticket from the suggestions\");\n return;\n }\n try {\n await api(withBoardQuery(`/api/relations`), {\n method: \"POST\",\n body: {\n source_ticket_id: ticket.id,\n target_ticket_id: targetId,\n type: relationType,\n },\n });\n } catch (err) {\n toast.error(err.message || \"Failed to add relation\");\n return;\n }\n await refreshTicketDetail(ticket.id);\n });\n }\n\n // Reverse of \"Set parent epic\": from an epic, pull a feature/task in as a\n // child by patching that ticket's parent_ticket_id to this epic.\n const epicChildForm = drawerInner.querySelector(\"#epicChildForm\");\n if (epicChildForm) {\n const childInput = epicChildForm.querySelector(\"[name=target]\");\n const childClear = epicChildForm.querySelector(\"[data-epic-child-clear]\");\n const syncChildClear = () => {\n epicChildForm.classList.toggle(\"has-value\", childInput.value.length > 0);\n };\n childInput.addEventListener(\"input\", syncChildClear);\n syncChildClear();\n childClear.addEventListener(\"click\", () => {\n childInput.value = \"\";\n syncChildClear();\n childInput.focus();\n });\n attachTicketTypeahead(childInput, () => childCandidates(ticket));\n epicChildForm.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const targetLabel = String(\n new FormData(event.currentTarget).get(\"target\") || \"\",\n ).trim();\n if (!targetLabel) return;\n const targetId = resolveTicketIdFromLabel(targetLabel, ticket.id);\n if (!targetId) {\n toast.warning(\"Pick a ticket from the suggestions\");\n return;\n }\n const target = ticketsForProject().find((t) => t.id === targetId);\n if (!target || canonicalTicketType(target.type) === \"epic\") {\n toast.warning(\"Epics can't be nested inside an epic\");\n return;\n }\n try {\n await api(withBoardQuery(`/api/tickets/${targetId}`), {\n method: \"PATCH\",\n body: { parent_ticket_id: ticket.id },\n });\n } catch (err) {\n toast.error(err.message || \"Failed to add feature\");\n return;\n }\n await refreshTicketDetail(ticket.id, { renderBoardAfter: true });\n toast.success(\"Feature added to epic\");\n });\n }\n\n openDrawer();\n}\n\nfunction aiPlanOpen(ticketId) {\n return localStorage.getItem(`mab_ai_plan_open:${ticketId}`) === \"1\";\n}\n\nfunction renderAttachmentSection(ticket, attachments = []) {\n const cards = attachments.length\n ? `<div class=\"attachment-grid\">${attachments.map((attachment) => renderAttachmentCard(ticket, attachment)).join(\"\")}</div>`\n : `<p class=\"description attachment-empty-state\">No images attached yet.</p>`;\n return renderPanel({\n title: \"Images\",\n className: \"attachments-panel\",\n attrs: `data-attachment-section data-ticket-id=\"${escapeHtml(ticket.id)}\"`,\n body: `\n <div class=\"settings-row\">\n <div class=\"attachment-dropzone\" data-attachment-dropzone tabindex=\"0\">\n <strong>Paste, drag, or upload images</strong>\n <span>PNG, JPG, GIF, WebP, SVG, BMP, or AVIF up to 10 MB each.</span>\n </div>\n ${cards}\n <label class=\"attachment-upload-button detail-action-btn\" role=\"button\" data-variant=\"ghost\" tabindex=\"0\">\n Upload\n <input type=\"file\" accept=\"image/*\" multiple data-attachment-input />\n </label>\n </div>\n `,\n });\n}\n\nfunction renderAttachmentCard(ticket, attachment) {\n const name = escapeHtml(attachment.original_name || \"image\");\n const meta = `${formatBytes(attachment.size_bytes)} \u00B7 ${escapeHtml(attachment.mime_type || \"image\")}`;\n if (attachment.missing) {\n return `\n <article class=\"attachment-card is-missing\">\n <div class=\"attachment-missing-thumb\">Missing</div>\n <div class=\"attachment-card-meta\"><strong>${name}</strong><span>${meta}</span></div>\n <button type=\"button\" class=\"attachment-delete\" data-delete-attachment=\"${escapeHtml(attachment.id)}\" aria-label=\"Remove missing image\">${closeIconSvg}</button>\n </article>\n `;\n }\n const src = withBoardQuery(\n attachment.content_url ||\n `/api/tickets/${ticket.id}/attachments/${attachment.id}/content`,\n );\n return `\n <article class=\"attachment-card\">\n <button type=\"button\" class=\"attachment-thumb-button\" data-no-arc data-open-lightbox=\"${escapeHtml(src)}\" data-lightbox-title=\"${name}\">\n <img src=\"${escapeHtml(src)}\" alt=\"${name}\" loading=\"lazy\" />\n </button>\n <div class=\"attachment-card-meta\"><strong>${name}</strong><span>${meta}</span></div>\n <button type=\"button\" class=\"attachment-delete\" data-delete-attachment=\"${escapeHtml(attachment.id)}\" aria-label=\"Remove image\">${closeIconSvg}</button>\n </article>\n `;\n}\n\nfunction formatBytes(value) {\n const bytes = Number(value || 0);\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction imageFilesFromList(files) {\n return [...(files || [])].filter(\n (file) => file && String(file.type || \"\").startsWith(\"image/\"),\n );\n}\n\nasync function uploadAttachmentFiles(ticket, files) {\n const imageFiles = imageFilesFromList(files);\n if (!imageFiles.length) {\n toast.warning(\"No image files found\");\n return;\n }\n for (const file of imageFiles) {\n const response = await fetch(\n withBoardQuery(\n `/api/tickets/${ticket.id}/attachments?filename=${encodeURIComponent(file.name || \"image\")}`,\n ),\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": file.type || \"application/octet-stream\",\n \"X-File-Name\": file.name || \"image\",\n },\n body: file,\n },\n );\n if (!response.ok) {\n let payload = {};\n try {\n payload = await response.json();\n } catch {}\n throw new Error(payload.error || `Upload failed (${response.status})`);\n }\n }\n await refreshTicketDetail(ticket.id);\n toast.success(\n imageFiles.length === 1\n ? \"Image attached\"\n : `${imageFiles.length} images attached`,\n );\n}\n\nfunction wireAttachmentControls(ticket) {\n const section = drawerInner.querySelector(\"[data-attachment-section]\");\n if (!section) return;\n const input = section.querySelector(\"[data-attachment-input]\");\n input?.addEventListener(\"change\", async () => {\n try {\n await uploadAttachmentFiles(ticket, input.files);\n input.value = \"\";\n } catch (err) {\n toast.error(err.message || \"Upload failed\");\n }\n });\n\n const dropzone = section.querySelector(\"[data-attachment-dropzone]\");\n dropzone?.addEventListener(\"dragover\", (event) => {\n event.preventDefault();\n dropzone.classList.add(\"is-dragover\");\n });\n dropzone?.addEventListener(\"dragleave\", () =>\n dropzone.classList.remove(\"is-dragover\"),\n );\n dropzone?.addEventListener(\"drop\", async (event) => {\n event.preventDefault();\n dropzone.classList.remove(\"is-dragover\");\n try {\n await uploadAttachmentFiles(ticket, event.dataTransfer?.files || []);\n } catch (err) {\n toast.error(err.message || \"Upload failed\");\n }\n });\n\n drawerInner.onpaste = async (event) => {\n if (event.target.closest(\"input, textarea, [contenteditable='true']\"))\n return;\n const files = imageFilesFromList(event.clipboardData?.files || []);\n if (!files.length) return;\n event.preventDefault();\n try {\n await uploadAttachmentFiles(ticket, files);\n } catch (err) {\n toast.error(err.message || \"Paste upload failed\");\n }\n };\n\n section.querySelectorAll(\"[data-delete-attachment]\").forEach((btn) => {\n btn.addEventListener(\"click\", async () => {\n try {\n await api(\n withBoardQuery(\n `/api/tickets/${ticket.id}/attachments/${btn.dataset.deleteAttachment}`,\n ),\n { method: \"DELETE\" },\n );\n await refreshTicketDetail(ticket.id);\n toast.success(\"Image removed\");\n } catch (err) {\n toast.error(err.message || \"Delete failed\");\n }\n });\n });\n\n section.querySelectorAll(\"[data-open-lightbox]\").forEach((btn) => {\n btn.addEventListener(\"click\", () =>\n openAttachmentLightbox(\n btn.dataset.openLightbox,\n btn.dataset.lightboxTitle || \"Image\",\n ),\n );\n });\n}\n\nfunction openAttachmentLightbox(src, title) {\n const existing = document.querySelector(\".attachment-lightbox\");\n existing?.remove();\n const overlay = document.createElement(\"div\");\n overlay.className = \"attachment-lightbox\";\n overlay.innerHTML = `\n <div class=\"attachment-lightbox-panel\" role=\"dialog\" aria-modal=\"true\" aria-label=\"${escapeHtml(title)}\">\n <button type=\"button\" class=\"attachment-lightbox-close\" aria-label=\"Close image\">${closeIconSvg}</button>\n <img src=\"${escapeHtml(src)}\" alt=\"${escapeHtml(title)}\" />\n <p>${escapeHtml(title)}</p>\n </div>\n `;\n const close = () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n overlay.remove();\n };\n function onKeyDown(event) {\n if (event.key === \"Escape\") close();\n }\n overlay.addEventListener(\"click\", (event) => {\n if (\n event.target === overlay ||\n event.target.closest(\".attachment-lightbox-close\")\n )\n close();\n });\n document.addEventListener(\"keydown\", onKeyDown);\n document.body.append(overlay);\n}\n\nfunction resolveTicketIdFromLabel(label, selfId) {\n const trimmed = label.trim();\n const match = trimmed.match(/^#?(\\d+)\\b/);\n const tickets = ticketsForProject().filter((t) => t.id !== selfId);\n if (match) {\n const n = Number(match[1]);\n const hit = tickets.find((t) => t.number === n);\n if (hit) return hit.id;\n }\n const exact = tickets.find((t) => `#${t.number} \u2014 ${t.title}` === trimmed);\n return exact ? exact.id : \"\";\n}\n\nfunction renderStatusHistory(history) {\n if (!history || history.length === 0) {\n return `<p class=\"description\">No status changes yet.</p>`;\n }\n return history\n .map((event) => {\n const body = event.body;\n const from = body.from ? escapeHtml(body.from) : \"?\";\n const to = escapeHtml(body.to || body.state || body.next_state || \"?\");\n const byLine = escapeHtml(\n formatActorLabel({\n actor: event.actor,\n actorType: body.actor_type || \"human\",\n actorId: body.actor_id,\n }),\n );\n return `<div class=\"comment status-change\">\n <div class=\"comment-meta\">\n <span class=\"status-route\">${from} \u2192 ${to}</span>\n <span>${byLine} \u00B7 ${formatDate(event.created_at)}</span>\n </div>\n </div>`;\n })\n .join(\"\");\n}\n\nfunction renderComment(comment) {\n const aiEnabled = currentBoard()?.ai_enabled !== 0;\n const omittedForAi = Boolean(comment.omitted_for_ai);\n const kindLabel =\n comment.kind === \"human_comment\" ? \"\" : escapeHtml(comment.kind.replace(/_/g, \" \"));\n return `\n <div class=\"comment ${comment.kind === \"checkpoint\" ? \"checkpoint\" : \"\"} ${aiEnabled && omittedForAi ? \"is-ai-omitted\" : \"\"}\">\n <div class=\"comment-head\">\n <div class=\"comment-head-main\">\n <div class=\"comment-head-title\">\n <strong>${escapeHtml(formatCommentAuthor(comment))}</strong>\n ${kindLabel ? `<span class=\"comment-kind-pill\">${kindLabel}</span>` : \"\"}\n </div>\n </div>\n </div>\n <div class=\"comment-body preserved-text-body\">${renderPreservedText(comment.body)}</div>\n <div class=\"comment-footer\">\n <span class=\"comment-footer-meta\">${formatDate(comment.created_at)}</span>\n ${\n aiEnabled\n ? `<button\n type=\"button\"\n class=\"comment-ai-toggle detail-action-btn\"\n data-variant=\"ghost\"\n data-comment-action=\"toggle-ai-omission\"\n data-comment-id=\"${escapeHtml(comment.id)}\"\n data-omitted-for-ai=\"${omittedForAi ? \"true\" : \"false\"}\"\n >${omittedForAi ? \"AI Include\" : \"AI Ignore\"}</button>`\n : \"\"\n }\n </div>\n </div>\n `;\n}\n\n/**\n * Click-to-edit row for AI Plan / Implementation fields and any other\n * long-form ticket field that should render literal read-only text and become\n * a textarea on click. The wiring (event handlers + commit) lives in\n * wireTicketDetailEditors so this helper stays a pure template.\n */\nexport function renderInlinePreservedTextField({\n fieldName,\n label,\n value,\n placeholder,\n ticketId,\n artifactPath,\n artifactFieldName,\n artifactLabel,\n}) {\n const text = value || \"\";\n const hasValue = Boolean(text.trim());\n const artifactPathText = String(artifactPath || \"\").trim();\n const hasArtifactControl = Boolean(artifactLabel || artifactFieldName);\n const inner = hasValue\n ? renderPreservedText(text)\n : escapeHtml(placeholder || \"\");\n const placeholderClass = hasValue ? \"\" : \"is-placeholder\";\n const artifactButton = hasArtifactControl\n ? `<button\n type=\"button\"\n class=\"detail-action-btn\"\n data-variant=\"ghost\"\n data-open-artifact=\"${escapeHtml(artifactPathText)}\"\n data-artifact-field=\"${escapeHtml(artifactFieldName || \"\")}\"\n data-artifact-ticket-id=\"${escapeHtml(ticketId || \"\")}\"\n data-artifact-title=\"${escapeHtml(label)}\"\n >${escapeHtml(artifactLabel || \"Open full artifact\")}</button>`\n : \"\";\n return `\n <div class=\"inline-md-field\">\n <div class=\"inline-md-field-head\">\n <span class=\"inline-md-field-label\">${escapeHtml(label)}</span>\n ${artifactButton}\n </div>\n <div\n class=\"inline-md-field-body preserved-text-body editable-field ${placeholderClass}\"\n data-edit-field=\"${escapeHtml(fieldName)}\"\n tabindex=\"0\"\n title=\"Click to edit\"\n role=\"button\"\n aria-label=\"Edit ${escapeHtml(label)}\"\n >${inner}</div>\n </div>\n `;\n}\n\n// Tickets eligible to be linked as \"related\": everything in the project except\n// the ticket itself, its existing relations, and its parent/child hierarchy.\nfunction relatedTicketCandidates(relations = [], ticket) {\n const relatedIds = new Set(relations.map((r) => r.other_ticket.id));\n const hierarchyIds = new Set();\n if (ticket?.parent_ticket_id) hierarchyIds.add(ticket.parent_ticket_id);\n if (ticket?.id) {\n for (const t of ticketsForProject()) {\n if (t.parent_ticket_id === ticket.id) hierarchyIds.add(t.id);\n }\n }\n return ticketsForProject().filter(\n (t) =>\n t.id !== ticket?.id && !relatedIds.has(t.id) && !hierarchyIds.has(t.id),\n );\n}\n\nfunction renderRelated(relations = [], ticket) {\n const list = relations.length\n ? `<div class=\"detail-card-grid\">${relations.map((r) => renderRelatedCard(r)).join(\"\")}</div>`\n : \"\";\n\n const form = `\n <form id=\"relatedAddForm\" class=\"related-add-row\">\n <div class=\"related-add-input-wrap\">\n <input type=\"text\" name=\"target\" class=\"related-add-input meta-inline-input\" placeholder=\"Add related ticket\u2026\" aria-label=\"Add related ticket\" autocomplete=\"off\" />\n <button type=\"button\" class=\"related-add-clear\" data-related-clear aria-label=\"Clear\" tabindex=\"-1\">${closeIconSvg}</button>\n </div>\n <select name=\"type\" class=\"related-add-type meta-inline\" aria-label=\"Relation type\">\n <option value=\"relates_to\">relates to</option>\n <option value=\"blocks\">blocks</option>\n <option value=\"blocked_by\">blocked by</option>\n </select>\n <button type=\"submit\" class=\"meta-add-btn detail-action-btn\" data-variant=\"ghost\">Add</button>\n </form>\n `;\n\n return list + form;\n}\n\nfunction renderHierarchySection(ticket, context) {\n const isEpic = canonicalTicketType(ticket.type) === \"epic\";\n if (!isEpic) return \"\";\n\n const cards = context.child_tickets || [];\n const grid = cards.length\n ? `<div class=\"detail-card-grid\">${cards.map((c) => renderDetailCard(c, { detach: { mode: \"child\", id: c.id } })).join(\"\")}</div>`\n : \"\";\n\n const form = `\n <form id=\"epicChildForm\" class=\"related-add-row epic-child-form\">\n <div class=\"related-add-input-wrap\">\n <input type=\"text\" name=\"target\" class=\"related-add-input meta-inline-input\" placeholder=\"Add feature to epic\u2026\" aria-label=\"Add feature to epic\" autocomplete=\"off\" />\n <button type=\"button\" class=\"related-add-clear\" data-epic-child-clear aria-label=\"Clear\" tabindex=\"-1\">${closeIconSvg}</button>\n </div>\n <button type=\"submit\" class=\"meta-add-btn detail-action-btn\" data-variant=\"ghost\">Add</button>\n </form>\n `;\n\n return renderPanel({\n title: \"Features inside this Epic\",\n body: `<div class=\"settings-row\">${grid}${form}</div>`,\n });\n}\n\n// Epics eligible to become this ticket's parent (any epic but itself).\nfunction epicCandidates(ticket) {\n return ticketsForProject().filter(\n (t) => t.type === \"epic\" && t.id !== ticket.id,\n );\n}\n\n// Tickets eligible to be pulled into this epic as children: any non-epic ticket\n// not already parented to it. (A ticket with another parent is reparented.)\nfunction childCandidates(epic) {\n return ticketsForProject().filter(\n (t) =>\n t.id !== epic.id &&\n canonicalTicketType(t.type) !== \"epic\" &&\n t.parent_ticket_id !== epic.id,\n );\n}\n\n\n// Board labels not yet applied to this ticket, as {name, color} items.\nfunction labelCandidates(ticket) {\n const applied = new Set((ticket.labels || []).map((l) => l.name));\n return boardLabelCatalog().filter((l) => !applied.has(l.name));\n}\n\n// A typeahead row for a label: colour swatch + bold name. Mirrors the topbar\n// hit layout (bold lead + trailing badge), adapted for a label's lack of a\n// number / state.\nfunction renderLabelHitRow(label) {\n return `\n <span class=\"search-hit-main\">\n <span class=\"typeahead-swatch\" style=\"--label-color: ${escapeHtml(label.color || \"var(--muted)\")}\"></span>\n <strong>${escapeHtml(label.name)}</strong>\n </span>\n `;\n}\n\nfunction attachLabelTypeahead(input, ticket) {\n if (!input) return;\n attachTypeahead(input, {\n getItems: () => labelCandidates(ticket),\n match: (label, query) => label.name.toLowerCase().includes(query),\n renderItem: renderLabelHitRow,\n valueOf: (label) => label.name,\n emptyText: \"No matching labels\",\n });\n}\n\nfunction renderParentEpicSection(ticket, context) {\n if (canonicalTicketType(ticket.type) === \"epic\") return \"\";\n\n const body = context.parent_ticket\n ? `<div class=\"detail-card-grid detail-card-grid--single\">${renderDetailCard(context.parent_ticket, { detach: { mode: \"parent\" } })}</div>`\n : `\n <form id=\"parentEpicForm\" class=\"related-add-row parent-epic-form\">\n <div class=\"related-add-input-wrap\">\n <input type=\"text\" name=\"target\" class=\"related-add-input meta-inline-input\" placeholder=\"Set parent epic\u2026\" aria-label=\"Set parent epic\" autocomplete=\"off\" />\n <button type=\"button\" class=\"related-add-clear\" data-parent-epic-clear aria-label=\"Clear\" tabindex=\"-1\">${closeIconSvg}</button>\n </div>\n <button type=\"submit\" class=\"meta-add-btn detail-action-btn\" data-variant=\"ghost\">Set</button>\n </form>\n `;\n\n return renderPanel({\n title: \"Epic\",\n body: `<div class=\"settings-row\">${body}</div>`,\n });\n}\n\nexport function renderDetailCard(ticket, options = {}) {\n const canonicalType = canonicalTicketType(ticket.type);\n const priorityKey = priorityKeyFor(ticket.priority);\n const stateClass = stateClassFor(ticket);\n const typeText = typeLabel(ticket.type).toUpperCase();\n const eyebrow = options.eyebrow\n ? `<span class=\"card-eyebrow\">${escapeHtml(options.eyebrow)}</span>`\n : \"\";\n let detachBtn = \"\";\n if (options.detach) {\n const { mode, id } = options.detach;\n let attr = \"\";\n let label = \"\";\n if (mode === \"child\") {\n attr = `data-detach-child=\"${escapeHtml(id)}\"`;\n label = \"Remove from epic\";\n } else if (mode === \"parent\") {\n attr = `data-detach-parent=\"1\"`;\n label = \"Remove parent epic\";\n } else if (mode === \"relation\") {\n attr = `data-detach-relation=\"${escapeHtml(id)}\"`;\n label = \"Remove relation\";\n }\n detachBtn = `<button type=\"button\" class=\"card-detach-btn\" ${attr} aria-label=\"${label}\" title=\"${label}\">${closeIconSvg}</button>`;\n } else if (options.archive) {\n const tid = escapeHtml(options.archive.id);\n const restoreSvg = `<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M3 12a9 9 0 1 0 3-6.7\"/><path d=\"M3 4v5h5\"/></svg>`;\n const trashSvg = `<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M3 6h18\"/><path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/><path d=\"M10 11v6\"/><path d=\"M14 11v6\"/></svg>`;\n detachBtn = `\n <div class=\"card-archive-actions\">\n <button type=\"button\" class=\"card-archive-btn card-archive-btn--restore\" data-archive-restore=\"${tid}\" aria-label=\"Restore to board\" title=\"Restore to board\">${restoreSvg}</button>\n <button type=\"button\" class=\"card-archive-btn card-archive-btn--delete\" data-archive-delete=\"${tid}\" aria-label=\"Delete permanently\" title=\"Delete permanently\">${trashSvg}</button>\n </div>\n `;\n }\n const unreadN = unreadCount(ticket);\n const unreadDot =\n unreadN === 0\n ? \"\"\n : unreadN === 1\n ? `<span class=\"card-unread-dot\" role=\"status\" aria-label=\"1 unread update\"></span>`\n : `<span class=\"card-unread-dot has-count\" role=\"status\" aria-label=\"${unreadN} unread updates\">${unreadN > 99 ? \"99+\" : unreadN}</span>`;\n return `\n <article class=\"card card--detail type-${escapeHtml(canonicalType)} priority-${escapeHtml(priorityKey)}\" data-variant=\"${escapeHtml(canonicalType)}\"${options.disableOpen ? \"\" : ` data-open-ticket=\"${escapeHtml(ticket.id)}\"`}>\n ${unreadDot}\n ${eyebrow}\n <h3>${escapeHtml(ticket.title)}</h3>\n <div class=\"card-meta\">\n <div class=\"card-expand-trigger card-expand-trigger--static\">\n <span class=\"ticket-number\">${escapeHtml(ticketLabel(ticket))}</span>\n <div class=\"card-type-id type-pill-${escapeHtml(canonicalType)}\">\n ${renderTypeIcon(ticket.type)}\n <span class=\"card-type-label\">${escapeHtml(typeText)}</span>\n </div>\n <span class=\"detail-card-state\" data-variant=\"${escapeHtml(stateClass)}\">${escapeHtml(ticket.state_name || \"State\")}</span>\n ${state.showPriority ? renderPriorityPill(ticket.priority) : \"\"}\n ${detachBtn}\n </div>\n </div>\n </article>\n `;\n}\n\nfunction renderRelatedCard(relation) {\n const verb = String(relation.type || \"\").replace(/_/g, \" \");\n const direction = relation.direction === \"incoming\" ? \"from\" : \"to\";\n return renderDetailCard(relation.other_ticket, {\n eyebrow: `${verb} ${direction}`,\n detach: { mode: \"relation\", id: relation.id },\n });\n}\n", "// Server-sent events client. Subscribes to /api/events/stream and turns\n// server events into a debounced bootstrap reload + toast notifications.\n// Owns its own reconnect backoff for the rare case where the browser's\n// auto-reconnect gives up (e.g., HTTP error \u2192 CLOSED state).\n\nimport { state, syncBoardSelection } from \"./state.js\";\nimport { api, bootstrapPath } from \"./api.js\";\nimport { toast, debounce } from \"./toast.js\";\nimport { render } from \"./app.js\";\nimport { markRead, bumpUnread, clearUnread } from \"./unread.js\";\n\n// Event types that meaningfully change a card's state from the human's POV\n// \u2014 these are the ones that should bump the per-card unread count.\nconst CARD_TOUCHING_EVENTS = new Set([\n \"ticket_created\",\n \"state_changed\",\n \"ticket_updated\",\n \"comment_created\",\n \"comment_ai_omission_changed\",\n \"agent_claimed\",\n \"checkpoint_requested\",\n \"agent_completed\"\n]);\n\n// Manual reconnect backoff for the rare case the browser's auto-reconnect\n// gives up (e.g., the server returned an HTTP error and EventSource entered\n// the CLOSED state). Reset on every successful open.\nlet sseReconnectDelayMs = 1000;\nlet sseReconnectTimer = null;\nlet sseDisconnectToastShown = false;\n\nexport function connectEventStream() {\n if (sseReconnectTimer) {\n clearTimeout(sseReconnectTimer);\n sseReconnectTimer = null;\n }\n if (state.eventSource) {\n state.eventSource.close();\n state.eventSource = null;\n }\n\n const params = new URLSearchParams();\n if (state.boardId) params.set(\"board_id\", state.boardId);\n const url = `/api/events/stream${params.toString() ? `?${params}` : \"\"}`;\n\n const es = new EventSource(url);\n state.eventSource = es;\n\n es.addEventListener(\"open\", () => {\n sseReconnectDelayMs = 1000;\n if (sseDisconnectToastShown) {\n toast.success(\"Live updates reconnected\");\n sseDisconnectToastShown = false;\n }\n });\n\n es.addEventListener(\"board\", async (msg) => {\n let event;\n try {\n event = JSON.parse(msg.data);\n } catch {\n return;\n }\n\n const eventType = event.type;\n const findTicket = () => state.data?.tickets?.find((t) => t.id === event.ticket_id);\n\n // Per-card unread counter:\n // - my own events \u2192 mark read (no badge for my own changes)\n // - foreign card-touching events \u2192 bump count by 1\n // - delete \u2192 clear the entry entirely\n const me = state.data?.actor?.name;\n const isMine = event.actor && me && event.actor === me;\n if (event.ticket_id) {\n if (isMine) {\n markRead(event.ticket_id, event.timestamp);\n } else if (eventType === \"ticket_deleted\") {\n clearUnread(event.ticket_id);\n } else if (CARD_TOUCHING_EVENTS.has(eventType)) {\n bumpUnread(event.ticket_id);\n }\n }\n\n if (eventType === \"ticket_created\") {\n toast.success(`Card created: ${event.data.title || \"New card\"}`);\n scheduleSSEReload();\n } else if (eventType === \"state_changed\") {\n const ticket = findTicket();\n const label = ticket ? `#${ticket.number} ${ticket.title}` : \"Card\";\n toast.info(`${label} \u2192 ${event.data.to}`);\n scheduleSSEReload();\n } else if (eventType === \"ticket_updated\") {\n const ticket = findTicket();\n const label = ticket ? `#${ticket.number}` : \"Card\";\n const fields = event.data.fields ? Object.keys(event.data.fields).join(\", \") : \"\";\n toast.info(`${label} updated${fields ? `: ${fields}` : \"\"}`);\n scheduleSSEReload();\n } else if (eventType === \"comment_created\") {\n const ticket = findTicket();\n const label = ticket ? `#${ticket.number}` : \"ticket\";\n toast.info(`New comment on ${label}`);\n scheduleSSEReload();\n } else if (eventType === \"comment_ai_omission_changed\") {\n scheduleSSEReload();\n } else if (eventType === \"agent_claimed\") {\n const ticket = findTicket();\n toast.info(`Agent claimed ${ticket ? `#${ticket.number} ${ticket.title}` : \"a ticket\"}`);\n scheduleSSEReload();\n } else if (eventType === \"checkpoint_requested\") {\n const ticket = findTicket();\n toast.warning(`Checkpoint on ${ticket ? `#${ticket.number}` : \"ticket\"} \u2014 needs human input`);\n scheduleSSEReload();\n } else if (eventType === \"agent_completed\") {\n const ticket = findTicket();\n toast.success(`Agent completed ${ticket ? `#${ticket.number} ${ticket.title}` : \"a ticket\"}`);\n scheduleSSEReload();\n } else if (\n eventType === \"ticket_deleted\" ||\n eventType === \"states_reordered\" ||\n eventType === \"state_created\" ||\n eventType === \"state_deleted\" ||\n eventType === \"board_updated\" ||\n eventType === \"board_imported\"\n ) {\n scheduleSSEReload();\n }\n });\n\n es.onerror = () => {\n // EventSource has three readyStates:\n // 0 (CONNECTING) \u2014 browser will auto-reconnect, no action needed.\n // 1 (OPEN) \u2014 transient blip, browser handles it.\n // 2 (CLOSED) \u2014 browser gave up (e.g., HTTP error). Surface and retry.\n if (es.readyState !== EventSource.CLOSED) return;\n\n if (!sseDisconnectToastShown) {\n toast.warning(\"Live updates disconnected \u2014 retrying\u2026\");\n sseDisconnectToastShown = true;\n }\n\n if (sseReconnectTimer) return;\n const delay = sseReconnectDelayMs;\n sseReconnectDelayMs = Math.min(sseReconnectDelayMs * 2, 30000);\n sseReconnectTimer = setTimeout(() => {\n sseReconnectTimer = null;\n connectEventStream();\n }, delay);\n };\n}\n\nexport const scheduleSSEReload = debounce(async () => {\n const selectedId = state.selectedTicketId;\n const mode = state.detailMode;\n state.data = await api(bootstrapPath());\n syncBoardSelection();\n state.selectedTicketId = selectedId;\n state.detailMode = mode;\n await render();\n}, 300);\n", "import { cleanText, escapeHtml, renderPreservedText } from \"./format.js\";\n\nconst NOTE_FALLBACK = \"No board notes yet\";\nconst NOTES_PLACEHOLDER = \"Add board notes for yourself and your agents\u2026\";\n\nfunction compactText(value) {\n return cleanText(value || \"\")\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean)\n .join(\" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nexport function boardNotesSummary(board = {}) {\n return compactText(board.project_notes) || NOTE_FALLBACK;\n}\n\nfunction updateCachedBoard(board, appState) {\n if (!board?.id || !appState?.data?.boards) return;\n const index = appState.data.boards.findIndex((item) => item.id === board.id);\n if (index >= 0) appState.data.boards.splice(index, 1, { ...appState.data.boards[index], ...board });\n}\n\nlet lastRenderedBoard = {};\n\nfunction renderNotesBody(board) {\n const notes = board?.project_notes || \"\";\n const hasNotes = Boolean(notes.trim());\n const placeholderClass = hasNotes ? \"\" : \" is-placeholder\";\n const inner = hasNotes ? renderPreservedText(notes) : escapeHtml(NOTES_PLACEHOLDER);\n return `\n <div\n class=\"inline-md-field-body preserved-text-body editable-field settings-notes-body brand-focus-notes-edit${placeholderClass}\"\n data-edit-field=\"project_notes\"\n tabindex=\"0\"\n title=\"Click to edit\"\n role=\"button\"\n aria-label=\"Edit Notes For You\"\n >${inner}</div>\n `;\n}\n\nexport function renderTopbarFocus(board = lastRenderedBoard) {\n lastRenderedBoard = board || {};\n const summary = boardNotesSummary(lastRenderedBoard);\n const notesButton = document.getElementById(\"brandNotesBtn\");\n const notesText = document.getElementById(\"brandNotesText\");\n const notesBody = document.getElementById(\"brandFocusNotes\");\n\n if (notesButton) {\n notesButton.hidden = false;\n notesButton.dataset.empty = summary === NOTE_FALLBACK ? \"true\" : \"false\";\n notesButton.setAttribute(\"aria-label\", `Show board notes: ${summary}`);\n }\n if (notesText) notesText.textContent = summary === NOTE_FALLBACK ? \"\" : summary;\n if (notesBody) notesBody.innerHTML = renderNotesBody(lastRenderedBoard);\n}\n\nfunction setPopoverOpen(open) {\n const buttons = [\n document.getElementById(\"brandFocusBtn\"),\n document.getElementById(\"brandNotesBtn\")\n ].filter(Boolean);\n const popover = document.getElementById(\"brandFocusPopover\");\n if (!popover) return;\n for (const button of buttons) {\n button.setAttribute(\"aria-expanded\", open ? \"true\" : \"false\");\n button.dataset.state = open ? \"open\" : \"closed\";\n }\n popover.hidden = !open;\n}\n\nfunction togglePopover() {\n const popover = document.getElementById(\"brandFocusPopover\");\n renderTopbarFocus();\n setPopoverOpen(Boolean(popover?.hidden));\n}\n\nasync function startBoardNotesEdit(sourceEvent) {\n const notesEl = document.querySelector('#brandFocusPopover [data-edit-field=\"project_notes\"]');\n if (!notesEl || !lastRenderedBoard?.id) return;\n const { startInlineEdit } = await import(\"./ticket-detail.js\");\n startInlineEdit(notesEl, {\n fieldName: \"project_notes\",\n multiline: true,\n initialValue: lastRenderedBoard.project_notes || \"\",\n ariaLabel: \"Edit Notes For You\",\n sourceEvent,\n rerender: async () => {\n renderTopbarFocus(lastRenderedBoard);\n setPopoverOpen(true);\n },\n commit: async (next) => {\n const [{ api }, { state }] = await Promise.all([\n import(\"./api.js\"),\n import(\"./state.js\")\n ]);\n const updatedBoard = await api(`/api/boards/${encodeURIComponent(lastRenderedBoard.id || state.boardId)}`, {\n method: \"PATCH\",\n body: { project_notes: cleanText(next) }\n });\n lastRenderedBoard = { ...lastRenderedBoard, ...updatedBoard };\n updateCachedBoard(lastRenderedBoard, state);\n renderTopbarFocus(lastRenderedBoard);\n setPopoverOpen(true);\n }\n });\n}\n\nexport function wireTopbarFocus() {\n const logoButton = document.getElementById(\"brandFocusBtn\");\n const notesButton = document.getElementById(\"brandNotesBtn\");\n const popover = document.getElementById(\"brandFocusPopover\");\n if (!logoButton || !notesButton || !popover) return;\n\n logoButton.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n togglePopover();\n });\n\n notesButton.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n togglePopover();\n });\n\n popover.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n if (event.target.closest('[data-edit-field=\"project_notes\"]')) {\n void startBoardNotesEdit(event);\n }\n });\n\n popover.addEventListener(\"keydown\", (event) => {\n if (event.key !== \"Enter\" && event.key !== \" \") return;\n if (!event.target.closest('[data-edit-field=\"project_notes\"]')) return;\n event.preventDefault();\n void startBoardNotesEdit(event);\n });\n\n document.addEventListener(\"click\", (event) => {\n if (\n event.target.closest(\"#brandFocusBtn\") ||\n event.target.closest(\"#brandNotesBtn\") ||\n event.target.closest(\"#brandFocusPopover\")\n ) return;\n setPopoverOpen(false);\n });\n\n document.addEventListener(\"keydown\", (event) => {\n if (event.key !== \"Escape\") return;\n setPopoverOpen(false);\n });\n}\n", "// Bootstrap reload + top-level render. Extracted from main.js so feature\n// modules can import `load` / `render` without pulling in the entry-point\n// init wiring (which would create import cycles).\n\nimport { state, syncBoardSelection, currentBoard } from \"./state.js\";\nimport { api, bootstrapPath } from \"./api.js\";\nimport { renderBoard, renderBoardSelection } from \"./kanban.js\";\nimport { renderDetail } from \"./ticket-detail.js\";\nimport { closeMenuFlyouts, updateTopbarChips } from \"./board-menu.js\";\nimport { connectEventStream } from \"./sse.js\";\nimport { seedReadIfNeeded } from \"./unread.js\";\nimport { features } from \"./config.js\";\nimport { renderTopbarFocus } from \"./topbar-notes.js\";\n\nlet sseBoardId = null;\n\nexport async function load() {\n closeMenuFlyouts();\n state.data = await api(bootstrapPath());\n syncBoardSelection();\n // First-time-per-board seed so existing cards don't all flash unread.\n // No-op once the seed flag is set for this board.\n seedReadIfNeeded(state.boardId, state.data?.tickets || []);\n await render();\n if (features.sse && state.boardId !== sseBoardId) {\n sseBoardId = state.boardId;\n connectEventStream();\n }\n}\n\nexport async function render() {\n syncBoardSelection();\n updateTopbarChips();\n renderTopbarFocus(currentBoard());\n renderBoard();\n await renderDetail();\n}\n\nexport async function renderDetailOnly() {\n syncBoardSelection();\n updateTopbarChips();\n renderTopbarFocus(currentBoard());\n renderBoardSelection();\n await renderDetail();\n}\n", "// \"New card\" flyout (top-right panel, separate from the main ticket\n// drawer). Handles open/close transitions, form rendering, and submission.\n\nimport {\n $,\n createFlyout,\n createFlyoutInner,\n createFlyoutBackdrop\n} from \"./dom.js\";\nimport { state, visibleStatesForProject, ticketsForProject } from \"./state.js\";\nimport { escapeHtml } from \"./format.js\";\nimport { api } from \"./api.js\";\nimport { syncUrlFromState } from \"./router.js\";\nimport { handleTextareaIndentationKeydown } from \"./text-editing.js\";\nimport { closeDrawer } from \"./drawer.js\";\nimport { closeMenuFlyouts } from \"./board-menu.js\";\nimport { load } from \"./app.js\";\nimport { closeIconSvg } from \"./icons.js\";\nimport { attachTicketTypeahead, ticketCanonicalLabel } from \"./ticket-typeahead.js\";\n\n/** Clears any pending hide timeout when reopening the create flyout quickly. */\nlet createFlyoutHideTimer = 0;\n\nexport function isCreateFlyoutOpen() {\n return createFlyout?.classList.contains(\"is-open\");\n}\n\n/** Compact top-right panel for creating a card (separate from the main ticket drawer). */\nexport function openCreateFlyout(preselectedLaneId) {\n clearTimeout(createFlyoutHideTimer);\n closeMenuFlyouts();\n closeDrawer();\n createFlyoutInner.innerHTML = renderCreateForm(preselectedLaneId || \"\");\n wireCreateForm();\n $(\"#createFlyoutClose\")?.addEventListener(\"click\", () => closeCreateFlyout());\n createFlyout.hidden = false;\n createFlyoutBackdrop.hidden = false;\n requestAnimationFrame(() => {\n createFlyout.classList.add(\"is-open\");\n createFlyoutBackdrop.classList.add(\"is-visible\");\n });\n requestAnimationFrame(() => {\n $(\"#createTicketTitle\")?.focus();\n });\n}\n\nexport function closeCreateFlyout() {\n clearTimeout(createFlyoutHideTimer);\n createFlyout.classList.remove(\"is-open\");\n createFlyoutBackdrop.classList.remove(\"is-visible\");\n createFlyoutHideTimer = setTimeout(() => {\n createFlyout.hidden = true;\n createFlyoutBackdrop.hidden = true;\n createFlyoutInner.innerHTML = \"\";\n }, 220);\n}\n\n/** HTML for the \u201CNew\u201D flyout: lane + type + priority on one row, then parent and labels. */\nfunction renderCreateForm(preselectedLaneId) {\n const states = visibleStatesForProject();\n const defaultState = states.find((item) => item.is_default) || states[0];\n const effectiveStateId =\n preselectedLaneId && states.some((s) => s.id === preselectedLaneId)\n ? preselectedLaneId\n : defaultState?.id || \"\";\n const stateOptions = states\n .map(\n (item) =>\n `<option value=\"${escapeHtml(item.id)}\" ${item.id === effectiveStateId ? \"selected\" : \"\"}>${escapeHtml(item.name)}</option>`\n )\n .join(\"\");\n return `\n <div class=\"create-flyout-head\">\n <h2>New card</h2>\n <button type=\"button\" class=\"create-flyout-close ghost\" id=\"createFlyoutClose\" aria-label=\"Close\">${closeIconSvg}</button>\n </div>\n <form id=\"createTicketForm\" class=\"create-flyout-form\">\n <input id=\"createTicketTitle\" name=\"title\" type=\"text\" placeholder=\"Title \u2014 what is this card?\" autocomplete=\"off\" required />\n <textarea id=\"createTicketDescription\" name=\"description\" placeholder=\"Description (optional)\"></textarea>\n <div class=\"control-grid\">\n <label class=\"control-field\">\n <span class=\"control-field-label\">LANE</span>\n <select id=\"createTicketState\" name=\"state\" class=\"select-chevron-field\" aria-label=\"Lane\">${stateOptions}</select>\n </label>\n <label class=\"control-field\">\n <span class=\"control-field-label\">TYPE</span>\n <select id=\"createTicketType\" name=\"type\" class=\"select-chevron-field\" aria-label=\"Ticket type\">\n <option value=\"epic\">Epic</option>\n <option value=\"feature\">Feature</option>\n <option value=\"task\" selected>Task</option>\n <option value=\"bug\">Bug</option>\n </select>\n </label>\n <label class=\"control-field\">\n <span class=\"control-field-label\">PRIORITY</span>\n <select id=\"createTicketPriority\" name=\"priority\" class=\"select-chevron-field\" aria-label=\"Priority\">\n <option value=\"4\">URGENT</option>\n <option value=\"3\">HIGH</option>\n <option value=\"2\" selected>MED</option>\n <option value=\"1\">LOW</option>\n <option value=\"0\">MAYBE</option>\n </select>\n </label>\n </div>\n <label class=\"control-field\" id=\"createTicketParentField\">\n <span class=\"control-field-label\">Parent epic</span>\n <input id=\"createTicketParent\" name=\"parent_target\" type=\"text\" placeholder=\"Search epic\u2026 (optional)\" autocomplete=\"off\" aria-label=\"Parent epic\" />\n <input type=\"hidden\" name=\"parent_ticket_id\" id=\"createTicketParentId\" value=\"\" />\n </label>\n <input id=\"createTicketLabels\" name=\"labels\" type=\"text\" placeholder=\"Labels (comma-separated)\" />\n <button type=\"submit\">Create card</button>\n </form>\n `;\n}\n\nfunction wireCreateForm() {\n const form = $(\"#createTicketForm\");\n if (!form) return;\n const description = form.querySelector(\"#createTicketDescription\");\n description?.addEventListener(\"keydown\", (event) => {\n handleTextareaIndentationKeydown(event, description);\n });\n\n // Parent epic is chosen via the shared styled typeahead. The visible field\n // holds the \"#12 \u2014 Title\" label; the resolved epic id lives in a hidden input\n // that the submit reads. Typing (or clearing) drops a stale id so only an\n // explicit pick is submitted.\n const parentInput = form.querySelector(\"#createTicketParent\");\n const parentId = form.querySelector(\"#createTicketParentId\");\n parentInput.addEventListener(\"input\", () => {\n parentId.value = \"\";\n });\n attachTicketTypeahead(\n parentInput,\n () => ticketsForProject().filter((ticket) => ticket.type === \"epic\"),\n {\n onSelect: (ticket) => {\n parentId.value = ticket.id;\n parentInput.value = ticketCanonicalLabel(ticket);\n },\n },\n );\n\n // Epics cannot have a parent (server rejects with `epic_cannot_have_parent`),\n // so hide the Parent epic field whenever Type is Epic.\n const typeSelect = form.querySelector(\"#createTicketType\");\n const parentField = form.querySelector(\"#createTicketParentField\");\n const syncParentVisibility = () => {\n const isEpic = typeSelect.value === \"epic\";\n parentField.hidden = isEpic;\n if (isEpic) {\n parentInput.value = \"\";\n parentId.value = \"\";\n }\n };\n typeSelect.addEventListener(\"change\", syncParentVisibility);\n syncParentVisibility();\n\n form.addEventListener(\"submit\", createTicketFromDrawer);\n}\n\nasync function createTicketFromDrawer(event) {\n event.preventDefault();\n const form = event.currentTarget;\n const data = new FormData(form);\n const labels = String(data.get(\"labels\") || \"\")\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n\n const created = await api(\"/api/tickets\", {\n method: \"POST\",\n body: {\n board_id: state.boardId,\n title: data.get(\"title\"),\n description: data.get(\"description\"),\n type: data.get(\"type\"),\n parent_ticket_id: data.get(\"parent_ticket_id\") || null,\n state_id: data.get(\"state\"),\n priority: Number(data.get(\"priority\")),\n labels\n }\n });\n\n closeCreateFlyout();\n state.selectedTicketId = created.id;\n state.detailMode = \"ticket\";\n await load();\n syncUrlFromState();\n}\n", "// Board picker flyout (the \"Board\" chip in the topbar). Lists every board\n// the actor can see, switches between them, and \u2014 for owners \u2014 exposes the\n// new-board form. Also owns the topbar chip label/title sync.\n\nimport { boardFlyout, boardMenuBtn } from \"./dom.js\";\nimport { state } from \"./state.js\";\nimport { escapeHtml } from \"./format.js\";\nimport { api } from \"./api.js\";\nimport { navigate, syncUrlFromState } from \"./router.js\";\nimport { closeCreateFlyout } from \"./create-card.js\";\nimport { toast } from \"./toast.js\";\nimport { load } from \"./app.js\";\nimport { features } from \"./config.js\";\nimport { exportAllBoards } from \"./board-export.js\";\n\nlet boardFlyoutView = \"list\";\n\nexport function closeBoardFlyout() {\n if (!boardFlyout) return;\n boardFlyout.hidden = true;\n boardFlyout.innerHTML = \"\";\n boardFlyoutView = \"list\";\n boardMenuBtn?.setAttribute(\"aria-expanded\", \"false\");\n}\n\nexport function closeMenuFlyouts() {\n closeBoardFlyout();\n}\n\nconst boardChipIcon = `\n <svg\n class=\"topbar-icon\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <rect x=\"4\" y=\"2\" width=\"6\" height=\"20\" rx=\"0.75\" stroke=\"currentColor\" stroke-width=\"2\" />\n <rect x=\"14\" y=\"2\" width=\"6\" height=\"20\" rx=\"0.75\" stroke=\"currentColor\" stroke-width=\"2\" />\n </svg>`;\n\nexport function updateTopbarChips() {\n if (!state.data) return;\n const board = (state.data.boards || []).find((b) => b.id === state.boardId);\n if (boardMenuBtn) {\n const label = board?.name || \"Board\";\n boardMenuBtn.innerHTML = `${boardChipIcon}<span class=\"topbar-chip-label\">${escapeHtml(label)}</span>`;\n boardMenuBtn.title = board ? `${board.name} \u2014 slug: ${board.slug}` : \"Choose board\";\n }\n}\n\nasync function inflateZipEntry(bytes) {\n if (typeof DecompressionStream === \"undefined\") {\n throw new Error(\"Compressed ZIP entries are not supported in this browser.\");\n }\n const stream = new Blob([bytes]).stream().pipeThrough(new DecompressionStream(\"deflate-raw\"));\n return new Uint8Array(await new Response(stream).arrayBuffer());\n}\n\nfunction parseImportSnapshotText(text, filename = \"snapshot\") {\n const trimmed = String(text || \"\").trimStart();\n if (trimmed.startsWith(\"<\")) throw new Error(`${filename} looks like HTML instead of JSON.`);\n try {\n const snapshot = JSON.parse(text);\n if (!snapshot?.board) throw new Error(\"snapshot_missing_board\");\n return snapshot;\n } catch (error) {\n throw new Error(`${filename}: ${error?.message || \"invalid JSON\"}`);\n }\n}\n\nasync function readZipSnapshots(file) {\n const buffer = await file.arrayBuffer();\n const view = new DataView(buffer);\n const bytes = new Uint8Array(buffer);\n const decoder = new TextDecoder();\n const snapshots = [];\n let offset = 0;\n\n while (offset + 30 <= bytes.length) {\n const signature = view.getUint32(offset, true);\n if (signature === 0x02014b50 || signature === 0x06054b50) break;\n if (signature !== 0x04034b50) throw new Error(\"Invalid ZIP archive.\");\n\n const flags = view.getUint16(offset + 6, true);\n const method = view.getUint16(offset + 8, true);\n const compressedSize = view.getUint32(offset + 18, true);\n const filenameLength = view.getUint16(offset + 26, true);\n const extraLength = view.getUint16(offset + 28, true);\n const nameStart = offset + 30;\n const dataStart = nameStart + filenameLength + extraLength;\n const dataEnd = dataStart + compressedSize;\n if (flags & 0x0008) throw new Error(\"ZIP entries with data descriptors are not supported.\");\n if (dataEnd > bytes.length) throw new Error(\"Invalid ZIP archive.\");\n\n const name = decoder.decode(bytes.slice(nameStart, nameStart + filenameLength));\n if (!name.endsWith(\"/\")) {\n if (!name.toLowerCase().endsWith(\".orbit.json\")) {\n throw new Error(\"ZIP imports may contain only .orbit.json files.\");\n }\n const compressed = bytes.slice(dataStart, dataEnd);\n const data = method === 0 ? compressed : method === 8 ? await inflateZipEntry(compressed) : null;\n if (!data) throw new Error(\"Unsupported ZIP compression method.\");\n snapshots.push(parseImportSnapshotText(decoder.decode(data), name));\n }\n\n offset = dataEnd;\n }\n\n if (!snapshots.length) throw new Error(\"ZIP archive did not contain any .orbit.json snapshots.\");\n return snapshots;\n}\n\nasync function readImportSnapshots(file) {\n const name = String(file?.name || \"\").toLowerCase();\n if (name.endsWith(\".zip\")) return readZipSnapshots(file);\n if (name.endsWith(\".orbit.json\")) return [parseImportSnapshotText(await file.text(), file.name)];\n throw new Error(\"Choose a .zip archive or a single .orbit.json snapshot.\");\n}\n\nfunction renderBoardFlyoutHeader() {\n const showListButton = boardFlyoutView !== \"list\";\n const newLabel = showListButton ? \"List\" : \"New\";\n return `\n <div class=\"menu-flyout-head menu-flyout-head--actions\">\n <span>Board</span>\n <span class=\"menu-flyout-actions\">\n ${features.multiBoard ? `<button type=\"button\" data-variant=\"ghost\" data-board-view=\"${showListButton ? \"list\" : \"new\"}\">${newLabel}</button>` : \"\"}\n <button type=\"button\" data-variant=\"ghost\" data-board-view=\"export\">Export</button>\n </span>\n </div>`;\n}\n\nfunction renderBoardFlyoutInner() {\n const boards = state.data.boards || [];\n const rows = boards\n .map(\n (b) => `\n <button type=\"button\" class=\"menu-flyout-item ${b.id === state.boardId ? \"is-current\" : \"\"}\" data-variant=\"menu-item\" data-pick-board=\"${escapeHtml(b.id)}\" role=\"menuitem\">\n <span class=\"menu-flyout-item-title\">${escapeHtml(b.name)}</span>\n <span class=\"menu-flyout-item-meta\">${escapeHtml(b.slug)}</span>\n </button>`\n )\n .join(\"\");\n const listBody =\n rows ||\n `<p class=\"menu-flyout-hint menu-flyout-hint--empty\">No boards yet. Create one below if you can.</p>`;\n const listBlock = `<div class=\"menu-flyout-list\">${listBody}</div>`;\n const createBlock = `\n <div class=\"menu-flyout-section\">\n <h3 class=\"menu-flyout-heading\">New Board</h3>\n <form id=\"createBoardForm\" class=\"menu-flyout-form\">\n <input name=\"name\" type=\"text\" required placeholder=\"Board name\" autocomplete=\"off\" />\n <div class=\"folder-picker-field\">\n <input id=\"repoPathInput\" name=\"repo_path\" type=\"text\" readonly placeholder=\"Coding project folder (optional)\" autocomplete=\"off\" />\n <button type=\"button\" id=\"pickRepoFolderBtn\">Browse</button>\n </div>\n <div id=\"helperFilesReveal\" hidden>\n <p class=\"menu-flyout-hint menu-flyout-hint--intro\">Orbit writes <code>SKILL-ORBIT.md</code> and <code>AGENTS.md</code> into this folder for your AI coding agent.</p>\n <label class=\"menu-flyout-check\">\n <input id=\"helperFilesCheckbox\" name=\"manage_helper_files\" type=\"checkbox\" checked />\n <span>Generate AI helper files (<code>SKILL-ORBIT.md</code>, <code>AGENTS.md</code>)</span>\n </label>\n </div>\n <input name=\"slug\" type=\"text\" placeholder=\"Slug (optional)\" autocomplete=\"off\" />\n <button type=\"submit\">Create board</button>\n </form>\n </div>`;\n const exportBlock = `\n <div class=\"menu-flyout-section menu-flyout-section--export\">\n <p class=\"menu-flyout-copy\">Export every board as Orbit snapshots in a ZIP archive.</p>\n ${features.attachments ? `\n <label class=\"orbit-check menu-flyout-toggle\">\n <input type=\"checkbox\" id=\"exportAllBoardImages\" />\n <span class=\"orbit-check-box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" class=\"orbit-check-tick\"><path d=\"M3.5 8.5l3 3 6-7\" /></svg>\n </span>\n <span class=\"menu-flyout-toggle-text\">Include attached images</span>\n </label>\n ` : \"\"}\n <div class=\"menu-flyout-actions-row\">\n <button type=\"button\" id=\"exportAllBoards\">Export All</button>\n </div>\n <div class=\"menu-flyout-divider\" aria-hidden=\"true\"></div>\n <section class=\"menu-flyout-danger-section\" aria-label=\"Import All\">\n <h3 class=\"menu-flyout-danger-heading\">Import All</h3>\n <p class=\"menu-flyout-danger-copy\">Imports fully overwrite each matching board. Snapshots without a matching board create new boards.</p>\n <div class=\"menu-flyout-actions-row\">\n <input type=\"file\" id=\"importAllBoardsFile\" class=\"import-file-input\" accept=\".zip,.orbit.json,application/zip\" />\n <button type=\"button\" data-arc=\"danger\" id=\"importAllBoards\">Import All</button>\n </div>\n </section>\n </div>`;\n const body = boardFlyoutView === \"export\" ? exportBlock : boardFlyoutView === \"new\" && features.multiBoard ? createBlock : listBlock;\n return `\n ${renderBoardFlyoutHeader()}\n ${body}\n `;\n}\n\nfunction rerenderBoardFlyout(view) {\n boardFlyoutView = view;\n boardFlyout.innerHTML = renderBoardFlyoutInner();\n wireBoardFlyout();\n if (view === \"new\") boardFlyout.querySelector('input[name=\"name\"]')?.focus();\n}\n\nfunction wireBoardFlyout() {\n boardFlyout.querySelectorAll(\"[data-board-view]\").forEach((button) => {\n button.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n const view = button.getAttribute(\"data-board-view\") || \"list\";\n rerenderBoardFlyout(view);\n });\n });\n\n boardFlyout.querySelectorAll(\"[data-pick-board]\").forEach((btn) => {\n btn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n const id = btn.getAttribute(\"data-pick-board\");\n closeBoardFlyout();\n if (id === state.boardId) return;\n closeCreateFlyout();\n await navigate({\n boardId: id,\n view: \"board\"\n });\n });\n });\n const form = boardFlyout.querySelector(\"#createBoardForm\");\n if (form) {\n const pickRepoFolderBtn = form.querySelector(\"#pickRepoFolderBtn\");\n const repoPathInput = form.querySelector(\"#repoPathInput\");\n const helperFilesReveal = form.querySelector(\"#helperFilesReveal\");\n // The folder explanation and \"Generate AI helper files\" option only make\n // sense once a folder is chosen \u2014 there's nowhere to write them otherwise.\n // Reveal both with the folder value rather than disabling.\n const syncHelperFilesVisibility = () => {\n if (helperFilesReveal) helperFilesReveal.hidden = !repoPathInput.value.trim();\n };\n syncHelperFilesVisibility();\n pickRepoFolderBtn?.addEventListener(\"click\", async (event) => {\n event.preventDefault();\n pickRepoFolderBtn.disabled = true;\n try {\n const result = await api(\"/api/system/pick-folder\", { method: \"POST\" });\n if (result.path) {\n repoPathInput.value = result.path;\n repoPathInput.dispatchEvent(new Event(\"input\", { bubbles: true }));\n syncHelperFilesVisibility();\n }\n } catch (error) {\n toast.error(error?.message || \"Folder picker unavailable\");\n } finally {\n pickRepoFolderBtn.disabled = false;\n }\n });\n form.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const fd = new FormData(form);\n const slug = String(fd.get(\"slug\") || \"\").trim();\n const repoPath = String(fd.get(\"repo_path\") || \"\").trim();\n // Folder is optional. Only forward the helper-files choice when a folder\n // is set; the server ignores it otherwise.\n const created = await api(\"/api/boards\", {\n method: \"POST\",\n body: {\n name: fd.get(\"name\"),\n ...(repoPath ? { repo_path: repoPath, manage_helper_files: fd.get(\"manage_helper_files\") === \"on\" } : {}),\n ...(slug ? { slug } : {})\n }\n });\n closeBoardFlyout();\n state.boardId = created.id;\n state.selectedTicketId = \"\";\n state.detailMode = \"settings\";\n await load();\n syncUrlFromState();\n toast.success(\"Board created\");\n });\n }\n\n boardFlyout.querySelector(\"#exportAllBoards\")?.addEventListener(\"click\", async (event) => {\n const button = event.currentTarget;\n const includeAttachments = Boolean(boardFlyout.querySelector(\"#exportAllBoardImages\")?.checked);\n button.disabled = true;\n const originalText = button.textContent;\n button.textContent = \"Exporting...\";\n try {\n await exportAllBoards({ includeAttachments });\n } catch (error) {\n toast.error(`Export failed: ${error?.message || \"request failed\"}`);\n } finally {\n button.disabled = false;\n button.textContent = originalText;\n }\n });\n\n const importAllBoardsFile = boardFlyout.querySelector(\"#importAllBoardsFile\");\n boardFlyout.querySelector(\"#importAllBoards\")?.addEventListener(\"click\", () => {\n importAllBoardsFile?.click();\n });\n\n importAllBoardsFile?.addEventListener(\"change\", async (event) => {\n const input = event.currentTarget;\n const file = input.files?.[0];\n if (!file) return;\n const importButton = boardFlyout.querySelector(\"#importAllBoards\");\n const originalText = importButton?.textContent;\n if (importButton) {\n importButton.disabled = true;\n importButton.textContent = \"Importing...\";\n }\n try {\n const snapshots = await readImportSnapshots(file);\n const boardsById = new Map((state.data.boards || []).map((board) => [board.id, board]));\n const boardsBySlug = new Map((state.data.boards || []).map((board) => [board.slug, board]));\n let replaced = 0;\n let created = 0;\n\n for (const snapshot of snapshots) {\n const incomingBoard = snapshot.board || {};\n const match = boardsBySlug.get(incomingBoard.slug) || boardsById.get(incomingBoard.id);\n if (match) {\n await api(\"/api/admin/import\", {\n method: \"POST\",\n body: {\n board_id: match.id,\n replace_existing: true,\n snapshot\n }\n });\n replaced += 1;\n continue;\n }\n\n const result = await api(\"/api/admin/import\", {\n method: \"POST\",\n body: {\n ...(state.boardId ? { board_id: state.boardId } : {}),\n create_new: true,\n snapshot\n }\n });\n created += 1;\n if (result.imported_board_id) boardsById.set(result.imported_board_id, { id: result.imported_board_id, slug: result.imported_board_slug });\n if (result.imported_board_slug) boardsBySlug.set(result.imported_board_slug, { id: result.imported_board_id, slug: result.imported_board_slug });\n }\n\n await load();\n toast.success(`Imported ${snapshots.length} board${snapshots.length === 1 ? \"\" : \"s\"} (${replaced} replaced, ${created} created)`);\n closeBoardFlyout();\n await navigate({ boardId: state.boardId, view: \"board\" }, { replace: true });\n } catch (error) {\n toast.error(`Import failed: ${error?.message || \"invalid import file\"}`);\n } finally {\n input.value = \"\";\n if (importButton) {\n importButton.disabled = false;\n importButton.textContent = originalText;\n }\n }\n });\n}\n\nexport function openBoardFlyout() {\n closeCreateFlyout();\n if (boardFlyoutView === \"new\" && !features.multiBoard) boardFlyoutView = \"list\";\n boardFlyout.innerHTML = renderBoardFlyoutInner();\n boardFlyout.hidden = false;\n boardMenuBtn?.setAttribute(\"aria-expanded\", \"true\");\n wireBoardFlyout();\n}\n", "import { SETTINGS_TAB_IDS } from \"./settings-tabs.js\";\n\nconst EMPTY_ROUTE = Object.freeze({ boardSlug: \"\", view: \"board\", ticketId: \"\", tab: \"\" });\n\nfunction emptyRoute() {\n return { ...EMPTY_ROUTE };\n}\n\nfunction normalizeLocation(input = globalThis.location) {\n if (typeof input === \"string\") {\n const url = new URL(input, \"http://orbit.local\");\n return { pathname: url.pathname || \"/\", search: url.search || \"\", hash: url.hash || \"\" };\n }\n return {\n pathname: input?.pathname || \"/\",\n search: input?.search || \"\",\n hash: input?.hash || \"\"\n };\n}\n\nfunction decodeSegment(value) {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nfunction routeSegments(value) {\n return String(value || \"\")\n .replace(/^#/, \"\")\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\")\n .split(\"/\")\n .filter(Boolean);\n}\n\nfunction routeFromSegments(parts) {\n if (!parts.length) return null;\n\n const out = emptyRoute();\n let i = 0;\n\n if (parts[i] === \"b\") {\n if (!parts[i + 1]) return null;\n out.boardSlug = decodeSegment(parts[i + 1]);\n i += 2;\n } else if (parts[i] !== \"t\" && parts[i] !== \"settings\") {\n return null;\n }\n\n if (parts[i] === \"t\" && parts[i + 1]) {\n out.view = \"ticket\";\n out.ticketId = decodeSegment(parts[i + 1]);\n } else if (parts[i] === \"settings\") {\n out.view = \"settings\";\n const tab = parts[i + 1] ? decodeSegment(parts[i + 1]) : \"\";\n if (tab && SETTINGS_TAB_IDS.has(tab)) out.tab = tab;\n }\n\n return out;\n}\n\nexport function parseLegacyHashRoute(hash) {\n const raw = String(hash || \"\");\n if (!raw || raw === \"#\" || raw === \"#/\") return null;\n return routeFromSegments(routeSegments(raw));\n}\n\nexport function parseRoute(input = globalThis.location) {\n const loc = normalizeLocation(input);\n return parseLegacyHashRoute(loc.hash) || emptyRoute();\n}\n\nexport function hasRoute(input = globalThis.location) {\n const loc = normalizeLocation(input);\n return Boolean(parseLegacyHashRoute(loc.hash));\n}\n\nexport function buildRoute({ boardSlug = \"\", view = \"board\", ticketId = \"\", tab = \"\" } = {}) {\n const segs = [];\n if (boardSlug) segs.push(\"b\", encodeURIComponent(boardSlug));\n if (view === \"ticket\" && ticketId) segs.push(\"t\", encodeURIComponent(ticketId));\n else if (view === \"settings\") {\n segs.push(\"settings\");\n if (tab && SETTINGS_TAB_IDS.has(tab)) segs.push(tab);\n }\n return \"#/\" + segs.join(\"/\");\n}\n\nexport function isCanonicalRouteUrl(input = globalThis.location, routeObj = parseRoute(input)) {\n const loc = normalizeLocation(input);\n return loc.hash === buildRoute(routeObj);\n}\n", "// Hash router. Copy/share URLs use board slugs, such as\n// `#/b/<boardSlug>`, `#/b/<boardSlug>/t/<ticketId>`, and\n// `#/b/<boardSlug>/settings/<tab>`. Keeping routing in the hash lets the\n// preview app keep working when mounted under `/app/` or opened as static HTML.\n\nimport { currentBoard, state } from \"./state.js\";\nimport { normalizeSettingsTab } from \"./settings-tabs.js\";\nimport { closeMenuFlyouts } from \"./board-menu.js\";\nimport { closeCreateFlyout } from \"./create-card.js\";\nimport {\n buildRoute,\n hasRoute,\n isCanonicalRouteUrl,\n parseRoute\n} from \"./url-routes.js\";\n\nexport { buildRoute, hasRoute, parseRoute } from \"./url-routes.js\";\n\nfunction boardBySlugOrId(value) {\n if (!value) return null;\n const boards = state.data?.boards || [];\n return boards.find((b) => b.slug === value) || boards.find((b) => b.id === value) || null;\n}\n\nfunction routeBoardSlug(routeObj = {}) {\n if (routeObj.boardSlug) return routeObj.boardSlug;\n if (routeObj.boardId) return boardBySlugOrId(routeObj.boardId)?.slug || routeObj.boardId;\n return currentBoard()?.slug || state.boardSlug || \"\";\n}\n\nfunction normalizeRouteForUrl(routeObj = {}) {\n return {\n ...routeObj,\n boardSlug: routeBoardSlug(routeObj)\n };\n}\n\nfunction routeFromState() {\n let view = \"board\";\n if (state.detailMode === \"ticket\" && state.selectedTicketId) view = \"ticket\";\n else if (state.detailMode === \"settings\") view = \"settings\";\n return {\n boardSlug: currentBoard()?.slug || state.boardSlug,\n view,\n ticketId: state.selectedTicketId,\n tab: view === \"settings\" ? normalizeSettingsTab(state.settingsTab) : \"\"\n };\n}\n\nlet routerReady = false;\n\nexport function setRouterReady(value) {\n routerReady = value;\n}\n\nexport function currentRoute() {\n return parseRoute(location);\n}\n\nexport async function navigate(routeObj, { replace = false } = {}) {\n const route = normalizeRouteForUrl(routeObj);\n const url = buildRoute(route);\n if (isCanonicalRouteUrl(location, route)) {\n if (routerReady) await applyRoute();\n return;\n }\n if (replace) history.replaceState(null, \"\", url);\n else history.pushState(null, \"\", url);\n if (routerReady) await applyRoute();\n}\n\n// Push or replace the URL to match the current `state` without re-rendering.\n// Used after flows that already mutated state and called load()/render()\n// (e.g. ticket/board creation).\nexport function syncUrlFromState({ replace = false } = {}) {\n const route = routeFromState();\n const url = buildRoute(route);\n if (isCanonicalRouteUrl(location, route)) return;\n if (replace) history.replaceState(null, \"\", url);\n else history.pushState(null, \"\", url);\n}\n\nexport async function applyRoute() {\n const { load, renderDetailOnly } = await import(\"./app.js\");\n const r = currentRoute();\n const urlHadRoute = hasRoute(location);\n const prevBoardId = state.boardId;\n const routeBoard = boardBySlugOrId(r.boardSlug);\n const fallbackBoard = routeBoard || (r.boardSlug ? currentBoard() : null);\n\n if (fallbackBoard) {\n state.boardId = fallbackBoard.id;\n state.boardSlug = fallbackBoard.slug;\n } else if (r.boardSlug) {\n state.boardSlug = r.boardSlug;\n }\n\n const canonicalRoute = fallbackBoard ? { ...r, boardSlug: fallbackBoard.slug } : r;\n if (urlHadRoute && !isCanonicalRouteUrl(location, canonicalRoute)) {\n history.replaceState(null, \"\", buildRoute(canonicalRoute));\n }\n\n if (r.view === \"ticket\") {\n state.selectedTicketId = r.ticketId || \"\";\n state.detailMode = r.ticketId ? \"ticket\" : \"empty\";\n } else if (r.view === \"settings\") {\n state.selectedTicketId = \"\";\n state.detailMode = \"settings\";\n if (r.tab) {\n state.settingsTab = r.tab;\n try {\n localStorage.setItem(\"mab_settings_tab\", r.tab);\n } catch {\n /* ignore */\n }\n }\n } else {\n state.selectedTicketId = \"\";\n state.detailMode = \"empty\";\n }\n\n closeMenuFlyouts();\n closeCreateFlyout();\n\n if (state.boardId && state.boardId !== prevBoardId) {\n await load();\n return;\n }\n await renderDetailOnly();\n}\n\nwindow.addEventListener(\"popstate\", () => {\n if (routerReady) void applyRoute();\n});\n", "// Animated starfield background, signature stars, meteors, and the theme\n// toggle (which drives the starscape's dark/light state). Self-initializing:\n// importing this module starts the canvas, schedules the first meteor, and\n// wires the theme toggle button.\n//\n// Background stars are drawn on a 2D canvas so each star has its own twinkle\n// period, phase, and warmth \u2014 scintillation that reads as per-star rather\n// than whole-layer. Layers parallax to the cursor by depth. The Milky Way,\n// nebula ghosts, signature stars with spikes, and meteors stay in CSS.\n\nimport { themeToggle, themeIcon } from \"./dom.js\";\nimport { applyReducedMotionPreference, effectiveReducedMotionPreference } from \"./motion-preference.js\";\nimport {\n THEME_CHANGE_EVENT,\n applyStoredThemePreference,\n currentTheme,\n storedThemePreference,\n setThemePreference,\n toggleThemePreference\n} from \"./theme-preference.js\";\n\n// Stored theme must be applied before startStarscape() so its first sync()\n// sees the real theme; otherwise the canvas stays stopped until next resize.\n{\n applyStoredThemePreference();\n applyReducedMotionPreference();\n}\n\nconst starscape = startStarscape();\nscheduleMeteor();\n\n// Sticky top bar gets a tinted glass panel once the page scrolls, so its\n// controls don't blend into whatever content is slipping behind them.\n{\n const updateScrolled = () => {\n document.body.classList.toggle(\"is-scrolled\", window.scrollY > 4);\n };\n window.addEventListener(\"scroll\", updateScrolled, { passive: true });\n updateScrolled();\n}\n\nsyncThemeIcon();\nthemeToggle?.addEventListener(\"click\", () => {\n toggleThemePreference();\n});\n\n// When there's no explicit user preference stored, track OS changes live so\n// data-theme stays in sync and CSS selectors ([data-theme=\"dark\"]) keep working.\nwindow.matchMedia(\"(prefers-color-scheme: dark)\").addEventListener(\"change\", (e) => {\n if (!storedThemePreference()) {\n setThemePreference(e.matches ? \"dark\" : \"light\", { notify: true });\n }\n});\n\nwindow.addEventListener(THEME_CHANGE_EVENT, () => {\n syncThemeIcon();\n starscape.sync();\n});\n\nfunction syncThemeIcon() {\n if (!themeIcon) return;\n const dark = currentTheme() === \"dark\";\n themeIcon.innerHTML = dark\n ? '<path d=\"M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z\" />'\n : '<circle cx=\"12\" cy=\"12\" r=\"5\" /><path d=\"M12 1v2m0 18v2M4.2 4.2l1.4 1.4m12.8 12.8l1.4 1.4M1 12h2m18 0h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4\" />';\n}\n\nfunction startStarscape() {\n const grain = document.querySelector(\".grain\");\n if (!grain) return { sync: () => {} };\n\n buildSignatureStars(grain);\n\n const canvas = document.createElement(\"canvas\");\n canvas.className = \"starfield-canvas\";\n canvas.setAttribute(\"aria-hidden\", \"true\");\n const milkyWay = grain.querySelector(\".milky-way\");\n if (milkyWay && milkyWay.nextSibling) {\n grain.insertBefore(canvas, milkyWay.nextSibling);\n } else if (milkyWay) {\n grain.appendChild(canvas);\n } else {\n grain.insertBefore(canvas, grain.firstChild);\n }\n\n const ctx = canvas.getContext(\"2d\");\n const DPR = Math.min(window.devicePixelRatio || 1, 2);\n let width = 0;\n let height = 0;\n let stars = [];\n let rafId = 0;\n let running = false;\n\n // Eased mouse position, normalized to [-0.5, 0.5]. Lerp gives inertia.\n const mouse = { x: 0, y: 0, tx: 0, ty: 0 };\n\n function resize() {\n width = window.innerWidth;\n height = window.innerHeight;\n canvas.width = Math.round(width * DPR);\n canvas.height = Math.round(height * DPR);\n canvas.style.width = width + \"px\";\n canvas.style.height = height + \"px\";\n ctx.setTransform(DPR, 0, 0, DPR, 0, 0);\n buildStars();\n }\n\n function buildStars() {\n // Star count scales with viewport area so wide screens don't read empty.\n const density = (width * height) / (1440 * 900);\n const layers = [\n { count: Math.round(320 * density), depth: 0.12, sizes: [[1, 0.9], [1.4, 0.1]], glow: 0 },\n { count: Math.round(160 * density), depth: 0.30, sizes: [[1, 0.5], [1.6, 0.4], [2.4, 0.1]], glow: 1.8 },\n { count: Math.round(44 * density), depth: 0.58, sizes: [[1.8, 0.5], [2.6, 0.38], [3.6, 0.12]], glow: 2.4 }\n ];\n const rng = mulberry32(0xc0ffee);\n stars = [];\n for (const layer of layers) {\n for (let i = 0; i < layer.count; i++) {\n const size = pickWeighted(rng(), layer.sizes);\n stars.push({\n x: rng() * width,\n y: rng() * height,\n size,\n depth: layer.depth,\n glow: size >= 2 ? layer.glow : 0,\n rgb: pickStarColor(rng()),\n period: 2.2 + rng() * 5.4,\n phase: rng() * Math.PI * 2,\n amp: 0.25 + rng() * 0.5,\n baseAlpha: size < 1.5 ? 0.45 + rng() * 0.28 : 0.55 + rng() * 0.22\n });\n }\n }\n }\n\n function pickStarColor(r) {\n if (r < 0.80) return [255, 255, 255];\n if (r < 0.93) return [255, 222, 186];\n return [195, 218, 255];\n }\n\n function onPointerMove(e) {\n if (!width || !height) return;\n mouse.tx = e.clientX / width - 0.5;\n mouse.ty = e.clientY / height - 0.5;\n }\n\n function frame(t) {\n mouse.x += (mouse.tx - mouse.x) * 0.06;\n mouse.y += (mouse.ty - mouse.y) * 0.06;\n\n ctx.clearRect(0, 0, width, height);\n ctx.globalCompositeOperation = \"lighter\";\n\n const time = t / 1000;\n const parallaxPx = 70;\n\n for (let i = 0; i < stars.length; i++) {\n const s = stars[i];\n const pulse = 0.5 + 0.5 * Math.sin(time * ((2 * Math.PI) / s.period) + s.phase);\n const alpha = s.baseAlpha * (1 - s.amp + s.amp * pulse);\n const px = s.x - mouse.x * s.depth * parallaxPx;\n const py = s.y - mouse.y * s.depth * parallaxPx;\n const [r, g, b] = s.rgb;\n\n if (s.glow > 0) {\n // Glowed stars: soft halo + circular core (arc, not rect) so the\n // bright center doesn't read as a square at larger zoom levels.\n const radius = s.size * s.glow;\n const grad = ctx.createRadialGradient(px, py, 0, px, py, radius);\n grad.addColorStop(0, `rgba(${r},${g},${b},${alpha * 0.85})`);\n grad.addColorStop(0.35, `rgba(${r},${g},${b},${alpha * 0.3})`);\n grad.addColorStop(1, `rgba(${r},${g},${b},0)`);\n ctx.fillStyle = grad;\n ctx.beginPath();\n ctx.arc(px, py, radius, 0, Math.PI * 2);\n ctx.fill();\n\n ctx.fillStyle = `rgba(${r},${g},${b},${alpha})`;\n ctx.beginPath();\n ctx.arc(px, py, s.size / 2, 0, Math.PI * 2);\n ctx.fill();\n } else {\n // Sub-pixel dim stars: fillRect is fine \u2014 they're one device pixel.\n const half = s.size / 2;\n ctx.fillStyle = `rgba(${r},${g},${b},${alpha})`;\n ctx.fillRect(px - half, py - half, s.size, s.size);\n }\n }\n\n ctx.globalCompositeOperation = \"source-over\";\n if (running) rafId = requestAnimationFrame(frame);\n }\n\n function drawStaticFrame() {\n ctx.clearRect(0, 0, width, height);\n ctx.globalCompositeOperation = \"lighter\";\n for (const s of stars) {\n const [r, g, b] = s.rgb;\n ctx.fillStyle = `rgba(${r},${g},${b},${s.baseAlpha})`;\n if (s.glow > 0) {\n ctx.beginPath();\n ctx.arc(s.x, s.y, s.size / 2, 0, Math.PI * 2);\n ctx.fill();\n } else {\n const half = s.size / 2;\n ctx.fillRect(s.x - half, s.y - half, s.size, s.size);\n }\n }\n ctx.globalCompositeOperation = \"source-over\";\n }\n\n function start() {\n if (running) return;\n running = true;\n rafId = requestAnimationFrame(frame);\n }\n\n function stop() {\n running = false;\n cancelAnimationFrame(rafId);\n }\n\n function sync() {\n const isDark = currentTheme() === \"dark\";\n const reduced = effectiveReducedMotionPreference();\n if (!isDark) {\n stop();\n ctx.clearRect(0, 0, width, height);\n return;\n }\n if (!stars.length) resize();\n if (reduced || document.hidden) {\n stop();\n drawStaticFrame();\n } else {\n start();\n }\n }\n\n window.addEventListener(\"resize\", () => {\n resize();\n sync();\n }, { passive: true });\n window.addEventListener(\"pointermove\", onPointerMove, { passive: true });\n document.addEventListener(\"visibilitychange\", sync);\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").addEventListener(\"change\", () => {\n applyReducedMotionPreference();\n sync();\n });\n window.addEventListener(\"orbit:motion-preference-change\", sync);\n\n resize();\n sync();\n return { sync };\n}\n\nfunction buildSignatureStars(grain) {\n grain.querySelectorAll(\".signature-star\").forEach((el) => el.remove());\n const rng = mulberry32(0x5ca1e5);\n const SIG_COUNT = 7;\n for (let i = 0; i < SIG_COUNT; i++) {\n const star = document.createElement(\"div\");\n star.className = \"signature-star\";\n star.setAttribute(\"aria-hidden\", \"true\");\n star.style.left = (6 + rng() * 88).toFixed(2) + \"%\";\n star.style.top = (8 + rng() * 78).toFixed(2) + \"%\";\n star.style.animationDelay = (-rng() * 4.8).toFixed(2) + \"s\";\n grain.appendChild(star);\n }\n}\n\n/* Shooting stars \u2014 rare streaks that cross the sky. CSS handles the trail\n and fade; JS picks the trajectory and reschedules the next one. */\nfunction scheduleMeteor() {\n const delay = 14000 + Math.random() * 28000;\n setTimeout(spawnMeteor, delay);\n}\n\nfunction spawnMeteor() {\n const isDark = currentTheme() === \"dark\";\n const reduced = effectiveReducedMotionPreference();\n const grain = document.querySelector(\".grain\");\n if (!isDark || reduced || document.hidden || !grain) {\n scheduleMeteor();\n return;\n }\n\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const startX = Math.random() * vw * 0.6;\n const startY = Math.random() * vh * 0.55;\n const distance = 380 + Math.random() * 520;\n const angleDeg = 18 + Math.random() * 26;\n const rad = (angleDeg * Math.PI) / 180;\n const endX = startX + Math.cos(rad) * distance;\n const endY = startY + Math.sin(rad) * distance;\n\n const m = document.createElement(\"div\");\n m.className = \"meteor\";\n m.setAttribute(\"aria-hidden\", \"true\");\n m.style.setProperty(\"--from-x\", startX + \"px\");\n m.style.setProperty(\"--from-y\", startY + \"px\");\n m.style.setProperty(\"--to-x\", endX + \"px\");\n m.style.setProperty(\"--to-y\", endY + \"px\");\n m.style.setProperty(\"--angle\", angleDeg + \"deg\");\n grain.appendChild(m);\n m.addEventListener(\"animationend\", () => m.remove(), { once: true });\n\n scheduleMeteor();\n}\n\nfunction pickWeighted(r, table) {\n let acc = 0;\n for (const [value, weight] of table) {\n acc += weight;\n if (r < acc) return value;\n }\n return table[table.length - 1][0];\n}\n\nfunction mulberry32(seed) {\n let a = seed >>> 0;\n return function () {\n a = (a + 0x6d2b79f5) >>> 0;\n let t = a;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n", "// Application entry point. Imports `starscape.js` for its side effects\n// (canvas + theme toggle init), wires the topbar buttons and global\n// keyboard/click listeners, and kicks off the bootstrap \u2192 router activation\n// sequence. The reusable `load` / `render` helpers live in app.js so feature\n// modules can import them without creating cycles back through this entry.\n\nimport \"./starscape.js\";\n\nimport {\n $,\n boardMenuBtn,\n boardFlyout,\n drawer,\n drawerBackdrop,\n createFlyoutBackdrop,\n searchInput\n} from \"./dom.js\";\nimport { state } from \"./state.js\";\nimport { api, withBoardQuery } from \"./api.js\";\nimport { toast, debounce } from \"./toast.js\";\nimport {\n navigate,\n applyRoute,\n currentRoute,\n hasRoute,\n syncUrlFromState,\n setRouterReady\n} from \"./router.js\";\nimport {\n openBoardFlyout,\n closeBoardFlyout,\n closeMenuFlyouts\n} from \"./board-menu.js\";\nimport {\n openCreateFlyout,\n closeCreateFlyout,\n isCreateFlyoutOpen\n} from \"./create-card.js\";\nimport { enableKanbanDragScroll, enableKanbanInteractions } from \"./kanban.js\";\nimport { runSearch, hideSearch } from \"./search.js\";\nimport { load } from \"./app.js\";\nimport { edition } from \"./config.js\";\nimport { openModal, wireModal } from \"./modal.js\";\nimport { wireTopbarFocus } from \"./topbar-notes.js\";\nimport { wireHelpMenu } from \"./help-menu.js\";\nimport { checkForUpdate } from \"./update-check.js\";\nimport { applyStoredFontPreferences } from \"./font-preference.js\";\n\nasync function init() {\n const welcomeDialog = document.getElementById(\"welcomeDialog\");\n applyStoredFontPreferences();\n wireModal(welcomeDialog);\n wireTopbarFocus();\n wireHelpMenu();\n if (edition === \"preview\") {\n openModal(welcomeDialog);\n }\n\n $(\"#settingsBtn\").addEventListener(\"click\", async () => {\n closeCreateFlyout();\n closeMenuFlyouts();\n navigate({\n boardId: state.boardId,\n view: \"settings\",\n tab: state.settingsTab || \"lanes\"\n });\n });\n\n boardMenuBtn?.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n if (!boardFlyout.hidden) {\n closeBoardFlyout();\n return;\n }\n openBoardFlyout();\n });\n\n $(\"#newTicketBtn\").addEventListener(\"click\", () => {\n if (isCreateFlyoutOpen()) {\n closeCreateFlyout();\n return;\n }\n openCreateFlyout(\"\");\n });\n\n createFlyoutBackdrop.addEventListener(\"click\", () => {\n closeCreateFlyout();\n });\n\n $(\"#drawerCloseBtn\").addEventListener(\"click\", () => {\n navigate({\n boardId: state.boardId,\n view: \"board\"\n });\n });\n\n $(\"#drawerArchiveBtn\").addEventListener(\"click\", async () => {\n const ticketId = state.selectedTicketId;\n if (!ticketId || state.detailMode !== \"ticket\") return;\n const ticket = state.data?.tickets?.find((t) => t.id === ticketId);\n const titleForToast = ticket?.title || \"card\";\n await api(withBoardQuery(`/api/tickets/${encodeURIComponent(ticketId)}/archive`), { method: \"POST\" });\n toast.removed(`Archived: ${titleForToast}`);\n await load();\n navigate({ boardId: state.boardId, view: \"board\" });\n });\n\n drawerBackdrop.addEventListener(\"click\", () => {\n navigate({\n boardId: state.boardId,\n view: \"board\"\n });\n });\n\n document.addEventListener(\"keydown\", (event) => {\n if (event.key !== \"Escape\") return;\n if (!boardFlyout.hidden) {\n closeMenuFlyouts();\n return;\n }\n if (isCreateFlyoutOpen()) {\n closeCreateFlyout();\n return;\n }\n if (!drawer.classList.contains(\"is-open\")) return;\n const el = document.activeElement;\n if (el?.classList?.contains(\"inline-title-editor\") || el?.classList?.contains(\"inline-desc-editor\")) return;\n navigate({\n boardId: state.boardId,\n view: \"board\"\n });\n });\n\n searchInput.addEventListener(\"input\", debounce(runSearch, 220));\n document.addEventListener(\"click\", (event) => {\n if (!event.target.closest(\"#topbarSearch\")) hideSearch();\n if (!event.target.closest(\".topbar-menu\")) closeMenuFlyouts();\n });\n\n enableKanbanDragScroll();\n enableKanbanInteractions();\n\n const initialRoute = currentRoute();\n if (initialRoute.boardSlug) state.boardSlug = initialRoute.boardSlug;\n await load();\n\n // Activate the router. If the page was loaded with a hash route, restore\n // that view; otherwise canonicalize the URL to reflect the current\n // state so the back button has a starting point.\n setRouterReady(true);\n if (hasRoute()) {\n await applyRoute();\n } else {\n syncUrlFromState({ replace: true });\n }\n\n // Best-effort, non-blocking: nudge if a newer Orbit is available.\n checkForUpdate();\n}\n\ninit();\n", "// Topbar search. Debounced via the input handler in main.js; queries the\n// /api/search endpoint and renders a small results dropdown that navigates\n// to the chosen ticket on click.\n\nimport { searchInput, searchResults } from \"./dom.js\";\nimport { state, currentBoard } from \"./state.js\";\nimport { api } from \"./api.js\";\nimport { navigate } from \"./router.js\";\nimport { escapeHtml, stateClassFor, ticketLabel } from \"./format.js\";\nimport { closeCreateFlyout } from \"./create-card.js\";\n\nexport async function runSearch() {\n const query = searchInput.value.trim();\n if (query.length < 2) {\n hideSearch();\n return;\n }\n const board = currentBoard();\n if (!board) return;\n const result = await api(`/api/search?q=${encodeURIComponent(query)}&board=${encodeURIComponent(board.slug)}`);\n if (result.results.length === 0) {\n searchResults.hidden = false;\n searchResults.innerHTML = `<div class=\"search-hit\">No results</div>`;\n return;\n }\n searchResults.hidden = false;\n searchResults.innerHTML = result.results\n .map(\n (ticket) => `\n <div class=\"search-hit\" data-ticket-id=\"${ticket.id}\">\n <span class=\"search-hit-main\">\n <strong>${escapeHtml(ticketLabel(ticket))}</strong>\n <span class=\"search-hit-title\">${escapeHtml(ticket.title)}</span>\n </span>\n <span class=\"search-hit-state\" data-variant=\"${escapeHtml(stateClassFor(ticket))}\">${escapeHtml(ticket.state_name || \"State\")}</span>\n </div>\n `\n )\n .join(\"\");\n searchResults.querySelectorAll(\"[data-ticket-id]\").forEach((hit) => {\n hit.addEventListener(\"click\", async () => {\n closeCreateFlyout();\n hideSearch();\n navigate({\n boardId: state.boardId,\n view: \"ticket\",\n ticketId: hit.dataset.ticketId\n });\n });\n });\n}\n\nexport function hideSearch() {\n searchResults.hidden = true;\n searchResults.innerHTML = \"\";\n}\n", "// Generic <dialog> modal utility.\n//\n// Usage:\n// wireModal(el) \u2014 wire backdrop-click + [data-modal-close] buttons.\n// openModal(el) \u2014 show the dialog as a modal (focus-trapped overlay).\n// closeModal(el) \u2014 close it programmatically.\n//\n// Escape key is handled natively by the browser; no extra wiring needed.\n\nexport function openModal(dialogEl) {\n if (!dialogEl) return;\n dialogEl.showModal();\n dialogEl.querySelector(\"[data-modal-initial-focus]\")?.focus({ preventScroll: true });\n}\n\nexport function closeModal(dialogEl) {\n if (dialogEl?.open) dialogEl.close();\n}\n\nexport function wireModal(dialogEl) {\n if (!dialogEl) return;\n\n // Close when the user clicks the backdrop (the dialog element itself,\n // outside its inner content box).\n dialogEl.addEventListener(\"click\", (event) => {\n if (event.target === dialogEl) closeModal(dialogEl);\n });\n\n // Close buttons: any element inside the dialog with [data-modal-close].\n dialogEl.querySelectorAll(\"[data-modal-close]\").forEach((btn) => {\n btn.addEventListener(\"click\", () => closeModal(dialogEl));\n });\n}\n", "// Help & About dialog. The topbar \"Help\" button opens a centered\n// .orbit-dialog (same shell as the welcome dialog) describing what Orbit is,\n// how to get started, and where the docs live. modal.js owns the\n// Escape/backdrop/close-button behavior; this module only wires the open\n// trigger and best-effort fills the version pill from the build's version.json.\n\nimport { openModal, wireModal } from \"./modal.js\";\n\nasync function fillVersion(pill) {\n if (!pill) return;\n try {\n const res = await fetch(\"./version.json\", { cache: \"no-store\" });\n if (!res.ok) return;\n const info = await res.json();\n if (info?.version) pill.textContent = `v${info.version}`;\n } catch {\n // Dev edition serves raw modules without version.json \u2014 leave the\n // static \"Orbit\" label in place.\n }\n}\n\nexport function wireHelpMenu() {\n const dialog = document.getElementById(\"helpDialog\");\n const helpBtn = document.getElementById(\"helpBtn\");\n if (!dialog || !helpBtn) return;\n\n wireModal(dialog);\n fillVersion(document.getElementById(\"helpDialogVersion\"));\n\n helpBtn.addEventListener(\"click\", () => openModal(dialog));\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["$", "boardMenuBtn", "boardFlyout", "kanban", "drawer", "drawerInner", "drawerBackdrop", "createFlyout", "createFlyoutInner", "createFlyoutBackdrop", "searchInput", "searchResults", "themeToggle", "themeIcon", "init_dom", "__esmMin", "selector", "safeStorage", "storage", "defaultMediaMatcher", "query", "storedReducedMotionPreference", "value", "REDUCE_MOTION_STORAGE_KEY", "browserPrefersReducedMotion", "mediaMatcher", "effectiveReducedMotionPreference", "setReducedMotionPreference", "reduce", "store", "applyReducedMotionPreference", "doc", "root", "stored", "init_motion_preference", "__esmMin", "safeStorage", "storage", "safeDocument", "doc", "safeEventTarget", "eventTarget", "normalizeTheme", "theme", "THEMES", "storedThemePreference", "value", "THEME_STORAGE_KEY", "systemTheme", "currentTheme", "rootTheme", "applyStoredThemePreference", "setThemePreference", "notify", "next", "dispatchThemeChange", "toggleThemePreference", "options", "target", "THEME_CHANGE_EVENT", "init_theme_preference", "__esmMin", "normalizeSettingsTab", "raw", "SETTINGS_TAB_IDS", "init_settings_tabs", "__esmMin", "state_exports", "__export", "boardLabelCatalog", "currentBoard", "getSettingsTab", "isAiReadyState", "selectableStatesForProject", "state", "statesForProject", "syncBoardSelection", "ticketsForProject", "upsertTicket", "visibleStatesForProject", "normalizeSettingsTab", "boards", "board", "b", "activeBoardId", "label", "item", "states", "currentStateId", "compactTicketForBoard", "ticket", "refreshBoardTicketDerivatives", "boardId", "boardTickets", "ticketById", "childCountByParent", "updatedTicket", "index", "previous", "merged", "a", "init_state", "__esmMin", "init_settings_tabs", "escapeHtml", "value", "fixMojibake", "text", "out", "from", "to", "MOJIBAKE_REPLACEMENTS", "cleanText", "renderPreservedText", "sanitizeMarkdownUrl", "href", "compact", "scheme", "SAFE_LINK_PROTOCOLS", "renderEmphasis", "html", "renderLinksAndEmphasis", "linkPattern", "lastIndex", "match", "labelHtml", "renderInlineMarkdown", "source", "cursor", "codeStart", "codeEnd", "renderParagraph", "lines", "renderTaskItem", "rawContent", "checked", "body", "renderMarkdown", "blocks", "paragraph", "list", "blockquote", "flushParagraph", "flushList", "classAttr", "item", "flushBlockquote", "flushAll", "i", "line", "codeLines", "header", "level", "quoteMatch", "ordered", "unordered", "type", "content", "task", "formatDate", "formatDateDetail", "ticketLabel", "ticket", "stateClassFor", "ticketOrState", "canonicalTicketType", "typeLabel", "typeLabelLong", "priorityLabel", "priority", "priorityKeyFor", "keys", "n", "renderLabels", "labels", "label", "init_format", "__esmMin", "closeIconSvg", "trashIconSvg", "init_icons", "__esmMin", "ensureToastContainer", "toastContainer", "toast", "message", "type", "duration", "options", "container", "node", "icon", "toastIcons", "escapeHtml", "closeIconSvg", "event", "dismissToast", "timer", "t2", "downloadJson", "filename", "value", "blob", "url", "anchor", "debounce", "fn", "wait", "args", "init_toast", "__esmMin", "init_format", "init_icons", "trashIconSvg", "msg", "dur", "request", "method", "path", "body", "headers", "finalHeaders", "response", "text", "payload", "error", "init_transport", "__esmMin", "api_exports", "__export", "api", "bootstrapPath", "withBoardQuery", "state", "path", "sep", "options", "request", "err", "toast", "init_api", "__esmMin", "init_state", "init_toast", "init_transport", "clampIndex", "value", "index", "n", "lineStartFor", "selectedLineRange", "selectionStart", "selectionEnd", "lineStart", "effectiveEnd", "nextBreak", "lineStartsForBlock", "block", "starts", "cursor", "line", "leadingOutdentWidth", "adjustmentBeforePosition", "position", "lineStarts", "widths", "total", "i", "applyTextareaIndentation", "shiftKey", "indent", "source", "start", "end", "first", "last", "indentText", "nextValue", "nextCaret", "lineEnd", "lines", "nextBlock", "selectionStartDelta", "selectionEndDelta", "handleTextareaIndentationKeydown", "event", "textarea", "next", "init_text_editing", "__esmMin", "syncDrawerTabsScrollState", "tabsEl", "shellEl", "maxScroll", "scrollActiveDrawerTabIntoView", "teardownDrawerTabsScroll", "drawerTabsScrollAbort", "bindDrawerTabsScroll", "controller", "signal", "onScrollChange", "observer", "LINE_SCROLL_PX", "wheelPixels", "value", "mode", "event", "horizontalDelta", "DRAG_THRESHOLD", "dragActive", "dragged", "startX", "startScroll", "pointerId", "delta", "endDrag", "openDrawer", "drawerToken", "drawer", "drawerBackdrop", "closeDrawer", "finishToken", "wasOpen", "finish", "drawerInner", "titleBlockEl", "tabsShellEl", "ended", "end", "renderDrawerShell", "eyebrow", "title", "titleAttrs", "subtitleHtml", "tabs", "activeTab", "onTabSelect", "body", "titleAttrHtml", "key", "escapeHtml", "segments", "t", "btn", "archiveBtn", "state", "init_drawer", "__esmMin", "init_dom", "init_state", "init_format", "buildCardActionMenu", "ticket", "lanes", "visibleStatesForProject", "lane", "PRIORITIES", "priority", "priorityLabel", "CARD_TYPES", "type", "typeLabel", "canonicalTicketType", "calculateMenuPosition", "x", "y", "menuWidth", "menuHeight", "viewportWidth", "viewportHeight", "margin", "MENU_MARGIN", "maxLeft", "maxTop", "preferredLeft", "preferredTop", "calculateSubmenuPosition", "triggerRect", "submenuWidth", "submenuHeight", "gap", "SUBMENU_GAP", "rightLeft", "leftLeft", "fitsRight", "fitsLeft", "maxHeight", "boundedHeight", "createCardActionHandlers", "apiClient", "api", "navigator", "confirmer", "patchTicket", "body", "withBoardQuery", "state", "stateId", "toast", "setCardActionDragInFlight", "value", "dragInFlight", "closeCardActionMenu", "restoreFocus", "cancelPendingClose", "dismissController", "submenu", "openSubmenus", "openMenu", "item", "submenuByItem", "lastFocusedElement", "openCardActionMenu", "anchor", "handlers", "onBeforeOpen", "menu", "renderMenuItems", "itemBySubmenu", "wireSubmenu", "rect", "position", "wireMenu", "firstEnabledItem", "signal", "dismissOnOutsidePointer", "dismissOnEscape", "dismissOnScroll", "bindCardContextMenuDelegated", "container", "resolveTicket", "event", "card", "items", "renderMenuItem", "hasChildren", "classes", "check", "suffix", "escapeHtml", "openSubmenu", "scheduleCloseOtherSubmenus", "closeOpenSubmenus", "handleItemClick", "handleMenuKeydown", "rootMenu", "button", "parent", "action", "currentMenu", "parentItem", "parentButton", "closeSubmenu", "moveFocus", "enabled", "enabledItems", "isEventInsideAnyMenu", "target", "siblings", "sibling", "positionSubmenu", "scope", "pendingCloseTimer", "HOVER_CLOSE_DELAY", "trigger", "availableHeight", "submenuRect", "list", "current", "step", "index", "nextIndex", "init_card_actions", "__esmMin", "init_api", "init_state", "init_format", "init_toast", "normalize", "raw", "getMap", "boardId", "m", "cache", "READ_KEY", "obj", "k", "v", "persist", "entryFor", "ticketId", "e", "unreadCount", "ticket", "state", "SEEDED_KEY", "markRead", "timestamp", "bumpUnread", "clearUnread", "seedReadIfNeeded", "tickets", "t", "init_unread", "__esmMin", "init_state", "renderBoard", "states", "visibleStatesForProject", "tickets", "ticketsForProject", "boardTicketsById", "ticket", "kanban", "column", "renderColumn", "toggleCardExpansion", "card", "id", "willExpand", "state", "meta", "renderCardExpandable", "toggleBtn", "enableKanbanInteractions", "cardActionHandlers", "createCardActionHandlers", "navigate", "dragOverColumn", "setDragOverColumn", "event", "closeCardActionMenu", "setCardActionDragInFlight", "suppressClickAfterDrag", "ticketId", "closeCreateFlyout", "api", "withBoardQuery", "load", "target", "addBtn", "openCreateFlyout", "toggle", "epicHeader", "bindCardContextMenuDelegated", "renderBoardSelection", "renderEmptyState", "columnName", "name", "flair", "escapeHtml", "columnTickets", "isEmpty", "isAiReady", "columnClasses", "accentAttr", "renderColumnBody", "allTickets", "epicById", "t", "canonicalTicketType", "epicIdsInColumn", "childrenByEpicId", "list", "rendered", "blocks", "children", "childrenHtml", "c", "renderCard", "epic", "siblings", "renderEpicMiniHeader", "renderTypeIcon", "ticketLabel", "renderPriorityPill", "priority", "key", "priorityKeyFor", "label", "priorityLabel", "type", "canonical", "icon", "color", "asEpicChild", "canonicalType", "priorityKey", "typeText", "typeLabel", "isExpanded", "hasExpandable", "triggerInner", "unreadN", "unreadCount", "unreadDot", "renderMarkdown", "renderLabels", "enableKanbanDragScroll", "PAGE_SCROLL_PX", "active", "dragged", "startX", "startScroll", "pointerId", "shouldIgnore", "wheelPixels", "value", "mode", "horizontalDelta", "delta", "endDrag", "bothBtnPanning", "bothBtnLastX", "suppressContextMenu", "touchPanning", "touchPanLastX", "twoFingerCentroidX", "touches", "x", "endTouchPan", "init_kanban", "__esmMin", "init_dom", "init_state", "init_format", "init_api", "init_router", "init_create_card", "init_app", "init_card_actions", "init_unread", "resolvedEdition", "edition", "features", "init_config", "__esmMin", "hasOwn", "object", "key", "clampUserScale", "value", "number", "normalizeFontPreferences", "input", "normalized", "DEFAULT_FONT_PREFERENCES", "explicitTargets", "FONT_TARGETS", "FONT_OPTIONS", "legacyKey", "target", "LEGACY_FONT_TARGET_ALIASES", "DEFAULT_SITE_FONT", "storedFontPreferences", "storage", "raw", "FONT_STORAGE_KEY", "fontStackFor", "optionId", "applyFontPreferences", "preferences", "doc", "root", "config", "m", "setFontPreferences", "eventTarget", "FONT_CHANGE_EVENT", "setFontPreference", "options", "setSiteFont", "next", "setUserScale", "applyStoredFontPreferences", "DEFAULT_BADGE_FONT", "SITE_FONT_OPTIONS", "DEFAULT_FONT_TARGET_PREFERENCES", "init_font_preference", "__esmMin", "crc32", "bytes", "crc", "byte", "crcTable", "writeUint16", "value", "writeUint32", "zipDateTime", "date", "createZip", "files", "encoder", "localParts", "centralParts", "offset", "timestamp", "file", "nameBytes", "dataBytes", "checksum", "localHeader", "centralHeader", "centralOffset", "centralSize", "sum", "part", "endHeader", "downloadBlob", "filename", "blob", "url", "anchor", "safeExportName", "board", "usedNames", "base", "name", "suffix", "exportAllBoards", "includeAttachments", "boards", "state", "toast", "snapshot", "api", "archive", "init_board_export", "__esmMin", "init_state", "init_api", "init_toast", "_", "index", "bit", "getUpdateInfo", "cachedInfo", "fetchVersionInfo", "force", "res", "syncUpdateBadge", "show", "btn", "dot", "checkForUpdate", "edition", "info", "TOAST_SEEN_KEY", "toast", "navigate", "state", "init_update_check", "__esmMin", "init_toast", "init_router", "init_state", "init_config", "syncSliderValue", "input", "min", "max", "value", "span", "pct", "bindSliders", "root", "slider", "renderProjectDetail", "context", "api", "state", "bootstrapBoard", "currentBoard", "project", "activeTab", "getSettingsTab", "tabs", "features", "resolvedTab", "renderDrawerShell", "id", "navigate", "renderProjectTabBody", "bindProjectTabHandlers", "tab", "renderNotesSettingsTab", "renderProjectLanesTab", "renderProjectAppearanceTab", "renderProjectAiTab", "renderProjectJournalTab", "renderProjectArchiveTab", "renderProjectDataTab", "aiEnabled", "agentContextSetup", "renderAgentContextSection", "helperFilesSetup", "renderHelperFilesSection", "mcpSetup", "renderMcpSetupSection", "instructionsPlaceholder", "instructions", "hasInstructions", "placeholderClass", "inner", "renderPreservedText", "escapeHtml", "osId", "detectedMcpOs", "clientId", "paths", "mcpDetectedPaths", "configText", "mcpConfigText", "commandText", "mcpRunCommand", "client", "MCP_CLIENTS", "MCP_OS_OPTIONS", "option", "platform", "mcpDefaultPaths", "template", "mcpPathsFromForm", "$", "claudeCodeMcpCommand", "codexMcpToml", "opencodeMcpJson", "vscodeMcpJson", "config", "escapeToml", "shellQuote", "repositoryDelete", "repoMeta", "renderUpdateCard", "renderBoardRenameSection", "renderDeleteBoardSection", "hasFolder", "managed", "slug", "exportedCopy", "notesPlaceholder", "notes", "hasNotes", "renderLaneManager", "info", "getUpdateInfo", "mode", "available", "current", "showSelfUpdate", "chip", "updateCheckGlyph", "statusLine", "versionBlock", "howto", "UPDATE_MODE_LABEL", "UPDATE_INSTRUCTIONS", "theme", "currentTheme", "reduceMotion", "effectiveReducedMotionPreference", "storedMotion", "storedReducedMotionPreference", "browserDefault", "browserPrefersReducedMotion", "sourceLabel", "themeIconMarkup", "motionIconMarkup", "renderTypographyControls", "prefs", "storedFontPreferences", "siteOptions", "SITE_FONT_OPTIONS", "FONT_OPTIONS", "overrideSelects", "FONT_TARGETS", "target", "options", "font", "s", "renderProjectEntries", "parseImportSnapshotText", "text", "error", "exportSnapshot", "includeAttachments", "suffix", "snapshot", "filename", "downloadJson", "event", "form", "nextName", "load", "toast", "importSnapshotFile", "file", "bodyForSnapshot", "importSnapshotAsNewFile", "result", "counts", "cardCount", "err", "replaceImportConfirmInput", "replaceCurrentBoardImportFile", "replaceCurrentBoardImportButton", "disabled", "confirmInput", "confirmButton", "btn", "fetchVersionInfo", "syncUpdateBadge", "orig", "exportAllBoards", "notesEl", "drawerInner", "edit", "startInlineEdit", "next", "cleanText", "button", "handleLaneAction", "field", "updateLane", "renderBoard", "themeToggleBtn", "themeLabel", "themeIcon", "toggleThemePreference", "motionToggleBtn", "reduce", "setReducedMotionPreference", "applyReducedMotionPreference", "setSiteFont", "select", "fontScaleSlider", "scaleValue", "setUserScale", "setFontPreference", "updateMcpPreview", "osNote", "format", "title", "helper", "configEl", "commandEl", "selector", "copyText", "instructionsEl", "enabled", "helperPickFolderBtn", "manageHelperFilesToggle", "listEl", "refresh", "tickets", "t", "renderDetailCard", "restoreBtn", "deleteBtn", "cardTitle", "withBoardQuery", "textArea", "entries", "entry", "isStruck", "showStruckState", "formatDate", "deleteDisabled", "lane", "CORE_LANE_ROLES", "deleteTitle", "count", "lanes", "statesForProject", "ticket", "ticketsForProject", "index", "isAiReady", "nameTitle", "closeIconSvg", "row", "laneId", "action", "swapWith", "silent", "name", "isDefault", "init_settings", "__esmMin", "init_state", "init_dom", "init_format", "init_api", "init_toast", "init_drawer", "init_router", "init_kanban", "init_ticket_detail", "init_app", "init_config", "init_motion_preference", "init_theme_preference", "init_font_preference", "init_icons", "init_board_export", "init_update_check", "clean", "value", "humanizeIdentifier", "raw", "char", "agentNameFrom", "actor", "actorId", "name", "id", "lowerName", "lowerId", "INTERNAL_LOCAL_NAMES", "GENERIC_AGENT_NAMES", "formatActorLabel", "actorType", "type", "agentName", "formatCommentAuthor", "comment", "kind", "author", "AGENT_COMMENT_KINDS", "init_actor_labels", "__esmMin", "setOpen", "open", "drawer", "backdrop", "bodyEl", "closeArtifactDrawer", "localPathHint", "path", "error", "code", "parts", "escapeHtml", "mntDrive", "slashDrive", "drive", "openArtifactDrawer", "ticketId", "title", "titleEl", "metaEl", "result", "api", "withBoardQuery", "renderMarkdown", "err", "toast", "closeBtn", "init_artifact_drawer", "__esmMin", "init_api", "init_format", "init_toast", "event", "renderPanel", "title", "body", "className", "attrs", "headExtra", "classAttr", "extraAttrs", "escapeHtml", "renderTogglePanel", "open", "panelChevronSvg", "init_panel", "__esmMin", "init_format", "attachTypeahead", "input", "getItems", "match", "renderItem", "valueOf", "onSelect", "emptyText", "minChars", "maxItems", "list", "el", "visible", "activeIndex", "blurTimer", "position", "r", "onReposition", "close", "open", "render", "query", "all", "item", "i", "setActive", "next", "rows", "row", "on", "ACTIVE_CLASS", "choose", "onInput", "onFocus", "onKeydown", "event", "onBlur", "onMouseDown", "init_typeahead", "__esmMin", "ticketCanonicalLabel", "t", "renderTicketHitRow", "type", "canonicalTicketType", "escapeHtml", "ticketLabel", "typeLabel", "stateClassFor", "ticketMatchesQuery", "query", "q", "attachTicketTypeahead", "input", "getCandidates", "onSelect", "attachTypeahead", "init_ticket_typeahead", "__esmMin", "init_format", "init_typeahead", "ticket_detail_exports", "__export", "renderDetail", "renderDetailCard", "renderInlinePreservedTextField", "startInlineEdit", "refreshTicketDetail", "ticketId", "renderBoardAfter", "context", "statusHistory", "commentsResult", "api", "withBoardQuery", "upsertTicket", "renderBoard", "state", "patchTicket", "body", "inlineTextOffsetFromPoint", "node", "sourceEvent", "maxLength", "range", "position", "caretRange", "captureInlineEditScrollState", "scrollContainer", "restoreInlineEditScroll", "scrollState", "editor", "editorRect", "nextScrollTop", "focusWithoutScrolling", "opts", "fieldName", "multiline", "initialValue", "ariaLabel", "emptyMessage", "rerender", "commitHandler", "initialString", "clickedCaretOffset", "sourceHeight", "selectionStart", "done", "stopWatchingOutsideClicks", "handleOutsidePointerDown", "restoreNode", "finish", "event", "commit", "next", "toast", "cancel", "handleTextareaIndentationKeydown", "promptArtifactPath", "currentPath", "label", "cleanText", "promptAndSaveArtifactPath", "wireTicketDetailEditors", "ticket", "editTitle", "titleEl", "drawer", "descEl", "drawerInner", "editDescription", "AI_FIELDS", "key", "fieldEl", "edit", "select", "field", "applyLabelPatch", "nextNames", "btn", "removeName", "names", "l", "n", "addLabel", "input", "name", "attachLabelTypeahead", "options", "renderProjectDetail", "openDrawer", "closeDrawer", "requestedTicketId", "hasOption", "comments", "attachmentList", "result", "features", "markRead", "states", "selectableStatesForProject", "typeOptions", "value", "escapeHtml", "canonicalTicketType", "typeLabelLong", "stateOptions", "s", "priorityOptions", "p", "priorityLabel", "labelPills", "closeIconSvg", "detailCanonicalType", "priorityKey", "priorityKeyFor", "currentState", "stateClass", "stateClassFor", "descriptionHtml", "renderPreservedText", "descriptionClass", "detailSubtitleHtml", "ticketLabel", "renderDrawerShell", "formatDateDetail", "renderPanel", "renderHierarchySection", "renderAttachmentSection", "renderParentEpicSection", "renderRelated", "currentBoard", "renderTogglePanel", "aiPlanOpen", "renderStatusHistory", "renderComment", "wireAttachmentControls", "commentTextarea", "$", "button", "commentId", "omittedForAi", "card", "navigate", "childId", "err", "relationId", "aiPlanEl", "id", "artifactFieldName", "artifactTitle", "artifactTicketId", "openArtifactDrawer", "parentEpicForm", "parentInput", "parentClear", "attachTicketTypeahead", "epicCandidates", "syncParentClear", "targetLabel", "targetId", "resolveTicketIdFromLabel", "target", "ticketsForProject", "t", "relatedAddForm", "relatedInput", "relatedClear", "relatedTicketCandidates", "syncRelatedClear", "form", "relationType", "epicChildForm", "childInput", "childClear", "syncChildClear", "childCandidates", "attachments", "cards", "attachment", "renderAttachmentCard", "meta", "formatBytes", "src", "bytes", "imageFilesFromList", "files", "file", "uploadAttachmentFiles", "imageFiles", "response", "payload", "section", "dropzone", "openAttachmentLightbox", "title", "overlay", "close", "onKeyDown", "selfId", "trimmed", "match", "tickets", "hit", "exact", "history", "from", "to", "byLine", "formatActorLabel", "formatDate", "comment", "aiEnabled", "kindLabel", "formatCommentAuthor", "placeholder", "artifactPath", "artifactLabel", "text", "hasValue", "artifactPathText", "hasArtifactControl", "inner", "placeholderClass", "artifactButton", "relations", "relatedIds", "hierarchyIds", "list", "renderRelatedCard", "grid", "c", "epic", "labelCandidates", "applied", "boardLabelCatalog", "renderLabelHitRow", "attachTypeahead", "query", "canonicalType", "typeText", "typeLabel", "eyebrow", "detachBtn", "mode", "attr", "tid", "unreadN", "unreadCount", "unreadDot", "renderTypeIcon", "renderPriorityPill", "relation", "verb", "direction", "init_ticket_detail", "__esmMin", "init_state", "init_dom", "init_format", "init_kanban", "init_drawer", "init_router", "init_api", "init_config", "init_toast", "init_settings", "init_unread", "init_actor_labels", "init_artifact_drawer", "init_icons", "init_text_editing", "init_panel", "init_typeahead", "init_ticket_typeahead", "connectEventStream", "sseReconnectTimer", "state", "params", "url", "es", "sseReconnectDelayMs", "sseDisconnectToastShown", "toast", "msg", "event", "eventType", "findTicket", "t", "me", "isMine", "markRead", "clearUnread", "CARD_TOUCHING_EVENTS", "bumpUnread", "scheduleSSEReload", "ticket", "label", "fields", "delay", "init_sse", "__esmMin", "init_state", "init_api", "init_toast", "init_app", "init_unread", "debounce", "selectedId", "mode", "api", "bootstrapPath", "syncBoardSelection", "render", "compactText", "value", "cleanText", "line", "boardNotesSummary", "board", "NOTE_FALLBACK", "updateCachedBoard", "appState", "index", "item", "renderNotesBody", "notes", "hasNotes", "placeholderClass", "inner", "renderPreservedText", "escapeHtml", "NOTES_PLACEHOLDER", "renderTopbarFocus", "lastRenderedBoard", "summary", "notesButton", "notesText", "notesBody", "setPopoverOpen", "open", "buttons", "popover", "button", "togglePopover", "startBoardNotesEdit", "sourceEvent", "notesEl", "startInlineEdit", "next", "api", "state", "updatedBoard", "wireTopbarFocus", "logoButton", "event", "init_topbar_notes", "__esmMin", "init_format", "app_exports", "__export", "load", "render", "renderDetailOnly", "closeMenuFlyouts", "state", "api", "bootstrapPath", "syncBoardSelection", "seedReadIfNeeded", "features", "sseBoardId", "connectEventStream", "updateTopbarChips", "renderTopbarFocus", "currentBoard", "renderBoard", "renderDetail", "renderBoardSelection", "init_app", "__esmMin", "init_state", "init_api", "init_kanban", "init_ticket_detail", "init_board_menu", "init_sse", "init_unread", "init_config", "init_topbar_notes", "isCreateFlyoutOpen", "createFlyout", "openCreateFlyout", "preselectedLaneId", "createFlyoutHideTimer", "closeMenuFlyouts", "closeDrawer", "createFlyoutInner", "renderCreateForm", "wireCreateForm", "$", "closeCreateFlyout", "createFlyoutBackdrop", "states", "visibleStatesForProject", "defaultState", "item", "effectiveStateId", "s", "stateOptions", "escapeHtml", "closeIconSvg", "form", "description", "event", "handleTextareaIndentationKeydown", "parentInput", "parentId", "attachTicketTypeahead", "ticketsForProject", "ticket", "ticketCanonicalLabel", "typeSelect", "parentField", "syncParentVisibility", "isEpic", "createTicketFromDrawer", "data", "labels", "created", "api", "state", "load", "syncUrlFromState", "init_create_card", "__esmMin", "init_dom", "init_state", "init_format", "init_api", "init_router", "init_text_editing", "init_drawer", "init_board_menu", "init_app", "init_icons", "init_ticket_typeahead", "closeBoardFlyout", "boardFlyout", "boardFlyoutView", "boardMenuBtn", "closeMenuFlyouts", "updateTopbarChips", "state", "board", "b", "label", "boardChipIcon", "escapeHtml", "inflateZipEntry", "bytes", "stream", "parseImportSnapshotText", "text", "filename", "snapshot", "error", "readZipSnapshots", "file", "buffer", "view", "decoder", "snapshots", "offset", "signature", "flags", "method", "compressedSize", "filenameLength", "extraLength", "nameStart", "dataStart", "dataEnd", "name", "compressed", "data", "readImportSnapshots", "renderBoardFlyoutHeader", "showListButton", "newLabel", "features", "renderBoardFlyoutInner", "listBlock", "createBlock", "exportBlock", "body", "rerenderBoardFlyout", "wireBoardFlyout", "button", "event", "btn", "id", "closeCreateFlyout", "navigate", "form", "pickRepoFolderBtn", "repoPathInput", "helperFilesReveal", "syncHelperFilesVisibility", "result", "api", "toast", "fd", "slug", "repoPath", "created", "load", "syncUrlFromState", "includeAttachments", "originalText", "exportAllBoards", "importAllBoardsFile", "input", "importButton", "boardsById", "boardsBySlug", "replaced", "incomingBoard", "match", "openBoardFlyout", "init_board_menu", "__esmMin", "init_dom", "init_state", "init_format", "init_api", "init_router", "init_create_card", "init_toast", "init_app", "init_config", "init_board_export", "emptyRoute", "EMPTY_ROUTE", "normalizeLocation", "input", "url", "decodeSegment", "value", "routeSegments", "routeFromSegments", "parts", "out", "i", "tab", "SETTINGS_TAB_IDS", "parseLegacyHashRoute", "hash", "raw", "parseRoute", "loc", "hasRoute", "buildRoute", "boardSlug", "view", "ticketId", "segs", "isCanonicalRouteUrl", "routeObj", "init_url_routes", "__esmMin", "init_settings_tabs", "boardBySlugOrId", "value", "boards", "state", "b", "routeBoardSlug", "routeObj", "currentBoard", "normalizeRouteForUrl", "routeFromState", "view", "normalizeSettingsTab", "setRouterReady", "routerReady", "currentRoute", "parseRoute", "navigate", "replace", "route", "url", "buildRoute", "isCanonicalRouteUrl", "applyRoute", "syncUrlFromState", "load", "renderDetailOnly", "r", "urlHadRoute", "hasRoute", "prevBoardId", "fallbackBoard", "canonicalRoute", "closeMenuFlyouts", "closeCreateFlyout", "init_router", "__esmMin", "init_state", "init_settings_tabs", "init_board_menu", "init_create_card", "init_url_routes", "init_dom", "init_motion_preference", "init_theme_preference", "applyStoredThemePreference", "applyReducedMotionPreference", "starscape", "startStarscape", "scheduleMeteor", "updateScrolled", "syncThemeIcon", "themeToggle", "toggleThemePreference", "storedThemePreference", "setThemePreference", "THEME_CHANGE_EVENT", "themeIcon", "dark", "currentTheme", "grain", "buildSignatureStars", "canvas", "milkyWay", "ctx", "DPR", "width", "height", "stars", "rafId", "running", "mouse", "resize", "buildStars", "density", "layers", "rng", "mulberry32", "layer", "i", "size", "pickWeighted", "pickStarColor", "r", "onPointerMove", "e", "frame", "t", "time", "parallaxPx", "s", "pulse", "alpha", "px", "py", "g", "b", "radius", "grad", "half", "drawStaticFrame", "start", "stop", "sync", "isDark", "reduced", "effectiveReducedMotionPreference", "el", "SIG_COUNT", "star", "delay", "spawnMeteor", "vw", "vh", "startX", "startY", "distance", "angleDeg", "rad", "endX", "endY", "m", "table", "acc", "value", "weight", "seed", "a", "init_dom", "init_state", "init_api", "init_toast", "init_router", "init_board_menu", "init_create_card", "init_kanban", "init_dom", "init_state", "init_api", "init_router", "init_format", "init_create_card", "runSearch", "query", "searchInput", "hideSearch", "board", "currentBoard", "result", "api", "searchResults", "ticket", "escapeHtml", "ticketLabel", "stateClassFor", "hit", "closeCreateFlyout", "navigate", "state", "init_app", "init_config", "openModal", "dialogEl", "closeModal", "wireModal", "event", "btn", "init_topbar_notes", "fillVersion", "pill", "res", "info", "wireHelpMenu", "dialog", "helpBtn", "wireModal", "openModal", "init_update_check", "init_font_preference", "init", "welcomeDialog", "applyStoredFontPreferences", "wireModal", "wireTopbarFocus", "wireHelpMenu", "edition", "openModal", "$", "closeCreateFlyout", "closeMenuFlyouts", "navigate", "state", "boardMenuBtn", "event", "boardFlyout", "closeBoardFlyout", "openBoardFlyout", "isCreateFlyoutOpen", "openCreateFlyout", "createFlyoutBackdrop", "ticketId", "titleForToast", "t", "api", "withBoardQuery", "toast", "load", "drawerBackdrop", "drawer", "el", "searchInput", "debounce", "runSearch", "hideSearch", "enableKanbanDragScroll", "enableKanbanInteractions", "initialRoute", "currentRoute", "setRouterReady", "hasRoute", "applyRoute", "syncUrlFromState", "checkForUpdate"]
7
+ }