codex-autorunner 1.0.0__py3-none-any.whl → 1.1.0__py3-none-any.whl

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 (170) hide show
  1. codex_autorunner/__init__.py +12 -1
  2. codex_autorunner/agents/codex/harness.py +1 -1
  3. codex_autorunner/agents/opencode/constants.py +3 -0
  4. codex_autorunner/agents/opencode/harness.py +6 -1
  5. codex_autorunner/agents/opencode/runtime.py +59 -18
  6. codex_autorunner/agents/registry.py +22 -3
  7. codex_autorunner/bootstrap.py +7 -3
  8. codex_autorunner/cli.py +5 -1174
  9. codex_autorunner/codex_cli.py +20 -84
  10. codex_autorunner/core/__init__.py +4 -0
  11. codex_autorunner/core/about_car.py +6 -1
  12. codex_autorunner/core/app_server_ids.py +59 -0
  13. codex_autorunner/core/app_server_threads.py +11 -2
  14. codex_autorunner/core/app_server_utils.py +165 -0
  15. codex_autorunner/core/archive.py +349 -0
  16. codex_autorunner/core/codex_runner.py +6 -2
  17. codex_autorunner/core/config.py +197 -3
  18. codex_autorunner/core/drafts.py +58 -4
  19. codex_autorunner/core/engine.py +1329 -680
  20. codex_autorunner/core/exceptions.py +4 -0
  21. codex_autorunner/core/flows/controller.py +25 -1
  22. codex_autorunner/core/flows/models.py +13 -0
  23. codex_autorunner/core/flows/reasons.py +52 -0
  24. codex_autorunner/core/flows/reconciler.py +131 -0
  25. codex_autorunner/core/flows/runtime.py +35 -4
  26. codex_autorunner/core/flows/store.py +83 -0
  27. codex_autorunner/core/flows/transition.py +5 -0
  28. codex_autorunner/core/flows/ux_helpers.py +257 -0
  29. codex_autorunner/core/git_utils.py +62 -0
  30. codex_autorunner/core/hub.py +121 -7
  31. codex_autorunner/core/notifications.py +14 -2
  32. codex_autorunner/core/ports/__init__.py +28 -0
  33. codex_autorunner/{integrations/agents → core/ports}/agent_backend.py +11 -3
  34. codex_autorunner/core/ports/backend_orchestrator.py +41 -0
  35. codex_autorunner/{integrations/agents → core/ports}/run_event.py +22 -2
  36. codex_autorunner/core/state_roots.py +57 -0
  37. codex_autorunner/core/supervisor_protocol.py +15 -0
  38. codex_autorunner/core/text_delta_coalescer.py +54 -0
  39. codex_autorunner/core/ticket_linter_cli.py +201 -0
  40. codex_autorunner/core/ticket_manager_cli.py +432 -0
  41. codex_autorunner/core/update.py +4 -5
  42. codex_autorunner/core/update_paths.py +28 -0
  43. codex_autorunner/core/usage.py +164 -12
  44. codex_autorunner/core/utils.py +91 -9
  45. codex_autorunner/flows/review/__init__.py +17 -0
  46. codex_autorunner/{core/review.py → flows/review/service.py} +15 -10
  47. codex_autorunner/flows/ticket_flow/definition.py +9 -2
  48. codex_autorunner/integrations/agents/__init__.py +9 -19
  49. codex_autorunner/integrations/agents/backend_orchestrator.py +284 -0
  50. codex_autorunner/integrations/agents/codex_adapter.py +90 -0
  51. codex_autorunner/integrations/agents/codex_backend.py +158 -17
  52. codex_autorunner/integrations/agents/opencode_adapter.py +108 -0
  53. codex_autorunner/integrations/agents/opencode_backend.py +305 -32
  54. codex_autorunner/integrations/agents/runner.py +91 -0
  55. codex_autorunner/integrations/agents/wiring.py +271 -0
  56. codex_autorunner/integrations/app_server/client.py +7 -60
  57. codex_autorunner/integrations/app_server/env.py +2 -107
  58. codex_autorunner/{core/app_server_events.py → integrations/app_server/event_buffer.py} +15 -8
  59. codex_autorunner/integrations/telegram/adapter.py +65 -0
  60. codex_autorunner/integrations/telegram/config.py +46 -0
  61. codex_autorunner/integrations/telegram/constants.py +1 -1
  62. codex_autorunner/integrations/telegram/handlers/callbacks.py +7 -0
  63. codex_autorunner/integrations/telegram/handlers/commands/flows.py +1203 -66
  64. codex_autorunner/integrations/telegram/handlers/commands_runtime.py +4 -3
  65. codex_autorunner/integrations/telegram/handlers/commands_spec.py +8 -2
  66. codex_autorunner/integrations/telegram/handlers/messages.py +1 -0
  67. codex_autorunner/integrations/telegram/handlers/selections.py +61 -1
  68. codex_autorunner/integrations/telegram/helpers.py +24 -1
  69. codex_autorunner/integrations/telegram/service.py +15 -10
  70. codex_autorunner/integrations/telegram/ticket_flow_bridge.py +329 -40
  71. codex_autorunner/integrations/telegram/transport.py +3 -1
  72. codex_autorunner/routes/__init__.py +37 -76
  73. codex_autorunner/routes/agents.py +2 -137
  74. codex_autorunner/routes/analytics.py +2 -238
  75. codex_autorunner/routes/app_server.py +2 -131
  76. codex_autorunner/routes/base.py +2 -596
  77. codex_autorunner/routes/file_chat.py +4 -833
  78. codex_autorunner/routes/flows.py +4 -977
  79. codex_autorunner/routes/messages.py +4 -456
  80. codex_autorunner/routes/repos.py +2 -196
  81. codex_autorunner/routes/review.py +2 -147
  82. codex_autorunner/routes/sessions.py +2 -175
  83. codex_autorunner/routes/settings.py +2 -168
  84. codex_autorunner/routes/shared.py +2 -275
  85. codex_autorunner/routes/system.py +4 -193
  86. codex_autorunner/routes/usage.py +2 -86
  87. codex_autorunner/routes/voice.py +2 -119
  88. codex_autorunner/routes/workspace.py +2 -270
  89. codex_autorunner/server.py +2 -2
  90. codex_autorunner/static/agentControls.js +40 -11
  91. codex_autorunner/static/app.js +11 -3
  92. codex_autorunner/static/archive.js +826 -0
  93. codex_autorunner/static/archiveApi.js +37 -0
  94. codex_autorunner/static/autoRefresh.js +7 -7
  95. codex_autorunner/static/dashboard.js +224 -171
  96. codex_autorunner/static/hub.js +112 -94
  97. codex_autorunner/static/index.html +80 -33
  98. codex_autorunner/static/messages.js +486 -83
  99. codex_autorunner/static/preserve.js +17 -0
  100. codex_autorunner/static/settings.js +125 -6
  101. codex_autorunner/static/smartRefresh.js +52 -0
  102. codex_autorunner/static/styles.css +1373 -101
  103. codex_autorunner/static/tabs.js +152 -11
  104. codex_autorunner/static/terminal.js +18 -0
  105. codex_autorunner/static/ticketEditor.js +99 -5
  106. codex_autorunner/static/tickets.js +760 -87
  107. codex_autorunner/static/utils.js +11 -0
  108. codex_autorunner/static/workspace.js +133 -40
  109. codex_autorunner/static/workspaceFileBrowser.js +9 -9
  110. codex_autorunner/surfaces/__init__.py +5 -0
  111. codex_autorunner/surfaces/cli/__init__.py +6 -0
  112. codex_autorunner/surfaces/cli/cli.py +1224 -0
  113. codex_autorunner/surfaces/cli/codex_cli.py +20 -0
  114. codex_autorunner/surfaces/telegram/__init__.py +3 -0
  115. codex_autorunner/surfaces/web/__init__.py +1 -0
  116. codex_autorunner/surfaces/web/app.py +2019 -0
  117. codex_autorunner/surfaces/web/hub_jobs.py +192 -0
  118. codex_autorunner/surfaces/web/middleware.py +587 -0
  119. codex_autorunner/surfaces/web/pty_session.py +370 -0
  120. codex_autorunner/surfaces/web/review.py +6 -0
  121. codex_autorunner/surfaces/web/routes/__init__.py +78 -0
  122. codex_autorunner/surfaces/web/routes/agents.py +138 -0
  123. codex_autorunner/surfaces/web/routes/analytics.py +277 -0
  124. codex_autorunner/surfaces/web/routes/app_server.py +132 -0
  125. codex_autorunner/surfaces/web/routes/archive.py +357 -0
  126. codex_autorunner/surfaces/web/routes/base.py +615 -0
  127. codex_autorunner/surfaces/web/routes/file_chat.py +836 -0
  128. codex_autorunner/surfaces/web/routes/flows.py +1164 -0
  129. codex_autorunner/surfaces/web/routes/messages.py +459 -0
  130. codex_autorunner/surfaces/web/routes/repos.py +197 -0
  131. codex_autorunner/surfaces/web/routes/review.py +148 -0
  132. codex_autorunner/surfaces/web/routes/sessions.py +176 -0
  133. codex_autorunner/surfaces/web/routes/settings.py +169 -0
  134. codex_autorunner/surfaces/web/routes/shared.py +280 -0
  135. codex_autorunner/surfaces/web/routes/system.py +196 -0
  136. codex_autorunner/surfaces/web/routes/usage.py +89 -0
  137. codex_autorunner/surfaces/web/routes/voice.py +120 -0
  138. codex_autorunner/surfaces/web/routes/workspace.py +271 -0
  139. codex_autorunner/surfaces/web/runner_manager.py +25 -0
  140. codex_autorunner/surfaces/web/schemas.py +417 -0
  141. codex_autorunner/surfaces/web/static_assets.py +490 -0
  142. codex_autorunner/surfaces/web/static_refresh.py +86 -0
  143. codex_autorunner/surfaces/web/terminal_sessions.py +78 -0
  144. codex_autorunner/tickets/__init__.py +8 -1
  145. codex_autorunner/tickets/agent_pool.py +26 -4
  146. codex_autorunner/tickets/files.py +6 -2
  147. codex_autorunner/tickets/models.py +3 -1
  148. codex_autorunner/tickets/outbox.py +12 -0
  149. codex_autorunner/tickets/runner.py +63 -5
  150. codex_autorunner/web/__init__.py +5 -1
  151. codex_autorunner/web/app.py +2 -1949
  152. codex_autorunner/web/hub_jobs.py +2 -191
  153. codex_autorunner/web/middleware.py +2 -586
  154. codex_autorunner/web/pty_session.py +2 -369
  155. codex_autorunner/web/runner_manager.py +2 -24
  156. codex_autorunner/web/schemas.py +2 -376
  157. codex_autorunner/web/static_assets.py +4 -441
  158. codex_autorunner/web/static_refresh.py +2 -85
  159. codex_autorunner/web/terminal_sessions.py +2 -77
  160. codex_autorunner/workspace/paths.py +49 -33
  161. codex_autorunner-1.1.0.dist-info/METADATA +154 -0
  162. codex_autorunner-1.1.0.dist-info/RECORD +308 -0
  163. codex_autorunner/core/static_assets.py +0 -55
  164. codex_autorunner-1.0.0.dist-info/METADATA +0 -246
  165. codex_autorunner-1.0.0.dist-info/RECORD +0 -251
  166. /codex_autorunner/{routes → surfaces/web/routes}/terminal_images.py +0 -0
  167. {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.1.0.dist-info}/WHEEL +0 -0
  168. {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.1.0.dist-info}/entry_points.txt +0 -0
  169. {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.1.0.dist-info}/licenses/LICENSE +0 -0
  170. {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.1.0.dist-info}/top_level.txt +0 -0
@@ -346,6 +346,8 @@ body {
346
346
  border-radius: var(--radius);
347
347
  position: relative;
348
348
  z-index: 1501;
349
+ overflow: hidden;
350
+ min-width: 0;
349
351
  }
350
352
 
351
353
  .nav-actions {
@@ -353,6 +355,12 @@ body {
353
355
  align-items: center;
354
356
  gap: 6px;
355
357
  flex-shrink: 0;
358
+ position: relative;
359
+ z-index: 1505;
360
+ }
361
+
362
+ .nav-actions:empty {
363
+ display: none;
356
364
  }
357
365
 
358
366
  .inbox-btn {
@@ -1089,6 +1097,30 @@ main {
1089
1097
  overflow: hidden;
1090
1098
  }
1091
1099
 
1100
+ .hub-repo-usage-line {
1101
+ display: flex;
1102
+ align-items: center;
1103
+ gap: 6px;
1104
+ margin-top: 2px;
1105
+ font-size: 10px;
1106
+ }
1107
+
1108
+ .hub-usage-pill {
1109
+ background: rgba(108, 245, 216, 0.08);
1110
+ border: 1px solid var(--border);
1111
+ color: var(--text);
1112
+ }
1113
+
1114
+ .hub-usage-pill-meta {
1115
+ color: var(--muted);
1116
+ white-space: nowrap;
1117
+ }
1118
+
1119
+ .hub-usage-unmatched-note {
1120
+ margin-top: 4px;
1121
+ padding-left: 2px;
1122
+ }
1123
+
1092
1124
  a.hub-pr-pill {
1093
1125
  text-decoration: none;
1094
1126
  border-color: rgba(108, 245, 216, 0.35);
@@ -1411,6 +1443,22 @@ button {
1411
1443
  -webkit-tap-highlight-color: transparent;
1412
1444
  }
1413
1445
 
1446
+ @media (pointer: coarse) {
1447
+
1448
+ button,
1449
+ .tab,
1450
+ .ticket-fm-toggle,
1451
+ select {
1452
+ min-height: 44px;
1453
+ min-width: 44px;
1454
+ }
1455
+
1456
+ button.icon-btn {
1457
+ min-width: 36px;
1458
+ min-height: 36px;
1459
+ }
1460
+ }
1461
+
1414
1462
  button:hover:not(:disabled) {
1415
1463
  border-color: var(--muted);
1416
1464
  background: #161b28;
@@ -1687,6 +1735,16 @@ button.icon-btn {
1687
1735
  opacity: 0.6;
1688
1736
  }
1689
1737
 
1738
+ .ticket-card .ticket-flow-meta .ticket-flow-action {
1739
+ padding: 2px 6px;
1740
+ font-size: 10px;
1741
+ line-height: 1.1;
1742
+ }
1743
+
1744
+ .ticket-card .ticket-flow-meta .ticket-flow-pill {
1745
+ margin-left: 2px;
1746
+ }
1747
+
1690
1748
  /* Ticket meta details container - desktop shows all */
1691
1749
  .ticket-card .ticket-meta-details {
1692
1750
  display: contents;
@@ -1699,10 +1757,6 @@ button.icon-btn {
1699
1757
  white-space: nowrap;
1700
1758
  }
1701
1759
 
1702
- /* Meta toggle button - hidden on desktop */
1703
- .ticket-card .ticket-meta-toggle {
1704
- display: none;
1705
- }
1706
1760
 
1707
1761
  /* Overflow menu container */
1708
1762
  .ticket-overflow-menu {
@@ -1766,6 +1820,28 @@ button.icon-btn {
1766
1820
  min-height: 0;
1767
1821
  container-type: inline-size;
1768
1822
  container-name: ticket-panel;
1823
+ position: relative;
1824
+ }
1825
+
1826
+ /* Scroll fade indicator - shows when content is scrollable */
1827
+ .ticket-card .ticket-panel::after {
1828
+ content: "";
1829
+ position: absolute;
1830
+ bottom: 10px;
1831
+ /* Match panel padding */
1832
+ left: 10px;
1833
+ right: 16px;
1834
+ /* Leave room for scrollbar */
1835
+ height: 32px;
1836
+ background: linear-gradient(to bottom, transparent, rgba(26, 33, 48, 0.95));
1837
+ border-radius: 0 0 8px 8px;
1838
+ pointer-events: none;
1839
+ opacity: 0;
1840
+ transition: opacity 0.2s ease;
1841
+ }
1842
+
1843
+ .ticket-card .ticket-panel.has-scroll-bottom::after {
1844
+ opacity: 1;
1769
1845
  }
1770
1846
 
1771
1847
  .ticket-card .ticket-panel-header {
@@ -1778,6 +1854,30 @@ button.icon-btn {
1778
1854
  margin-bottom: 2px;
1779
1855
  }
1780
1856
 
1857
+ /* Ticket progress bar */
1858
+ .ticket-progress-bar {
1859
+ height: 3px;
1860
+ background: rgba(255, 255, 255, 0.08);
1861
+ border-radius: 2px;
1862
+ overflow: hidden;
1863
+ margin: 4px 0 6px 0;
1864
+ flex-shrink: 0;
1865
+ }
1866
+
1867
+ .ticket-progress-fill {
1868
+ height: 100%;
1869
+ background: linear-gradient(90deg, #3fb950, #58d66a);
1870
+ border-radius: 2px;
1871
+ transition: width 0.3s ease;
1872
+ width: 0%;
1873
+ }
1874
+
1875
+ /* Hide progress bar when empty (0 tickets) */
1876
+ .ticket-progress-bar:empty,
1877
+ .ticket-progress-bar.hidden {
1878
+ display: none;
1879
+ }
1880
+
1781
1881
  .ticket-card .ticket-list {
1782
1882
  display: grid;
1783
1883
  gap: 6px;
@@ -1823,12 +1923,15 @@ button.icon-btn {
1823
1923
  /* Compact dispatch items that don't stack */
1824
1924
  .dispatch-item {
1825
1925
  flex-shrink: 0;
1826
- padding: 10px 12px;
1926
+ padding: 0;
1827
1927
  background: rgba(255, 255, 255, 0.03);
1828
1928
  border: 1px solid var(--border);
1829
1929
  border-radius: 8px;
1830
- cursor: pointer;
1930
+ cursor: default;
1831
1931
  transition: background 0.15s ease, border-color 0.15s ease;
1932
+ position: relative;
1933
+ display: flex;
1934
+ flex-direction: row;
1832
1935
  }
1833
1936
 
1834
1937
  .dispatch-item:hover {
@@ -1836,12 +1939,94 @@ button.icon-btn {
1836
1939
  border-color: var(--accent);
1837
1940
  }
1838
1941
 
1942
+ /* Reddit-style thin collapse bar on the left */
1943
+ .dispatch-collapse-bar {
1944
+ flex-shrink: 0;
1945
+ width: 4px;
1946
+ min-height: 100%;
1947
+ background: rgba(255, 255, 255, 0.15);
1948
+ border-radius: 8px 0 0 8px;
1949
+ cursor: pointer;
1950
+ transition: background 0.15s ease, width 0.1s ease;
1951
+ position: relative;
1952
+ }
1953
+
1954
+ .dispatch-collapse-bar:hover {
1955
+ background: var(--accent);
1956
+ width: 6px;
1957
+ }
1958
+
1959
+ .dispatch-collapse-bar:active {
1960
+ background: var(--accent-hover, var(--accent));
1961
+ }
1962
+
1963
+ /* Collapsed state - bar is dimmer */
1964
+ .dispatch-item.collapsed .dispatch-collapse-bar {
1965
+ background: rgba(255, 255, 255, 0.08);
1966
+ }
1967
+
1968
+ .dispatch-item.collapsed .dispatch-collapse-bar:hover {
1969
+ background: var(--accent);
1970
+ width: 6px;
1971
+ }
1972
+
1973
+ /* Dispatch content wrapper */
1974
+ .dispatch-content-wrapper {
1975
+ flex: 1;
1976
+ min-width: 0;
1977
+ display: flex;
1978
+ flex-direction: column;
1979
+ }
1980
+
1981
+ /* Dispatch header */
1982
+ .dispatch-header {
1983
+ display: flex;
1984
+ align-items: center;
1985
+ gap: 6px;
1986
+ padding: 8px 10px;
1987
+ border-bottom: 1px solid transparent;
1988
+ transition: border-color 0.15s ease;
1989
+ cursor: pointer;
1990
+ }
1991
+
1992
+ .dispatch-header:hover {
1993
+ background: rgba(255, 255, 255, 0.02);
1994
+ }
1995
+
1996
+ .dispatch-item.collapsed .dispatch-header {
1997
+ border-bottom: none;
1998
+ }
1999
+
2000
+ /* Hide old collapse button - replaced by bar */
2001
+ .dispatch-collapse-btn {
2002
+ display: none;
2003
+ }
2004
+
2005
+ /* Header content area */
2006
+ .dispatch-header-content {
2007
+ flex: 1;
2008
+ min-width: 0;
2009
+ }
2010
+
2011
+ .dispatch-item.turn-summary .dispatch-header-content {
2012
+ cursor: default;
2013
+ }
2014
+
1839
2015
  .dispatch-item-head {
1840
2016
  display: flex;
1841
2017
  align-items: center;
1842
- justify-content: space-between;
1843
2018
  gap: 8px;
1844
- margin-bottom: 6px;
2019
+ margin-bottom: 0;
2020
+ flex-wrap: wrap;
2021
+ }
2022
+
2023
+ /* Dispatch body wrapper */
2024
+ .dispatch-body-wrapper {
2025
+ padding: 0 10px 10px 10px;
2026
+ }
2027
+
2028
+ .dispatch-item.collapsed .dispatch-body-wrapper {
2029
+ display: none;
1845
2030
  }
1846
2031
 
1847
2032
  .dispatch-item .ticket-name {
@@ -1926,11 +2111,57 @@ button.icon-btn {
1926
2111
  border-color: rgba(63, 185, 80, 0.5);
1927
2112
  }
1928
2113
 
2114
+ .dispatch-item.turn-summary .dispatch-collapse-bar {
2115
+ background: rgba(63, 185, 80, 0.5);
2116
+ }
2117
+
2118
+ .dispatch-item.turn-summary .dispatch-collapse-bar:hover {
2119
+ background: rgba(63, 185, 80, 0.8);
2120
+ }
2121
+
1929
2122
  .dispatch-item .turn-summary-badge {
1930
2123
  background: rgba(63, 185, 80, 0.25);
1931
2124
  color: #8dc896;
1932
2125
  }
1933
2126
 
2127
+ /* Pause/handoff dispatch styling - red */
2128
+ .dispatch-item.pause {
2129
+ background: rgba(248, 81, 73, 0.06);
2130
+ border-color: rgba(248, 81, 73, 0.3);
2131
+ }
2132
+
2133
+ .dispatch-item.pause:hover {
2134
+ background: rgba(248, 81, 73, 0.1);
2135
+ border-color: rgba(248, 81, 73, 0.5);
2136
+ }
2137
+
2138
+ .dispatch-item.pause .dispatch-collapse-bar {
2139
+ background: rgba(248, 81, 73, 0.5);
2140
+ }
2141
+
2142
+ .dispatch-item.pause .dispatch-collapse-bar:hover {
2143
+ background: rgba(248, 81, 73, 0.8);
2144
+ }
2145
+
2146
+ /* Notify dispatch styling - orange */
2147
+ .dispatch-item.notify {
2148
+ background: rgba(255, 163, 68, 0.06);
2149
+ border-color: rgba(255, 163, 68, 0.3);
2150
+ }
2151
+
2152
+ .dispatch-item.notify:hover {
2153
+ background: rgba(255, 163, 68, 0.1);
2154
+ border-color: rgba(255, 163, 68, 0.5);
2155
+ }
2156
+
2157
+ .dispatch-item.notify .dispatch-collapse-bar {
2158
+ background: rgba(255, 163, 68, 0.5);
2159
+ }
2160
+
2161
+ .dispatch-item.notify .dispatch-collapse-bar:hover {
2162
+ background: rgba(255, 163, 68, 0.8);
2163
+ }
2164
+
1934
2165
  /* Ticket reference in dispatch items */
1935
2166
  .dispatch-ticket-ref {
1936
2167
  font-size: 10px;
@@ -1938,7 +2169,45 @@ button.icon-btn {
1938
2169
  border-radius: 4px;
1939
2170
  background: rgba(255, 255, 255, 0.08);
1940
2171
  color: #a0a8b8;
2172
+ }
2173
+
2174
+ /* Timestamp in dispatch items */
2175
+ .dispatch-time {
2176
+ font-size: 10px;
2177
+ color: var(--muted);
1941
2178
  margin-left: auto;
2179
+ white-space: nowrap;
2180
+ margin-left: auto;
2181
+ }
2182
+
2183
+ /* Diff stats in dispatch items (GitHub-style +/- indicators) */
2184
+ .dispatch-diff-stats {
2185
+ display: inline-flex;
2186
+ gap: 4px;
2187
+ font-family: 'JetBrains Mono', 'SF Mono', Monaco, monospace;
2188
+ font-size: 11px;
2189
+ white-space: nowrap;
2190
+ }
2191
+
2192
+ .dispatch-diff-stats .diff-add {
2193
+ color: #3fb950;
2194
+ }
2195
+
2196
+ .dispatch-diff-stats .diff-del {
2197
+ color: #f85149;
2198
+ }
2199
+
2200
+ /* Diff stats in analytics metrics */
2201
+ .diff-stats-metric {
2202
+ font-family: 'JetBrains Mono', 'SF Mono', Monaco, monospace;
2203
+ }
2204
+
2205
+ .diff-stats-metric .diff-add {
2206
+ color: #3fb950;
2207
+ }
2208
+
2209
+ .diff-stats-metric .diff-del {
2210
+ color: #f85149;
1942
2211
  }
1943
2212
 
1944
2213
 
@@ -1950,8 +2219,26 @@ button.icon-btn {
1950
2219
  display: flex;
1951
2220
  flex-direction: column;
1952
2221
  gap: 3px;
1953
- min-height: 0;
1954
- transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
2222
+ min-height: 56px;
2223
+ /* Consistent height for visual rhythm with body preview */
2224
+ transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
2225
+ overflow: hidden;
2226
+ }
2227
+
2228
+ .ticket-card .ticket-item:hover {
2229
+ background: rgba(255, 255, 255, 0.06);
2230
+ border-color: rgba(255, 255, 255, 0.12);
2231
+ transform: translateY(-1px);
2232
+ }
2233
+
2234
+ .ticket-card .ticket-item.selected {
2235
+ border-color: var(--accent, #6f89ff);
2236
+ background: rgba(111, 137, 255, 0.08);
2237
+ box-shadow: 0 0 0 1px rgba(111, 137, 255, 0.3);
2238
+ }
2239
+
2240
+ .ticket-card .ticket-item.selected:hover {
2241
+ background: rgba(111, 137, 255, 0.12);
1955
2242
  }
1956
2243
 
1957
2244
  .ticket-card .ticket-item.done {
@@ -2059,6 +2346,9 @@ button.icon-btn {
2059
2346
  /* Ticket title text span - follows number */
2060
2347
  .ticket-card .ticket-item .ticket-title-text {
2061
2348
  color: #9098a8;
2349
+ min-width: 0;
2350
+ overflow: hidden;
2351
+ text-overflow: ellipsis;
2062
2352
  }
2063
2353
 
2064
2354
  .ticket-card .ticket-item .ticket-badges {
@@ -2118,12 +2408,21 @@ button.icon-btn {
2118
2408
  line-height: 1.4;
2119
2409
  max-height: 2.8em;
2120
2410
  /* ~2 lines */
2411
+ min-height: 1.4em;
2412
+ /* Reserve space for at least 1 line */
2121
2413
  overflow: hidden;
2122
2414
  word-break: break-word;
2123
2415
  -webkit-mask-image: linear-gradient(to bottom, black 50%, transparent 100%);
2124
2416
  mask-image: linear-gradient(to bottom, black 50%, transparent 100%);
2125
2417
  }
2126
2418
 
2419
+ /* Empty body placeholder */
2420
+ .ticket-card .ticket-item .ticket-body:empty::before {
2421
+ content: "No description";
2422
+ color: rgba(144, 152, 168, 0.5);
2423
+ font-style: italic;
2424
+ }
2425
+
2127
2426
  /* Compact mode when panel is narrow */
2128
2427
  @container ticket-panel (max-width: 350px) {
2129
2428
  .ticket-item .ticket-body {
@@ -2139,6 +2438,38 @@ button.icon-btn {
2139
2438
  }
2140
2439
  }
2141
2440
 
2441
+ /* ===== Desktop (>=1024px): Compact emoji-only badges ===== */
2442
+ @media (min-width: 1024px) {
2443
+
2444
+ /* Hide badge text on desktop, show emoji only */
2445
+ .ticket-card .ticket-item .ticket-done-badge .badge-text,
2446
+ .ticket-card .ticket-item .ticket-working-badge .badge-text {
2447
+ display: none;
2448
+ }
2449
+
2450
+ /* Compact done badge - just checkmark */
2451
+ .ticket-card .ticket-item.done .ticket-done-badge {
2452
+ padding: 2px 6px;
2453
+ gap: 0;
2454
+ }
2455
+
2456
+ /* Compact working badge - hammer emoji instead of animated dot */
2457
+ .ticket-card .ticket-item.active .ticket-working-badge {
2458
+ padding: 2px 6px;
2459
+ gap: 0;
2460
+ }
2461
+
2462
+ .ticket-card .ticket-item.active .ticket-working-badge::before {
2463
+ content: "🔨";
2464
+ width: auto;
2465
+ height: auto;
2466
+ border-radius: 0;
2467
+ background: none;
2468
+ animation: none;
2469
+ font-size: 11px;
2470
+ }
2471
+ }
2472
+
2142
2473
  /* ===== Collapsible Dispatch Panel for Medium Screens ===== */
2143
2474
 
2144
2475
  /* Mini dispatch list - hidden by default, shown in collapsed mode */
@@ -2186,6 +2517,7 @@ button.icon-btn {
2186
2517
 
2187
2518
  /* ===== Mobile (<640px): Stacked layout with full ticket info ===== */
2188
2519
  @media (max-width: 639px) {
2520
+
2189
2521
  /* Force single column stacked layout on mobile */
2190
2522
  .ticket-card .ticket-flow-grid {
2191
2523
  grid-template-columns: 1fr !important;
@@ -2245,6 +2577,24 @@ button.icon-btn {
2245
2577
  white-space: nowrap;
2246
2578
  line-height: 1;
2247
2579
  margin: 0 !important;
2580
+ gap: 0 !important;
2581
+ }
2582
+
2583
+ /* Hide badge text on mobile, show emoji only */
2584
+ .ticket-card .ticket-item .ticket-done-badge .badge-text,
2585
+ .ticket-card .ticket-item .ticket-working-badge .badge-text {
2586
+ display: none;
2587
+ }
2588
+
2589
+ /* Working badge - hammer emoji instead of animated dot on mobile */
2590
+ .ticket-card .ticket-item.active .ticket-working-badge::before {
2591
+ content: "🔨" !important;
2592
+ width: auto !important;
2593
+ height: auto !important;
2594
+ border-radius: 0 !important;
2595
+ background: none !important;
2596
+ animation: none !important;
2597
+ font-size: 10px;
2248
2598
  }
2249
2599
 
2250
2600
  .ticket-card .ticket-item .ticket-agent {
@@ -2276,7 +2626,16 @@ button.icon-btn {
2276
2626
 
2277
2627
  /* Compact dispatch items on mobile */
2278
2628
  .dispatch-item {
2279
- padding: 8px 10px;
2629
+ padding: 0;
2630
+ }
2631
+
2632
+ /* Wider collapse bar on mobile for easier touch */
2633
+ .dispatch-collapse-bar {
2634
+ width: 6px;
2635
+ }
2636
+
2637
+ .dispatch-collapse-bar:hover {
2638
+ width: 8px;
2280
2639
  }
2281
2640
 
2282
2641
  .ticket-dispatch-body {
@@ -2286,6 +2645,7 @@ button.icon-btn {
2286
2645
 
2287
2646
  /* ===== Small tablets / narrow landscape (640-900px): Compact side-by-side ===== */
2288
2647
  @media (min-width: 640px) and (max-width: 899px) {
2648
+
2289
2649
  /* Use slim tickets sidebar with compact pills */
2290
2650
  .ticket-card .ticket-flow-grid {
2291
2651
  grid-template-columns: auto 1fr;
@@ -2298,7 +2658,7 @@ button.icon-btn {
2298
2658
  }
2299
2659
 
2300
2660
  /* Tickets panel: slim fixed-width sidebar */
2301
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child {
2661
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child {
2302
2662
  width: 90px;
2303
2663
  min-width: 90px;
2304
2664
  max-width: 90px;
@@ -2310,23 +2670,23 @@ button.icon-btn {
2310
2670
  }
2311
2671
 
2312
2672
  /* Compact header - prevent shrinking */
2313
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-panel-header {
2673
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-panel-header {
2314
2674
  padding: 2px 4px 4px;
2315
2675
  margin-bottom: 2px;
2316
2676
  flex-shrink: 0;
2317
2677
  }
2318
2678
 
2319
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-panel-header > span:first-child {
2679
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-panel-header>span:first-child {
2320
2680
  font-size: 10px;
2321
2681
  }
2322
2682
 
2323
2683
  /* Hide directory path */
2324
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child #ticket-flow-dir {
2684
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child #ticket-flow-dir {
2325
2685
  display: none;
2326
2686
  }
2327
2687
 
2328
2688
  /* Ticket list scrollable */
2329
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-list {
2689
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-list {
2330
2690
  flex: 1;
2331
2691
  min-height: 0;
2332
2692
  overflow-y: auto;
@@ -2335,7 +2695,7 @@ button.icon-btn {
2335
2695
  }
2336
2696
 
2337
2697
  /* Compact ticket pills - number only, minimal spacing, centered */
2338
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item {
2698
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item {
2339
2699
  padding: 4px 2px !important;
2340
2700
  border-radius: 4px;
2341
2701
  background: rgba(255, 255, 255, 0.03);
@@ -2347,44 +2707,44 @@ button.icon-btn {
2347
2707
  justify-content: center !important;
2348
2708
  }
2349
2709
 
2350
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item:hover {
2710
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item:hover {
2351
2711
  background: rgba(255, 255, 255, 0.08);
2352
2712
  }
2353
2713
 
2354
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item.done {
2714
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item.done {
2355
2715
  border-left: 2px solid rgba(63, 185, 80, 0.6);
2356
2716
  padding-left: 2px !important;
2357
2717
  }
2358
2718
 
2359
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item.active {
2719
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item.active {
2360
2720
  background: rgba(111, 137, 255, 0.15);
2361
2721
  border-color: rgba(111, 137, 255, 0.4);
2362
2722
  }
2363
2723
 
2364
2724
  /* Hide everything except the number in compact view */
2365
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item .ticket-body,
2366
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item .ticket-title,
2367
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item .ticket-title-text,
2368
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item .ticket-badges {
2725
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item .ticket-body,
2726
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item .ticket-title,
2727
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item .ticket-title-text,
2728
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item .ticket-badges {
2369
2729
  display: none !important;
2370
2730
  }
2371
2731
 
2372
2732
  /* Center the ticket number - reset margins */
2373
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item .ticket-item-head {
2733
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item .ticket-item-head {
2374
2734
  display: block !important;
2375
2735
  text-align: center;
2376
2736
  margin: 0 !important;
2377
2737
  padding: 0 !important;
2378
2738
  }
2379
2739
 
2380
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item .ticket-name {
2740
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item .ticket-name {
2381
2741
  display: block !important;
2382
2742
  text-align: center;
2383
2743
  margin: 0 !important;
2384
2744
  padding: 0 !important;
2385
2745
  }
2386
2746
 
2387
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item .ticket-num {
2747
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item .ticket-num {
2388
2748
  display: inline-block;
2389
2749
  font-size: 11px;
2390
2750
  font-weight: 600;
@@ -2394,7 +2754,7 @@ button.icon-btn {
2394
2754
  padding: 0 !important;
2395
2755
  }
2396
2756
 
2397
- .ticket-card .ticket-flow-grid > .ticket-panel:first-child .ticket-item.done .ticket-num {
2757
+ .ticket-card .ticket-flow-grid>.ticket-panel:first-child .ticket-item.done .ticket-num {
2398
2758
  color: rgba(168, 230, 180, 0.9);
2399
2759
  }
2400
2760
  }
@@ -2524,10 +2884,13 @@ button.icon-btn {
2524
2884
  }
2525
2885
 
2526
2886
  @keyframes ticket-pulse {
2527
- 0%, 100% {
2887
+
2888
+ 0%,
2889
+ 100% {
2528
2890
  border-color: rgba(111, 137, 255, 0.4);
2529
2891
  box-shadow: 0 0 4px rgba(111, 137, 255, 0.2);
2530
2892
  }
2893
+
2531
2894
  50% {
2532
2895
  border-color: rgba(111, 137, 255, 0.7);
2533
2896
  box-shadow: 0 0 12px rgba(111, 137, 255, 0.4);
@@ -2695,7 +3058,8 @@ button.icon-btn {
2695
3058
  display: -webkit-box;
2696
3059
  -webkit-line-clamp: 3;
2697
3060
  -webkit-box-orient: vertical;
2698
- max-height: calc(3 * 1.4em + 12px); /* 3 lines + padding */
3061
+ max-height: calc(3 * 1.4em + 12px);
3062
+ /* 3 lines + padding */
2699
3063
  }
2700
3064
 
2701
3065
  .ticket-live-output-compact:empty::before {
@@ -5554,6 +5918,8 @@ button.terminal-text-send-icon.disconnected {
5554
5918
  transition: opacity 0.15s ease, transform 0.15s ease;
5555
5919
  transform: translateY(8px);
5556
5920
  z-index: 10000;
5921
+ pointer-events: none;
5922
+ user-select: none;
5557
5923
  }
5558
5924
 
5559
5925
  .toast.show {
@@ -6156,11 +6522,16 @@ button.loading::after {
6156
6522
  .hub-shell {
6157
6523
  padding: 4px;
6158
6524
  padding-top: max(4px, env(safe-area-inset-top));
6159
- }
6525
+ overflow-y: auto;
6526
+ overflow-x: hidden;
6527
+ -webkit-overflow-scrolling: touch;
6528
+ }
6160
6529
 
6161
6530
  .hub-hero {
6162
6531
  padding: 8px 10px;
6163
6532
  gap: 8px;
6533
+ flex-wrap: wrap;
6534
+ overflow: visible;
6164
6535
  }
6165
6536
 
6166
6537
  .hub-hero h1 {
@@ -6172,13 +6543,23 @@ button.loading::after {
6172
6543
  }
6173
6544
 
6174
6545
  .hub-hero-actions {
6175
- gap: 4px;
6546
+ gap: 6px;
6547
+ flex-wrap: wrap;
6548
+ width: 100%;
6549
+ justify-content: flex-start;
6176
6550
  }
6177
6551
 
6178
6552
  .hub-hero-actions button {
6179
6553
  padding: 6px 10px;
6180
6554
  }
6181
6555
 
6556
+ .hub-version {
6557
+ max-width: 80px;
6558
+ overflow: hidden;
6559
+ text-overflow: ellipsis;
6560
+ white-space: nowrap;
6561
+ }
6562
+
6182
6563
  .hub-stats {
6183
6564
  gap: 4px;
6184
6565
  margin: 6px 0;
@@ -6216,6 +6597,8 @@ button.loading::after {
6216
6597
 
6217
6598
  .hub-repo-row {
6218
6599
  gap: 6px;
6600
+ flex-direction: column;
6601
+ align-items: flex-start;
6219
6602
  }
6220
6603
 
6221
6604
  .hub-repo-left {
@@ -6235,8 +6618,16 @@ button.loading::after {
6235
6618
  font-size: 10px;
6236
6619
  }
6237
6620
 
6621
+ .hub-repo-usage-line {
6622
+ font-size: 10px;
6623
+ width: 100%;
6624
+ }
6625
+
6238
6626
  .hub-repo-right {
6239
6627
  gap: 3px;
6628
+ width: 100%;
6629
+ justify-content: flex-start;
6630
+ flex-wrap: wrap;
6240
6631
  }
6241
6632
 
6242
6633
  .hub-repo-right button {
@@ -6249,6 +6640,10 @@ button.loading::after {
6249
6640
  margin-top: 3px;
6250
6641
  }
6251
6642
 
6643
+ .hub-usage-chart {
6644
+ display: none;
6645
+ }
6646
+
6252
6647
  /* Compact usage on mobile */
6253
6648
  .hub-usage-compact {
6254
6649
  padding: 6px 8px;
@@ -6397,7 +6792,7 @@ button.loading::after {
6397
6792
  background: linear-gradient(to top, var(--panel) 0%, rgba(16, 19, 28, 0.98) 100%);
6398
6793
  border-top: 1px solid var(--border);
6399
6794
  box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.3);
6400
- z-index: 100;
6795
+ z-index: 1900;
6401
6796
  backdrop-filter: blur(8px);
6402
6797
  -webkit-backdrop-filter: blur(8px);
6403
6798
  transition: transform 0.18s ease;
@@ -6524,13 +6919,38 @@ button.loading::after {
6524
6919
  display: block;
6525
6920
  }
6526
6921
 
6922
+ /* Compact ticket header on mobile */
6923
+ .ticket-card .card-header {
6924
+ padding-bottom: 4px;
6925
+ margin-bottom: 4px;
6926
+ gap: 4px;
6927
+ }
6928
+
6929
+ .ticket-card .ticket-header-left {
6930
+ gap: 6px;
6931
+ }
6932
+
6933
+ .ticket-card .ticket-header-left .label {
6934
+ font-size: 10px;
6935
+ }
6936
+
6937
+ .ticket-card .ticket-header-left .ticket-mono {
6938
+ font-size: 9px;
6939
+ max-width: 120px;
6940
+ overflow: hidden;
6941
+ text-overflow: ellipsis;
6942
+ }
6943
+
6944
+ /* Compact action buttons on mobile */
6527
6945
  .ticket-card .ticket-flow-actions {
6528
6946
  gap: 4px;
6947
+ margin: 2px 0;
6529
6948
  }
6530
6949
 
6531
6950
  .ticket-card .ticket-flow-actions button {
6532
- min-height: 44px;
6533
- padding: 8px 12px;
6951
+ min-height: 36px;
6952
+ padding: 6px 10px;
6953
+ font-size: 11px;
6534
6954
  }
6535
6955
 
6536
6956
  .ticket-card .ticket-flow-meta {
@@ -6541,58 +6961,45 @@ button.loading::after {
6541
6961
  border: none;
6542
6962
  }
6543
6963
 
6544
- .ticket-card .ticket-meta-toggle {
6964
+ /* Always show details on mobile (simplified critical info only) */
6965
+ .ticket-card .ticket-meta-details {
6545
6966
  display: flex;
6546
- align-items: center;
6547
- justify-content: space-between;
6548
- width: 100%;
6549
- padding: 8px 10px;
6550
- background: linear-gradient(120deg, rgba(111, 137, 255, 0.12), rgba(16, 21, 33, 0.6));
6551
- border: 1px solid var(--border);
6552
- border-radius: 8px;
6553
- color: var(--text);
6554
- font-size: 12px;
6555
- cursor: pointer;
6556
- transition: background 0.15s ease;
6967
+ flex-wrap: wrap;
6968
+ gap: 4px 12px;
6969
+ padding: 4px 8px;
6970
+ margin-top: 0;
6971
+ background: rgba(16, 21, 33, 0.3);
6972
+ border-radius: 4px;
6973
+ font-size: 10px;
6557
6974
  }
6558
6975
 
6559
- .ticket-card .ticket-meta-toggle:active {
6560
- background: rgba(111, 137, 255, 0.2);
6976
+ /* Hide secondary (non-critical) meta rows on mobile */
6977
+ .ticket-card .ticket-meta-details .ticket-meta-secondary {
6978
+ display: none;
6561
6979
  }
6562
6980
 
6563
- .ticket-card .ticket-meta-summary {
6564
- font-weight: 500;
6981
+ /* Show critical meta rows inline on mobile */
6982
+ .ticket-card .ticket-meta-details .ticket-meta-critical {
6983
+ display: flex;
6984
+ align-items: center;
6985
+ gap: 4px;
6986
+ white-space: nowrap;
6565
6987
  }
6566
6988
 
6567
- .ticket-card .ticket-meta-arrow {
6568
- color: var(--muted);
6569
- transition: transform 0.2s ease;
6989
+ /* Compact panel headers on mobile */
6990
+ .ticket-card .ticket-panel-header {
6991
+ padding: 2px 4px 4px;
6992
+ margin-bottom: 0;
6570
6993
  }
6571
6994
 
6572
- .ticket-card .ticket-meta-toggle.expanded .ticket-meta-arrow {
6573
- transform: rotate(180deg);
6995
+ .ticket-card .ticket-panel-header .muted,
6996
+ .ticket-card .ticket-panel-header .small {
6997
+ font-size: 10px;
6574
6998
  }
6575
6999
 
6576
- .ticket-card .ticket-meta-details {
7000
+ /* Hide empty agent selects on mobile */
7001
+ select.mobile-hide-empty:empty {
6577
7002
  display: none;
6578
- flex-wrap: wrap;
6579
- gap: 4px 14px;
6580
- padding: 8px 10px;
6581
- margin-top: 4px;
6582
- background: rgba(16, 21, 33, 0.4);
6583
- border-radius: 6px;
6584
- font-size: 11px;
6585
- }
6586
-
6587
- .ticket-card .ticket-meta-details.expanded {
6588
- display: flex;
6589
- }
6590
-
6591
- .ticket-card .ticket-meta-details>div {
6592
- display: flex;
6593
- align-items: baseline;
6594
- gap: 4px;
6595
- white-space: nowrap;
6596
7003
  }
6597
7004
 
6598
7005
  /* Workspace mobile - hide desktop header, show bottom toolbar */
@@ -6613,7 +7020,7 @@ button.loading::after {
6613
7020
  margin-bottom: 0;
6614
7021
  }
6615
7022
 
6616
- .workspace-mobile-toolbar + .compose-panel {
7023
+ .workspace-mobile-toolbar+.compose-panel {
6617
7024
  margin-top: 2px;
6618
7025
  }
6619
7026
 
@@ -8893,6 +9300,7 @@ button.loading::after {
8893
9300
  overflow-y: auto;
8894
9301
  flex: 1;
8895
9302
  min-height: 0;
9303
+ position: relative;
8896
9304
  }
8897
9305
 
8898
9306
  .messages-main {
@@ -8901,6 +9309,37 @@ button.loading::after {
8901
9309
  min-height: 0;
8902
9310
  }
8903
9311
 
9312
+ .messages-detail-header {
9313
+ display: none;
9314
+ }
9315
+
9316
+ .messages-detail-meta {
9317
+ display: flex;
9318
+ align-items: center;
9319
+ gap: 8px;
9320
+ margin-left: auto;
9321
+ }
9322
+
9323
+ .messages-detail-status {
9324
+ font-size: 10px;
9325
+ }
9326
+
9327
+ .messages-detail-counts {
9328
+ font-size: 11px;
9329
+ white-space: nowrap;
9330
+ }
9331
+
9332
+ .messages-back-btn {
9333
+ border: 1px solid var(--border);
9334
+ background: var(--bg);
9335
+ color: var(--text);
9336
+ border-radius: var(--radius);
9337
+ padding: 8px 14px;
9338
+ font-size: 12px;
9339
+ text-transform: uppercase;
9340
+ letter-spacing: 0.02em;
9341
+ }
9342
+
8904
9343
  .messages-thread {
8905
9344
  text-align: left;
8906
9345
  border: 1px solid var(--border);
@@ -8942,15 +9381,33 @@ button.loading::after {
8942
9381
  flex-shrink: 0;
8943
9382
  }
8944
9383
 
9384
+ .messages-thread-header {
9385
+ display: flex;
9386
+ align-items: center;
9387
+ justify-content: space-between;
9388
+ gap: 8px;
9389
+ }
9390
+
8945
9391
  .messages-thread-meta-line {
8946
9392
  display: flex;
8947
9393
  align-items: center;
9394
+ justify-content: space-between;
8948
9395
  gap: 6px;
8949
9396
  margin-top: 4px;
8950
9397
  font-size: 10px;
8951
9398
  color: var(--muted);
8952
9399
  }
8953
9400
 
9401
+ .messages-thread-counts {
9402
+ flex: 1;
9403
+ }
9404
+
9405
+ .messages-thread-time {
9406
+ color: var(--muted);
9407
+ font-size: 10px;
9408
+ white-space: nowrap;
9409
+ }
9410
+
8954
9411
  .messages-thread-detail {
8955
9412
  border: 1px solid var(--border);
8956
9413
  border-radius: var(--radius);
@@ -8959,6 +9416,23 @@ button.loading::after {
8959
9416
  overflow-y: auto;
8960
9417
  flex: 1;
8961
9418
  min-height: 0;
9419
+ position: relative;
9420
+ }
9421
+
9422
+ .messages-thread-list.refreshing::after,
9423
+ .messages-thread-detail.refreshing::after {
9424
+ content: "";
9425
+ position: absolute;
9426
+ top: 10px;
9427
+ right: 10px;
9428
+ width: 12px;
9429
+ height: 12px;
9430
+ border: 2px solid var(--border);
9431
+ border-top-color: var(--accent);
9432
+ border-radius: 50%;
9433
+ animation: spin 0.6s linear infinite;
9434
+ opacity: 0.8;
9435
+ pointer-events: none;
8962
9436
  }
8963
9437
 
8964
9438
  /* Empty state styling */
@@ -9065,21 +9539,143 @@ button.loading::after {
9065
9539
  .messages-entry {
9066
9540
  border: 1px solid var(--border);
9067
9541
  border-radius: var(--radius);
9068
- padding: 10px 12px;
9542
+ padding: 0;
9069
9543
  background: var(--panel);
9070
9544
  margin-top: 10px;
9545
+ transition: border-color 0.15s ease, background 0.15s ease;
9546
+ position: relative;
9547
+ display: flex;
9548
+ flex-direction: row;
9071
9549
  }
9072
9550
 
9073
9551
  .messages-entry:first-child {
9074
9552
  margin-top: 0;
9075
9553
  }
9076
9554
 
9555
+ /* Reddit-style thin collapse bar on the left */
9556
+ .messages-collapse-bar {
9557
+ flex-shrink: 0;
9558
+ width: 4px;
9559
+ min-height: 100%;
9560
+ background: rgba(255, 255, 255, 0.15);
9561
+ border-radius: var(--radius) 0 0 var(--radius);
9562
+ cursor: pointer;
9563
+ transition: background 0.15s ease, width 0.1s ease;
9564
+ }
9565
+
9566
+ .messages-collapse-bar:hover {
9567
+ background: var(--accent);
9568
+ width: 6px;
9569
+ }
9570
+
9571
+ .messages-collapse-bar:active {
9572
+ background: var(--accent-hover, var(--accent));
9573
+ }
9574
+
9575
+ /* Collapsed state - bar is dimmer */
9576
+ .messages-entry.collapsed .messages-collapse-bar {
9577
+ background: rgba(255, 255, 255, 0.08);
9578
+ }
9579
+
9580
+ .messages-entry.collapsed .messages-collapse-bar:hover {
9581
+ background: var(--accent);
9582
+ width: 6px;
9583
+ }
9584
+
9585
+ /* Messages content wrapper */
9586
+ .messages-content-wrapper {
9587
+ flex: 1;
9588
+ min-width: 0;
9589
+ display: flex;
9590
+ flex-direction: column;
9591
+ }
9592
+
9593
+ /* Hide old collapse button - replaced by bar */
9594
+ .messages-collapse-btn {
9595
+ display: none;
9596
+ }
9597
+
9598
+ /* Messages entry body wrapper */
9599
+ .messages-entry-body {
9600
+ padding: 0 12px 10px 12px;
9601
+ margin-top: 8px;
9602
+ }
9603
+
9604
+ .messages-entry.collapsed .messages-entry-body {
9605
+ display: none;
9606
+ }
9607
+
9077
9608
  .messages-entry.messages-entry-reply {
9078
9609
  margin-left: 20px;
9079
- border-left: 2px solid rgba(108, 168, 255, 0.4);
9080
9610
  background: rgba(108, 168, 255, 0.04);
9081
9611
  }
9082
9612
 
9613
+ /* User reply collapse bar is blue */
9614
+ .messages-entry.messages-entry-reply .messages-collapse-bar {
9615
+ background: rgba(108, 168, 255, 0.4);
9616
+ }
9617
+
9618
+ .messages-entry.messages-entry-reply .messages-collapse-bar:hover {
9619
+ background: rgba(108, 168, 255, 0.7);
9620
+ }
9621
+
9622
+ /* Pause/handoff dispatch styling - red */
9623
+ .messages-entry.dispatch-pause {
9624
+ border-color: rgba(248, 81, 73, 0.4);
9625
+ background: rgba(248, 81, 73, 0.04);
9626
+ }
9627
+
9628
+ .messages-entry.dispatch-pause:hover {
9629
+ border-color: rgba(248, 81, 73, 0.6);
9630
+ background: rgba(248, 81, 73, 0.08);
9631
+ }
9632
+
9633
+ .messages-entry.dispatch-pause .messages-collapse-bar {
9634
+ background: rgba(248, 81, 73, 0.5);
9635
+ }
9636
+
9637
+ .messages-entry.dispatch-pause .messages-collapse-bar:hover {
9638
+ background: rgba(248, 81, 73, 0.8);
9639
+ }
9640
+
9641
+ /* Notify dispatch styling - orange */
9642
+ .messages-entry.dispatch-notify {
9643
+ border-color: rgba(255, 163, 68, 0.4);
9644
+ background: rgba(255, 163, 68, 0.04);
9645
+ }
9646
+
9647
+ .messages-entry.dispatch-notify:hover {
9648
+ border-color: rgba(255, 163, 68, 0.6);
9649
+ background: rgba(255, 163, 68, 0.08);
9650
+ }
9651
+
9652
+ .messages-entry.dispatch-notify .messages-collapse-bar {
9653
+ background: rgba(255, 163, 68, 0.5);
9654
+ }
9655
+
9656
+ .messages-entry.dispatch-notify .messages-collapse-bar:hover {
9657
+ background: rgba(255, 163, 68, 0.8);
9658
+ }
9659
+
9660
+ /* Turn summary dispatch styling - green */
9661
+ .messages-entry.dispatch-turn {
9662
+ border-color: rgba(63, 185, 80, 0.4);
9663
+ background: rgba(63, 185, 80, 0.04);
9664
+ }
9665
+
9666
+ .messages-entry.dispatch-turn:hover {
9667
+ border-color: rgba(63, 185, 80, 0.6);
9668
+ background: rgba(63, 185, 80, 0.08);
9669
+ }
9670
+
9671
+ .messages-entry.dispatch-turn .messages-collapse-bar {
9672
+ background: rgba(63, 185, 80, 0.5);
9673
+ }
9674
+
9675
+ .messages-entry.dispatch-turn .messages-collapse-bar:hover {
9676
+ background: rgba(63, 185, 80, 0.8);
9677
+ }
9678
+
9083
9679
  .messages-entry-header {
9084
9680
  display: flex;
9085
9681
  align-items: center;
@@ -9087,6 +9683,13 @@ button.loading::after {
9087
9683
  font-weight: 500;
9088
9684
  font-size: 12px;
9089
9685
  color: var(--text);
9686
+ padding: 8px 12px;
9687
+ cursor: pointer;
9688
+ transition: background 0.15s ease;
9689
+ }
9690
+
9691
+ .messages-entry-header:hover {
9692
+ background: rgba(255, 255, 255, 0.02);
9090
9693
  }
9091
9694
 
9092
9695
  .messages-entry-seq {
@@ -9125,7 +9728,7 @@ button.loading::after {
9125
9728
  background: transparent;
9126
9729
  border: none;
9127
9730
  padding: 0;
9128
- margin: 10px 0 0;
9731
+ margin: 0;
9129
9732
  color: var(--text);
9130
9733
  }
9131
9734
 
@@ -9138,6 +9741,10 @@ button.loading::after {
9138
9741
  padding: 0;
9139
9742
  }
9140
9743
 
9744
+ .messages-markdown li {
9745
+ margin: 0;
9746
+ }
9747
+
9141
9748
  .messages-markdown code {
9142
9749
  background: rgba(255, 255, 255, 0.06);
9143
9750
  padding: 2px 4px;
@@ -9180,6 +9787,9 @@ button.loading::after {
9180
9787
  position: sticky;
9181
9788
  bottom: 0;
9182
9789
  background: var(--panel);
9790
+ max-width: 100%;
9791
+ overflow: hidden;
9792
+ min-width: 0;
9183
9793
  }
9184
9794
 
9185
9795
  .messages-thread-footer code {
@@ -9198,12 +9808,14 @@ button.loading::after {
9198
9808
  .messages-footer-stats {
9199
9809
  color: var(--muted);
9200
9810
  white-space: nowrap;
9811
+ overflow: hidden;
9812
+ text-overflow: ellipsis;
9813
+ min-width: 0;
9814
+ flex: 1;
9201
9815
  }
9202
9816
 
9203
- /* Legacy header styles - deprecated but kept for compatibility */
9204
- .messages-thread-header {
9205
- display: none;
9206
- }
9817
+ /* Thread header (title + status) used in thread list items */
9818
+ /* Note: .messages-thread-header is now actively used, not deprecated */
9207
9819
 
9208
9820
  .messages-header-info {
9209
9821
  display: none;
@@ -9277,22 +9889,371 @@ button.loading::after {
9277
9889
  min-width: 100px;
9278
9890
  }
9279
9891
 
9280
- @media (max-width: 900px) {
9281
- /* Inbox mobile - fill height and scroll */
9282
- .messages-layout {
9283
- display: flex;
9284
- flex-direction: column;
9285
- gap: 8px;
9286
- flex: 1;
9287
- min-height: 0;
9288
- }
9892
+ /* Archive panel */
9893
+ #archive.panel.active {
9894
+ display: flex;
9895
+ flex-direction: column;
9896
+ flex: 1;
9897
+ min-height: 0;
9898
+ }
9289
9899
 
9290
- .messages-sidebar {
9291
- flex-shrink: 0;
9292
- }
9900
+ #archive .cards {
9901
+ grid-template-columns: 1fr;
9902
+ flex: 1;
9903
+ min-height: 0;
9904
+ }
9293
9905
 
9294
- .messages-thread-list {
9295
- max-height: 180px;
9906
+ #archive .card {
9907
+ max-width: none;
9908
+ padding: 12px 16px;
9909
+ display: flex;
9910
+ flex-direction: column;
9911
+ flex: 1;
9912
+ min-height: 0;
9913
+ }
9914
+
9915
+ .archive-layout {
9916
+ display: grid;
9917
+ grid-template-columns: minmax(240px, 320px) 1fr;
9918
+ gap: 16px;
9919
+ flex: 1;
9920
+ min-height: 0;
9921
+ }
9922
+
9923
+ .archive-sidebar {
9924
+ display: flex;
9925
+ flex-direction: column;
9926
+ min-height: 0;
9927
+ }
9928
+
9929
+ .archive-header {
9930
+ display: flex;
9931
+ align-items: center;
9932
+ justify-content: space-between;
9933
+ gap: 12px;
9934
+ margin-bottom: 10px;
9935
+ }
9936
+
9937
+ .archive-list {
9938
+ display: grid;
9939
+ gap: 8px;
9940
+ align-content: start;
9941
+ overflow-y: auto;
9942
+ flex: 1;
9943
+ min-height: 0;
9944
+ }
9945
+
9946
+ .archive-snapshot {
9947
+ text-align: left;
9948
+ border: 1px solid var(--border);
9949
+ border-radius: var(--radius);
9950
+ padding: 10px 12px;
9951
+ background: var(--panel);
9952
+ cursor: pointer;
9953
+ }
9954
+
9955
+ .archive-snapshot:hover {
9956
+ border-color: rgba(255, 255, 255, 0.16);
9957
+ }
9958
+
9959
+ .archive-snapshot.active {
9960
+ border-color: rgba(80, 250, 123, 0.5);
9961
+ box-shadow: 0 0 0 1px rgba(80, 250, 123, 0.35) inset;
9962
+ }
9963
+
9964
+ .archive-snapshot-title {
9965
+ font-weight: 600;
9966
+ font-size: 12px;
9967
+ margin-bottom: 4px;
9968
+ }
9969
+
9970
+ .archive-snapshot-meta {
9971
+ font-size: 11px;
9972
+ }
9973
+
9974
+ .archive-detail {
9975
+ display: flex;
9976
+ flex-direction: column;
9977
+ min-height: 0;
9978
+ overflow: hidden;
9979
+ }
9980
+
9981
+ .archive-detail-header {
9982
+ display: flex;
9983
+ align-items: flex-start;
9984
+ justify-content: space-between;
9985
+ gap: 12px;
9986
+ margin-bottom: 12px;
9987
+ }
9988
+
9989
+ .archive-detail-title {
9990
+ font-weight: 600;
9991
+ font-size: 14px;
9992
+ }
9993
+
9994
+ .archive-detail-subtitle {
9995
+ font-size: 12px;
9996
+ }
9997
+
9998
+ .archive-meta-grid {
9999
+ display: grid;
10000
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
10001
+ gap: 12px 16px;
10002
+ margin-bottom: 16px;
10003
+ }
10004
+
10005
+ .archive-meta-row {
10006
+ background: var(--panel);
10007
+ border: 1px solid var(--border);
10008
+ border-radius: var(--radius);
10009
+ padding: 10px 12px;
10010
+ }
10011
+
10012
+ .archive-meta-value {
10013
+ font-size: 12px;
10014
+ }
10015
+
10016
+ .archive-summary-block {
10017
+ border: 1px solid var(--border);
10018
+ border-radius: var(--radius);
10019
+ padding: 12px;
10020
+ margin-bottom: 12px;
10021
+ background: var(--panel);
10022
+ }
10023
+
10024
+ .archive-summary-block pre {
10025
+ white-space: pre-wrap;
10026
+ font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
10027
+ font-size: 11px;
10028
+ margin: 0;
10029
+ }
10030
+
10031
+ .archive-section-title {
10032
+ font-weight: 600;
10033
+ font-size: 12px;
10034
+ margin-bottom: 8px;
10035
+ cursor: pointer;
10036
+ }
10037
+
10038
+ .archive-file-section {
10039
+ display: flex;
10040
+ flex-direction: column;
10041
+ gap: 12px;
10042
+ min-height: 0;
10043
+ }
10044
+
10045
+ .archive-file-header-row {
10046
+ display: flex;
10047
+ align-items: flex-start;
10048
+ justify-content: space-between;
10049
+ gap: 12px;
10050
+ flex-wrap: wrap;
10051
+ }
10052
+
10053
+ .archive-quick-links {
10054
+ display: flex;
10055
+ flex-wrap: wrap;
10056
+ gap: 6px;
10057
+ }
10058
+
10059
+ .archive-file-path-row {
10060
+ display: flex;
10061
+ align-items: center;
10062
+ justify-content: space-between;
10063
+ gap: 10px;
10064
+ flex-wrap: wrap;
10065
+ }
10066
+
10067
+ .archive-file-grid {
10068
+ flex: 1;
10069
+ min-height: 0;
10070
+ }
10071
+
10072
+ .archive-file-browser {
10073
+ min-height: 0;
10074
+ }
10075
+
10076
+ .archive-file-browser .workspace-file-list {
10077
+ max-height: none;
10078
+ flex: 1;
10079
+ }
10080
+
10081
+ .archive-file-main {
10082
+ min-height: 0;
10083
+ }
10084
+
10085
+ .archive-file-viewer-header {
10086
+ display: flex;
10087
+ align-items: flex-start;
10088
+ justify-content: space-between;
10089
+ gap: 12px;
10090
+ }
10091
+
10092
+ .archive-file-title {
10093
+ font-weight: 600;
10094
+ font-size: 12px;
10095
+ }
10096
+
10097
+ .archive-file-actions {
10098
+ display: flex;
10099
+ align-items: center;
10100
+ gap: 6px;
10101
+ }
10102
+
10103
+ .archive-file-content {
10104
+ flex: 1;
10105
+ min-height: 180px;
10106
+ padding: 10px;
10107
+ border: 1px solid var(--border);
10108
+ border-radius: var(--radius);
10109
+ background: var(--panel);
10110
+ white-space: pre-wrap;
10111
+ font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
10112
+ font-size: 12px;
10113
+ overflow: auto;
10114
+ }
10115
+
10116
+ .archive-file-empty {
10117
+ padding: 12px;
10118
+ border: 1px dashed var(--border);
10119
+ border-radius: var(--radius);
10120
+ background: var(--panel);
10121
+ }
10122
+
10123
+ .archive-empty-state {
10124
+ border: 1px dashed var(--border);
10125
+ border-radius: var(--radius);
10126
+ padding: 24px;
10127
+ text-align: center;
10128
+ color: var(--muted);
10129
+ }
10130
+
10131
+ .archive-empty-title {
10132
+ font-weight: 600;
10133
+ margin-bottom: 6px;
10134
+ color: var(--text);
10135
+ }
10136
+
10137
+ .archive-empty-hint {
10138
+ font-size: 12px;
10139
+ }
10140
+
10141
+ /* Archive Sub-tabs */
10142
+ .archive-subtabs {
10143
+ display: flex;
10144
+ gap: 2px;
10145
+ padding: 2px;
10146
+ background: var(--bg);
10147
+ border: 1px solid var(--border);
10148
+ border-radius: var(--radius);
10149
+ margin-bottom: 16px;
10150
+ flex-shrink: 0;
10151
+ }
10152
+
10153
+ .archive-subtab {
10154
+ flex: 1;
10155
+ padding: 8px 16px;
10156
+ border: none;
10157
+ border-radius: calc(var(--radius) - 2px);
10158
+ background: transparent;
10159
+ color: var(--muted);
10160
+ font-size: 12px;
10161
+ font-weight: 500;
10162
+ cursor: pointer;
10163
+ transition: background 0.12s ease, color 0.12s ease;
10164
+ }
10165
+
10166
+ .archive-subtab:hover {
10167
+ color: var(--text);
10168
+ background: rgba(255, 255, 255, 0.04);
10169
+ }
10170
+
10171
+ .archive-subtab.active {
10172
+ color: var(--accent);
10173
+ background: var(--panel);
10174
+ box-shadow: inset 0 -2px 0 var(--accent), 0 1px 3px rgba(0, 0, 0, 0.2);
10175
+ }
10176
+
10177
+ .archive-tab-content {
10178
+ display: none;
10179
+ flex-direction: column;
10180
+ flex: 1;
10181
+ min-height: 0;
10182
+ overflow: hidden;
10183
+ }
10184
+
10185
+ .archive-tab-content.active {
10186
+ display: flex;
10187
+ }
10188
+
10189
+ /* Snapshot tab content - scrollable */
10190
+ .archive-tab-snapshot {
10191
+ overflow-y: auto;
10192
+ padding-right: 4px;
10193
+ }
10194
+
10195
+ /* Files tab content - fill height (only when active) */
10196
+ .archive-tab-files.active {
10197
+ flex-direction: column;
10198
+ }
10199
+
10200
+ .archive-tab-files .archive-file-section {
10201
+ flex: 1;
10202
+ display: flex;
10203
+ flex-direction: column;
10204
+ min-height: 0;
10205
+ }
10206
+
10207
+ .archive-tab-files .archive-file-grid {
10208
+ flex: 1;
10209
+ min-height: 200px;
10210
+ }
10211
+
10212
+ .archive-tab-files .workspace-grid {
10213
+ height: 100%;
10214
+ }
10215
+
10216
+ .archive-tab-files .workspace-file-browser {
10217
+ max-height: none;
10218
+ height: 100%;
10219
+ }
10220
+
10221
+ .archive-tab-files .workspace-file-list {
10222
+ max-height: none;
10223
+ height: 100%;
10224
+ overflow-y: auto;
10225
+ }
10226
+
10227
+ .archive-tab-files .workspace-main {
10228
+ display: flex;
10229
+ flex-direction: column;
10230
+ min-height: 0;
10231
+ }
10232
+
10233
+ .archive-tab-files .archive-file-content {
10234
+ flex: 1;
10235
+ min-height: 200px;
10236
+ max-height: none;
10237
+ overflow: auto;
10238
+ }
10239
+
10240
+ @media (max-width: 900px) {
10241
+
10242
+ /* Inbox mobile - fill height and scroll */
10243
+ .messages-layout {
10244
+ display: flex;
10245
+ flex-direction: column;
10246
+ gap: 8px;
10247
+ flex: 1;
10248
+ min-height: 0;
10249
+ }
10250
+
10251
+ .messages-sidebar {
10252
+ flex-shrink: 0;
10253
+ }
10254
+
10255
+ .messages-thread-list {
10256
+ max-height: 180px;
9296
10257
  overflow-y: auto;
9297
10258
  }
9298
10259
 
@@ -9321,6 +10282,92 @@ button.loading::after {
9321
10282
  flex-direction: column;
9322
10283
  flex: 1;
9323
10284
  }
10285
+
10286
+ .archive-layout {
10287
+ display: flex;
10288
+ flex-direction: column;
10289
+ gap: 8px;
10290
+ flex: 1;
10291
+ min-height: 0;
10292
+ }
10293
+
10294
+ .archive-list {
10295
+ max-height: 180px;
10296
+ overflow-y: auto;
10297
+ }
10298
+ }
10299
+
10300
+ @media (max-width: 640px) {
10301
+ .messages-layout {
10302
+ display: block;
10303
+ gap: 0;
10304
+ flex: 1;
10305
+ min-height: 0;
10306
+ }
10307
+
10308
+ /* Wider collapse bar on mobile for easier touch */
10309
+ .messages-collapse-bar {
10310
+ width: 6px;
10311
+ }
10312
+
10313
+ .messages-collapse-bar:hover {
10314
+ width: 8px;
10315
+ }
10316
+
10317
+ .messages-sidebar {
10318
+ display: block;
10319
+ height: 100%;
10320
+ }
10321
+
10322
+ .messages-main {
10323
+ display: none;
10324
+ height: 100%;
10325
+ }
10326
+
10327
+ .messages-layout.viewing-detail .messages-sidebar {
10328
+ display: none;
10329
+ }
10330
+
10331
+ .messages-layout.viewing-detail .messages-main {
10332
+ display: flex;
10333
+ flex-direction: column;
10334
+ }
10335
+
10336
+ .messages-detail-header {
10337
+ display: flex;
10338
+ align-items: center;
10339
+ padding: 8px 0;
10340
+ border-bottom: 1px solid var(--border);
10341
+ margin-bottom: 8px;
10342
+ gap: 8px;
10343
+ }
10344
+
10345
+ .messages-back-btn {
10346
+ min-height: 44px;
10347
+ padding: 8px 16px;
10348
+ font-size: 12px;
10349
+ flex-shrink: 0;
10350
+ }
10351
+
10352
+ .messages-detail-meta {
10353
+ flex: 1;
10354
+ justify-content: flex-end;
10355
+ }
10356
+
10357
+ /* Hide footer on mobile since info is in header */
10358
+ .messages-thread-footer {
10359
+ display: none;
10360
+ }
10361
+
10362
+ .messages-thread-list {
10363
+ max-height: none;
10364
+ height: calc(100vh - 120px);
10365
+ }
10366
+
10367
+ .messages-thread-detail {
10368
+ flex: 1;
10369
+ min-height: 0;
10370
+ }
9324
10371
  }
9325
10372
 
9326
10373
  /* ===== Ticket Editor Modal - Full Screen ===== */
@@ -9368,6 +10415,25 @@ button.loading::after {
9368
10415
  flex-shrink: 0;
9369
10416
  }
9370
10417
 
10418
+ .ticket-header-actions .ticket-nav-btn {
10419
+ width: 28px;
10420
+ height: 28px;
10421
+ min-width: 28px;
10422
+ min-height: 28px;
10423
+ padding: 0;
10424
+ font-size: 14px;
10425
+ line-height: 1;
10426
+ border-radius: var(--radius);
10427
+ }
10428
+
10429
+ .ticket-header-actions .ticket-nav-btn:disabled {
10430
+ opacity: 0.35;
10431
+ cursor: not-allowed;
10432
+ color: var(--muted);
10433
+ background: transparent;
10434
+ border-color: transparent;
10435
+ }
10436
+
9371
10437
  .ticket-header-row .ticket-fm-select {
9372
10438
  padding: 5px 8px;
9373
10439
  font-size: 11px;
@@ -9563,19 +10629,39 @@ button.loading::after {
9563
10629
  }
9564
10630
 
9565
10631
  @media (max-width: 600px) {
10632
+ .ticket-editor-header {
10633
+ display: flex;
10634
+ flex-direction: column;
10635
+ gap: 6px;
10636
+ }
10637
+
9566
10638
  .ticket-header-row {
9567
- flex-wrap: wrap;
9568
- gap: 4px;
10639
+ display: grid;
10640
+ grid-template-columns: repeat(3, minmax(0, 1fr));
10641
+ gap: 6px;
10642
+ align-items: center;
10643
+ }
10644
+
10645
+ .ticket-header-row .ticket-fm-select {
10646
+ width: 100%;
9569
10647
  }
9570
10648
 
9571
10649
  .ticket-header-row .ticket-fm-input {
10650
+ grid-column: 1 / -1;
9572
10651
  order: 10;
9573
10652
  width: 100%;
9574
- flex: none;
10653
+ }
10654
+
10655
+ .ticket-header-actions {
10656
+ grid-column: 1 / -1;
10657
+ order: 20;
10658
+ width: 100%;
10659
+ justify-content: space-between;
10660
+ gap: 8px;
9575
10661
  }
9576
10662
 
9577
10663
  .ticket-header-row #ticket-editor-close {
9578
- order: 5;
10664
+ order: 30;
9579
10665
  }
9580
10666
  }
9581
10667
 
@@ -10135,3 +11221,189 @@ button.loading::after {
10135
11221
  font-size: 10px;
10136
11222
  }
10137
11223
  }
11224
+
11225
+ /* ===== Hamburger Menu ===== */
11226
+ .hamburger-wrapper {
11227
+ position: relative;
11228
+ display: flex;
11229
+ align-items: center;
11230
+ z-index: 2002;
11231
+ flex-shrink: 0;
11232
+ }
11233
+
11234
+ .hamburger-btn {
11235
+ display: flex;
11236
+ align-items: center;
11237
+ justify-content: center;
11238
+ width: 36px;
11239
+ height: 32px;
11240
+ padding: 0;
11241
+ border: 1px solid var(--border);
11242
+ border-radius: var(--radius);
11243
+ background: var(--panel);
11244
+ color: var(--muted);
11245
+ cursor: pointer;
11246
+ transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
11247
+ /* Ensure entire button is clickable */
11248
+ position: relative;
11249
+ overflow: hidden;
11250
+ z-index: 2001;
11251
+ }
11252
+
11253
+ .hamburger-btn:hover {
11254
+ color: var(--text);
11255
+ border-color: rgba(255, 255, 255, 0.2);
11256
+ }
11257
+
11258
+ .hamburger-btn:active,
11259
+ .hamburger-btn.active {
11260
+ color: var(--accent);
11261
+ border-color: rgba(108, 245, 216, 0.4);
11262
+ background: rgba(108, 245, 216, 0.08);
11263
+ }
11264
+
11265
+ .hamburger-icon {
11266
+ display: flex;
11267
+ flex-direction: column;
11268
+ gap: 3px;
11269
+ width: 14px;
11270
+ pointer-events: none;
11271
+ }
11272
+
11273
+ .hamburger-icon span {
11274
+ display: block;
11275
+ height: 2px;
11276
+ width: 100%;
11277
+ background: currentColor;
11278
+ border-radius: 1px;
11279
+ pointer-events: none;
11280
+ }
11281
+
11282
+ .hamburger-menu {
11283
+ position: fixed;
11284
+ top: 50px;
11285
+ right: 8px;
11286
+ min-width: 160px;
11287
+ background: var(--panel);
11288
+ border: 1px solid var(--border);
11289
+ border-radius: var(--radius);
11290
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
11291
+ padding: 4px;
11292
+ z-index: 3000;
11293
+ opacity: 0;
11294
+ visibility: hidden;
11295
+ transform: translateY(-5px);
11296
+ transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s ease;
11297
+ pointer-events: none;
11298
+ }
11299
+
11300
+ .hamburger-menu.open {
11301
+ opacity: 1;
11302
+ visibility: visible;
11303
+ transform: translateY(0);
11304
+ pointer-events: auto;
11305
+ }
11306
+
11307
+ .hamburger-item {
11308
+ display: flex;
11309
+ align-items: center;
11310
+ gap: 10px;
11311
+ width: 100%;
11312
+ padding: 10px 12px;
11313
+ border: none;
11314
+ border-radius: 6px;
11315
+ background: transparent;
11316
+ color: var(--text);
11317
+ font-size: 13px;
11318
+ text-align: left;
11319
+ cursor: pointer;
11320
+ transition: background 0.12s ease, color 0.12s ease;
11321
+ }
11322
+
11323
+ .hamburger-item:hover {
11324
+ background: rgba(255, 255, 255, 0.06);
11325
+ }
11326
+
11327
+ .hamburger-item:active {
11328
+ background: rgba(108, 245, 216, 0.12);
11329
+ }
11330
+
11331
+ .hamburger-item.active {
11332
+ color: var(--accent);
11333
+ background: rgba(108, 245, 216, 0.1);
11334
+ }
11335
+
11336
+ .hamburger-item-icon {
11337
+ width: 16px;
11338
+ text-align: center;
11339
+ font-size: 14px;
11340
+ opacity: 0.7;
11341
+ }
11342
+
11343
+ .hamburger-divider {
11344
+ height: 1px;
11345
+ background: var(--border);
11346
+ margin: 4px 8px;
11347
+ }
11348
+
11349
+ /* Mobile hamburger menu - bottom sheet style */
11350
+ @media (max-width: 640px) {
11351
+ .hamburger-wrapper {
11352
+ position: relative;
11353
+ z-index: 2002;
11354
+ }
11355
+
11356
+ .hamburger-btn {
11357
+ min-height: 48px;
11358
+ min-width: 48px;
11359
+ width: auto;
11360
+ height: auto;
11361
+ border: none;
11362
+ border-radius: 0;
11363
+ background: transparent;
11364
+ }
11365
+
11366
+ .hamburger-btn.active {
11367
+ background: rgba(108, 245, 216, 0.12);
11368
+ border-top: 2px solid var(--accent);
11369
+ }
11370
+
11371
+ .hamburger-menu {
11372
+ position: fixed;
11373
+ bottom: calc(60px + env(safe-area-inset-bottom, 0px));
11374
+ left: 8px;
11375
+ right: 8px;
11376
+ top: auto;
11377
+ min-width: auto;
11378
+ max-height: 60vh;
11379
+ overflow-y: auto;
11380
+ border-radius: 12px;
11381
+ box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.5);
11382
+ transform: translateY(16px);
11383
+ }
11384
+
11385
+ .hamburger-menu.open {
11386
+ transform: translateY(0);
11387
+ }
11388
+
11389
+ .hamburger-item {
11390
+ padding: 14px 16px;
11391
+ font-size: 14px;
11392
+ min-height: 48px;
11393
+ }
11394
+
11395
+ .hamburger-backdrop {
11396
+ position: fixed;
11397
+ inset: 0;
11398
+ background: rgba(0, 0, 0, 0.5);
11399
+ z-index: 2999;
11400
+ opacity: 0;
11401
+ visibility: hidden;
11402
+ transition: opacity 0.15s ease, visibility 0.15s ease;
11403
+ }
11404
+
11405
+ .hamburger-backdrop.open {
11406
+ opacity: 1;
11407
+ visibility: visible;
11408
+ }
11409
+ }