@bobfrankston/rmfmail 1.0.467

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 (330) hide show
  1. package/README.md +429 -0
  2. package/bin/build-icon-ico.js +283 -0
  3. package/bin/lean-accounts.js +172 -0
  4. package/bin/mailx.js +1580 -0
  5. package/bin/mailx.js.map +1 -0
  6. package/bin/mailx.ts +1549 -0
  7. package/bin/postinstall.js +39 -0
  8. package/bin/postinstall.js.map +1 -0
  9. package/bin/postinstall.ts +41 -0
  10. package/bin/tsconfig.json +10 -0
  11. package/client/.gitattributes +10 -0
  12. package/client/.msger-window.json +1 -0
  13. package/client/android.html +226 -0
  14. package/client/app.js +3400 -0
  15. package/client/app.js.map +1 -0
  16. package/client/app.ts +3190 -0
  17. package/client/components/address-book.js +199 -0
  18. package/client/components/address-book.js.map +1 -0
  19. package/client/components/address-book.ts +204 -0
  20. package/client/components/alarms.js +299 -0
  21. package/client/components/alarms.js.map +1 -0
  22. package/client/components/alarms.ts +276 -0
  23. package/client/components/calendar-sidebar.js +508 -0
  24. package/client/components/calendar-sidebar.js.map +1 -0
  25. package/client/components/calendar-sidebar.ts +474 -0
  26. package/client/components/calendar.js +217 -0
  27. package/client/components/calendar.js.map +1 -0
  28. package/client/components/calendar.ts +211 -0
  29. package/client/components/context-menu.js +80 -0
  30. package/client/components/context-menu.js.map +1 -0
  31. package/client/components/context-menu.ts +95 -0
  32. package/client/components/folder-picker.js +119 -0
  33. package/client/components/folder-picker.js.map +1 -0
  34. package/client/components/folder-picker.ts +127 -0
  35. package/client/components/folder-tree.js +1093 -0
  36. package/client/components/folder-tree.js.map +1 -0
  37. package/client/components/folder-tree.ts +1069 -0
  38. package/client/components/message-list.js +1140 -0
  39. package/client/components/message-list.js.map +1 -0
  40. package/client/components/message-list.ts +1129 -0
  41. package/client/components/message-viewer.js +1291 -0
  42. package/client/components/message-viewer.js.map +1 -0
  43. package/client/components/message-viewer.ts +1257 -0
  44. package/client/components/outbox-view.js +104 -0
  45. package/client/components/outbox-view.js.map +1 -0
  46. package/client/components/outbox-view.ts +102 -0
  47. package/client/components/tasks.js +261 -0
  48. package/client/components/tasks.js.map +1 -0
  49. package/client/components/tasks.ts +234 -0
  50. package/client/compose/compose.css +560 -0
  51. package/client/compose/compose.html +52 -0
  52. package/client/compose/compose.js +1289 -0
  53. package/client/compose/compose.js.map +1 -0
  54. package/client/compose/compose.ts +1231 -0
  55. package/client/compose/editor.js +616 -0
  56. package/client/compose/editor.js.map +1 -0
  57. package/client/compose/editor.ts +599 -0
  58. package/client/compose/ghost-text.js +122 -0
  59. package/client/compose/ghost-text.js.map +1 -0
  60. package/client/compose/ghost-text.ts +140 -0
  61. package/client/favicon.svg +11 -0
  62. package/client/icon.ico +0 -0
  63. package/client/icon.png +0 -0
  64. package/client/index.html +230 -0
  65. package/client/lib/android-bootstrap.js +9 -0
  66. package/client/lib/android-bootstrap.js.map +1 -0
  67. package/client/lib/android-bootstrap.ts +9 -0
  68. package/client/lib/api-client.js +378 -0
  69. package/client/lib/api-client.js.map +1 -0
  70. package/client/lib/api-client.ts +439 -0
  71. package/client/lib/local-service.js +603 -0
  72. package/client/lib/local-service.js.map +1 -0
  73. package/client/lib/local-service.ts +646 -0
  74. package/client/lib/local-store.js +214 -0
  75. package/client/lib/local-store.js.map +1 -0
  76. package/client/lib/local-store.ts +283 -0
  77. package/client/lib/mailxapi.js +304 -0
  78. package/client/lib/message-state.js +132 -0
  79. package/client/lib/message-state.js.map +1 -0
  80. package/client/lib/message-state.ts +160 -0
  81. package/client/package.json +16 -0
  82. package/client/styles/components.css +2049 -0
  83. package/client/styles/layout.css +332 -0
  84. package/client/styles/variables.css +85 -0
  85. package/client/tsconfig.json +19 -0
  86. package/package.json +124 -0
  87. package/packages/mailx-api/.gitattributes +10 -0
  88. package/packages/mailx-api/index.d.ts +10 -0
  89. package/packages/mailx-api/index.d.ts.map +1 -0
  90. package/packages/mailx-api/index.js +322 -0
  91. package/packages/mailx-api/index.js.map +1 -0
  92. package/packages/mailx-api/index.ts +283 -0
  93. package/packages/mailx-api/package.json +27 -0
  94. package/packages/mailx-api/tsconfig.json +9 -0
  95. package/packages/mailx-api/tsconfig.tsbuildinfo +1 -0
  96. package/packages/mailx-compose/.gitattributes +10 -0
  97. package/packages/mailx-compose/index.d.ts +21 -0
  98. package/packages/mailx-compose/index.d.ts.map +1 -0
  99. package/packages/mailx-compose/index.js +61 -0
  100. package/packages/mailx-compose/index.js.map +1 -0
  101. package/packages/mailx-compose/index.ts +85 -0
  102. package/packages/mailx-compose/package.json +18 -0
  103. package/packages/mailx-compose/tsconfig.json +9 -0
  104. package/packages/mailx-core/index.d.ts +139 -0
  105. package/packages/mailx-core/index.d.ts.map +1 -0
  106. package/packages/mailx-core/index.js +403 -0
  107. package/packages/mailx-core/index.js.map +1 -0
  108. package/packages/mailx-core/index.ts +424 -0
  109. package/packages/mailx-core/ipc.d.ts +13 -0
  110. package/packages/mailx-core/ipc.d.ts.map +1 -0
  111. package/packages/mailx-core/ipc.js +56 -0
  112. package/packages/mailx-core/ipc.js.map +1 -0
  113. package/packages/mailx-core/ipc.ts +62 -0
  114. package/packages/mailx-core/package.json +18 -0
  115. package/packages/mailx-core/tsconfig.json +9 -0
  116. package/packages/mailx-host/.gitattributes +10 -0
  117. package/packages/mailx-host/index.d.ts +21 -0
  118. package/packages/mailx-host/index.d.ts.map +1 -0
  119. package/packages/mailx-host/index.js +29 -0
  120. package/packages/mailx-host/index.js.map +1 -0
  121. package/packages/mailx-host/index.ts +38 -0
  122. package/packages/mailx-host/package.json +23 -0
  123. package/packages/mailx-host/tsconfig.json +9 -0
  124. package/packages/mailx-host/types-shim.d.ts +14 -0
  125. package/packages/mailx-imap/.gitattributes +10 -0
  126. package/packages/mailx-imap/index.d.ts +442 -0
  127. package/packages/mailx-imap/index.d.ts.map +1 -0
  128. package/packages/mailx-imap/index.js +3684 -0
  129. package/packages/mailx-imap/index.js.map +1 -0
  130. package/packages/mailx-imap/index.ts +3652 -0
  131. package/packages/mailx-imap/package-lock.json +131 -0
  132. package/packages/mailx-imap/package.json +28 -0
  133. package/packages/mailx-imap/providers/gmail-api.d.ts +8 -0
  134. package/packages/mailx-imap/providers/gmail-api.d.ts.map +1 -0
  135. package/packages/mailx-imap/providers/gmail-api.js +8 -0
  136. package/packages/mailx-imap/providers/gmail-api.js.map +1 -0
  137. package/packages/mailx-imap/providers/gmail-api.ts +8 -0
  138. package/packages/mailx-imap/providers/outlook-api.ts +7 -0
  139. package/packages/mailx-imap/providers/types.d.ts +9 -0
  140. package/packages/mailx-imap/providers/types.d.ts.map +1 -0
  141. package/packages/mailx-imap/providers/types.js +9 -0
  142. package/packages/mailx-imap/providers/types.js.map +1 -0
  143. package/packages/mailx-imap/providers/types.ts +9 -0
  144. package/packages/mailx-imap/tsconfig.json +9 -0
  145. package/packages/mailx-imap/tsconfig.tsbuildinfo +1 -0
  146. package/packages/mailx-send/.gitattributes +10 -0
  147. package/packages/mailx-send/README.md +217 -0
  148. package/packages/mailx-send/cli-queue.d.ts +11 -0
  149. package/packages/mailx-send/cli-queue.d.ts.map +1 -0
  150. package/packages/mailx-send/cli-queue.js +59 -0
  151. package/packages/mailx-send/cli-queue.js.map +1 -0
  152. package/packages/mailx-send/cli-queue.ts +62 -0
  153. package/packages/mailx-send/cli-send.d.ts +17 -0
  154. package/packages/mailx-send/cli-send.d.ts.map +1 -0
  155. package/packages/mailx-send/cli-send.js +75 -0
  156. package/packages/mailx-send/cli-send.js.map +1 -0
  157. package/packages/mailx-send/cli-send.ts +83 -0
  158. package/packages/mailx-send/cli.d.ts +22 -0
  159. package/packages/mailx-send/cli.d.ts.map +1 -0
  160. package/packages/mailx-send/cli.js +115 -0
  161. package/packages/mailx-send/cli.js.map +1 -0
  162. package/packages/mailx-send/cli.ts +126 -0
  163. package/packages/mailx-send/index.d.ts +77 -0
  164. package/packages/mailx-send/index.d.ts.map +1 -0
  165. package/packages/mailx-send/index.js +264 -0
  166. package/packages/mailx-send/index.js.map +1 -0
  167. package/packages/mailx-send/index.ts +333 -0
  168. package/packages/mailx-send/mailsend/README.md +133 -0
  169. package/packages/mailx-send/mailsend/cli.d.ts +12 -0
  170. package/packages/mailx-send/mailsend/cli.d.ts.map +1 -0
  171. package/packages/mailx-send/mailsend/cli.js +70 -0
  172. package/packages/mailx-send/mailsend/cli.js.map +1 -0
  173. package/packages/mailx-send/mailsend/cli.ts +81 -0
  174. package/packages/mailx-send/mailsend/index.d.ts +77 -0
  175. package/packages/mailx-send/mailsend/index.d.ts.map +1 -0
  176. package/packages/mailx-send/mailsend/index.js +264 -0
  177. package/packages/mailx-send/mailsend/index.js.map +1 -0
  178. package/packages/mailx-send/mailsend/index.ts +333 -0
  179. package/packages/mailx-send/mailsend/package-lock.json +65 -0
  180. package/packages/mailx-send/mailsend/package.json +26 -0
  181. package/packages/mailx-send/mailsend/tsconfig.json +21 -0
  182. package/packages/mailx-send/package-lock.json +65 -0
  183. package/packages/mailx-send/package.json +37 -0
  184. package/packages/mailx-send/tsconfig.json +21 -0
  185. package/packages/mailx-server/.gitattributes +10 -0
  186. package/packages/mailx-server/index.d.ts +8 -0
  187. package/packages/mailx-server/index.d.ts.map +1 -0
  188. package/packages/mailx-server/index.js +397 -0
  189. package/packages/mailx-server/index.js.map +1 -0
  190. package/packages/mailx-server/index.ts +429 -0
  191. package/packages/mailx-server/package.json +28 -0
  192. package/packages/mailx-server/tsconfig.json +9 -0
  193. package/packages/mailx-server/tsconfig.tsbuildinfo +1 -0
  194. package/packages/mailx-service/google-sync.d.ts +96 -0
  195. package/packages/mailx-service/google-sync.d.ts.map +1 -0
  196. package/packages/mailx-service/google-sync.js +153 -0
  197. package/packages/mailx-service/google-sync.js.map +1 -0
  198. package/packages/mailx-service/google-sync.ts +238 -0
  199. package/packages/mailx-service/index.d.ts +366 -0
  200. package/packages/mailx-service/index.d.ts.map +1 -0
  201. package/packages/mailx-service/index.js +2589 -0
  202. package/packages/mailx-service/index.js.map +1 -0
  203. package/packages/mailx-service/index.ts +2512 -0
  204. package/packages/mailx-service/jsonrpc.d.ts +25 -0
  205. package/packages/mailx-service/jsonrpc.d.ts.map +1 -0
  206. package/packages/mailx-service/jsonrpc.js +238 -0
  207. package/packages/mailx-service/jsonrpc.js.map +1 -0
  208. package/packages/mailx-service/jsonrpc.ts +268 -0
  209. package/packages/mailx-service/package.json +22 -0
  210. package/packages/mailx-service/tsconfig.json +9 -0
  211. package/packages/mailx-settings/.gitattributes +10 -0
  212. package/packages/mailx-settings/cloud.d.ts +47 -0
  213. package/packages/mailx-settings/cloud.d.ts.map +1 -0
  214. package/packages/mailx-settings/cloud.js +408 -0
  215. package/packages/mailx-settings/cloud.js.map +1 -0
  216. package/packages/mailx-settings/cloud.ts +393 -0
  217. package/packages/mailx-settings/index.d.ts +140 -0
  218. package/packages/mailx-settings/index.d.ts.map +1 -0
  219. package/packages/mailx-settings/index.js +872 -0
  220. package/packages/mailx-settings/index.js.map +1 -0
  221. package/packages/mailx-settings/index.ts +908 -0
  222. package/packages/mailx-settings/package.json +20 -0
  223. package/packages/mailx-settings/tsconfig.json +9 -0
  224. package/packages/mailx-settings/tsconfig.tsbuildinfo +1 -0
  225. package/packages/mailx-store/.gitattributes +10 -0
  226. package/packages/mailx-store/db.d.ts +346 -0
  227. package/packages/mailx-store/db.d.ts.map +1 -0
  228. package/packages/mailx-store/db.js +1796 -0
  229. package/packages/mailx-store/db.js.map +1 -0
  230. package/packages/mailx-store/db.ts +2007 -0
  231. package/packages/mailx-store/file-store.d.ts +36 -0
  232. package/packages/mailx-store/file-store.d.ts.map +1 -0
  233. package/packages/mailx-store/file-store.js +80 -0
  234. package/packages/mailx-store/file-store.js.map +1 -0
  235. package/packages/mailx-store/file-store.ts +82 -0
  236. package/packages/mailx-store/index.d.ts +7 -0
  237. package/packages/mailx-store/index.d.ts.map +1 -0
  238. package/packages/mailx-store/index.js +7 -0
  239. package/packages/mailx-store/index.js.map +1 -0
  240. package/packages/mailx-store/index.ts +7 -0
  241. package/packages/mailx-store/package.json +19 -0
  242. package/packages/mailx-store/tsconfig.json +9 -0
  243. package/packages/mailx-store/tsconfig.tsbuildinfo +1 -0
  244. package/packages/mailx-store-web/android-bootstrap.d.ts +16 -0
  245. package/packages/mailx-store-web/android-bootstrap.d.ts.map +1 -0
  246. package/packages/mailx-store-web/android-bootstrap.js +1247 -0
  247. package/packages/mailx-store-web/android-bootstrap.js.map +1 -0
  248. package/packages/mailx-store-web/android-bootstrap.ts +1262 -0
  249. package/packages/mailx-store-web/db.d.ts +132 -0
  250. package/packages/mailx-store-web/db.d.ts.map +1 -0
  251. package/packages/mailx-store-web/db.js +642 -0
  252. package/packages/mailx-store-web/db.js.map +1 -0
  253. package/packages/mailx-store-web/db.ts +756 -0
  254. package/packages/mailx-store-web/gmail-api-web.d.ts +11 -0
  255. package/packages/mailx-store-web/gmail-api-web.d.ts.map +1 -0
  256. package/packages/mailx-store-web/gmail-api-web.js +11 -0
  257. package/packages/mailx-store-web/gmail-api-web.js.map +1 -0
  258. package/packages/mailx-store-web/gmail-api-web.ts +11 -0
  259. package/packages/mailx-store-web/imap-web-provider.d.ts +33 -0
  260. package/packages/mailx-store-web/imap-web-provider.d.ts.map +1 -0
  261. package/packages/mailx-store-web/imap-web-provider.js +140 -0
  262. package/packages/mailx-store-web/imap-web-provider.js.map +1 -0
  263. package/packages/mailx-store-web/imap-web-provider.ts +156 -0
  264. package/packages/mailx-store-web/index.d.ts +10 -0
  265. package/packages/mailx-store-web/index.d.ts.map +1 -0
  266. package/packages/mailx-store-web/index.js +10 -0
  267. package/packages/mailx-store-web/index.js.map +1 -0
  268. package/packages/mailx-store-web/index.ts +10 -0
  269. package/packages/mailx-store-web/main-thread-host.d.ts +15 -0
  270. package/packages/mailx-store-web/main-thread-host.d.ts.map +1 -0
  271. package/packages/mailx-store-web/main-thread-host.js +292 -0
  272. package/packages/mailx-store-web/main-thread-host.js.map +1 -0
  273. package/packages/mailx-store-web/main-thread-host.ts +322 -0
  274. package/packages/mailx-store-web/package.json +23 -0
  275. package/packages/mailx-store-web/provider-types.d.ts +7 -0
  276. package/packages/mailx-store-web/provider-types.d.ts.map +1 -0
  277. package/packages/mailx-store-web/provider-types.js +7 -0
  278. package/packages/mailx-store-web/provider-types.js.map +1 -0
  279. package/packages/mailx-store-web/provider-types.ts +7 -0
  280. package/packages/mailx-store-web/sql-wasm-esm.js +10 -0
  281. package/packages/mailx-store-web/sql.js.d.ts +29 -0
  282. package/packages/mailx-store-web/sync-manager.d.ts +68 -0
  283. package/packages/mailx-store-web/sync-manager.d.ts.map +1 -0
  284. package/packages/mailx-store-web/sync-manager.js +506 -0
  285. package/packages/mailx-store-web/sync-manager.js.map +1 -0
  286. package/packages/mailx-store-web/sync-manager.ts +508 -0
  287. package/packages/mailx-store-web/tsconfig.json +10 -0
  288. package/packages/mailx-store-web/web-jsonrpc.d.ts +20 -0
  289. package/packages/mailx-store-web/web-jsonrpc.d.ts.map +1 -0
  290. package/packages/mailx-store-web/web-jsonrpc.js +102 -0
  291. package/packages/mailx-store-web/web-jsonrpc.js.map +1 -0
  292. package/packages/mailx-store-web/web-jsonrpc.ts +116 -0
  293. package/packages/mailx-store-web/web-message-store.d.ts +16 -0
  294. package/packages/mailx-store-web/web-message-store.d.ts.map +1 -0
  295. package/packages/mailx-store-web/web-message-store.js +89 -0
  296. package/packages/mailx-store-web/web-message-store.js.map +1 -0
  297. package/packages/mailx-store-web/web-message-store.ts +97 -0
  298. package/packages/mailx-store-web/web-service.d.ts +111 -0
  299. package/packages/mailx-store-web/web-service.d.ts.map +1 -0
  300. package/packages/mailx-store-web/web-service.js +542 -0
  301. package/packages/mailx-store-web/web-service.js.map +1 -0
  302. package/packages/mailx-store-web/web-service.ts +616 -0
  303. package/packages/mailx-store-web/web-settings.d.ts +83 -0
  304. package/packages/mailx-store-web/web-settings.d.ts.map +1 -0
  305. package/packages/mailx-store-web/web-settings.js +491 -0
  306. package/packages/mailx-store-web/web-settings.js.map +1 -0
  307. package/packages/mailx-store-web/web-settings.ts +522 -0
  308. package/packages/mailx-store-web/worker-bundle.js +6838 -0
  309. package/packages/mailx-store-web/worker-entry.d.ts +8 -0
  310. package/packages/mailx-store-web/worker-entry.d.ts.map +1 -0
  311. package/packages/mailx-store-web/worker-entry.js +187 -0
  312. package/packages/mailx-store-web/worker-entry.js.map +1 -0
  313. package/packages/mailx-store-web/worker-entry.ts +215 -0
  314. package/packages/mailx-store-web/worker-tcp-transport.d.ts +28 -0
  315. package/packages/mailx-store-web/worker-tcp-transport.d.ts.map +1 -0
  316. package/packages/mailx-store-web/worker-tcp-transport.js +98 -0
  317. package/packages/mailx-store-web/worker-tcp-transport.js.map +1 -0
  318. package/packages/mailx-store-web/worker-tcp-transport.ts +101 -0
  319. package/packages/mailx-types/.gitattributes +10 -0
  320. package/packages/mailx-types/index.d.ts +319 -0
  321. package/packages/mailx-types/index.d.ts.map +1 -0
  322. package/packages/mailx-types/index.js +243 -0
  323. package/packages/mailx-types/index.js.map +1 -0
  324. package/packages/mailx-types/index.ts +498 -0
  325. package/packages/mailx-types/package.json +16 -0
  326. package/packages/mailx-types/tsconfig.json +9 -0
  327. package/packages/mailx-types/tsconfig.tsbuildinfo +1 -0
  328. package/todo.json +13 -0
  329. package/tsconfig.base.json +31 -0
  330. package/tsconfig.json +9 -0
@@ -0,0 +1,2049 @@
1
+ /* mailx component styles */
2
+
3
+ /* ── Alert Banner ── */
4
+ .alert-banner {
5
+ display: flex; align-items: center; gap: var(--gap-sm);
6
+ padding: var(--gap-xs) var(--gap-md);
7
+ background: oklch(0.45 0.15 25); color: #fff;
8
+ font-size: var(--font-size-sm); font-weight: 500;
9
+ grid-area: alert;
10
+ }
11
+ .alert-banner[hidden] { display: none; }
12
+ .alert-banner #alert-text { flex: 1; }
13
+ .alert-dismiss { background: none; border: none; color: #fff; font-size: 1.2em; cursor: pointer; padding: 0 var(--gap-xs); opacity: 0.7; }
14
+ .alert-dismiss:hover { opacity: 1; }
15
+
16
+ /* ── Context Menu ── */
17
+
18
+ .ctx-menu {
19
+ position: fixed;
20
+ z-index: 1000;
21
+ background: var(--color-bg-surface);
22
+ border: 1px solid var(--color-border);
23
+ border-radius: var(--radius-md);
24
+ padding: var(--gap-xs) 0;
25
+ min-width: 180px;
26
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
27
+ }
28
+
29
+ .ctx-item {
30
+ padding: var(--gap-xs) var(--gap-md);
31
+ cursor: pointer;
32
+ font-size: var(--font-size-sm);
33
+ white-space: nowrap;
34
+ }
35
+
36
+ .ctx-item:hover { background: var(--color-bg-hover); }
37
+ .ctx-disabled { opacity: 0.4; cursor: default; }
38
+ .ctx-disabled:hover { background: transparent; }
39
+ .ctx-sep { height: 1px; background: var(--color-border); margin: var(--gap-xs) 0; }
40
+
41
+ /* ── Toolbar ── */
42
+
43
+ .toolbar {
44
+ display: flex;
45
+ align-items: center;
46
+ justify-content: space-between;
47
+ padding: 0 var(--gap-sm);
48
+ background: var(--color-brand);
49
+ border-bottom: 1px solid var(--color-border);
50
+ gap: var(--gap-sm);
51
+
52
+ .toolbar-left, .toolbar-right {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: var(--gap-xs);
56
+ }
57
+ }
58
+
59
+ .tb-btn {
60
+ display: inline-flex;
61
+ align-items: center;
62
+ gap: var(--gap-xs);
63
+ padding: var(--gap-xs) var(--gap-sm);
64
+ border: none;
65
+ border-radius: var(--radius-sm);
66
+ background: transparent;
67
+ color: var(--color-brand-dark);
68
+ font-size: var(--font-size-sm);
69
+ font-weight: 700;
70
+ cursor: pointer;
71
+ white-space: nowrap;
72
+
73
+ &:hover { background: var(--color-bg-hover); }
74
+ &:disabled { opacity: 0.4; cursor: default; }
75
+ &:disabled:hover { background: transparent; }
76
+ }
77
+
78
+ .tb-icon { font-size: 1.1em; }
79
+ .tb-btn.syncing .tb-icon { animation: spin 1s linear infinite; }
80
+ @keyframes spin { to { transform: rotate(360deg); } }
81
+ .app-version { font-size: var(--font-size-sm); color: var(--color-text); opacity: 0.7; }
82
+
83
+ .tb-menu { position: relative; display: inline-block; }
84
+ .tb-menu-dropdown {
85
+ position: absolute;
86
+ top: 100%;
87
+ left: 0;
88
+ background: var(--color-bg-surface);
89
+ border: 1px solid var(--color-border);
90
+ border-radius: var(--radius-md);
91
+ padding: var(--gap-xs) 0;
92
+ z-index: 100;
93
+ min-width: 160px;
94
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
95
+ }
96
+ .tb-menu-item {
97
+ display: flex;
98
+ align-items: center;
99
+ gap: var(--gap-sm);
100
+ padding: var(--gap-xs) var(--gap-md);
101
+ font-size: var(--font-size-sm);
102
+ cursor: pointer;
103
+ white-space: nowrap;
104
+ }
105
+ .tb-menu-item:hover { background: var(--color-bg-hover); }
106
+ .tb-menu-item input[type="checkbox"] { accent-color: var(--color-accent); }
107
+ button.tb-menu-item { background: none; border: none; color: inherit; width: 100%; text-align: left; }
108
+ .tb-menu-sep { border: none; border-top: 1px solid var(--color-border); margin: var(--gap-xs) 0; }
109
+ .tb-menu-hint { display: block; padding: var(--gap-xs) var(--gap-md); font-size: 0.75rem; color: var(--color-text-muted); }
110
+ .tb-menu-label { display: block; padding: var(--gap-xs) var(--gap-md); font-size: 0.75rem; font-weight: 600; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.05em; }
111
+ .tb-menu-item input[type="radio"] { accent-color: var(--color-accent); }
112
+ .tb-sep { width: 1px; height: 1.2rem; background: var(--color-border); margin: 0 var(--gap-xs); }
113
+
114
+ .search-bar {
115
+ display: flex;
116
+ align-items: center;
117
+ gap: 0;
118
+ }
119
+
120
+ #search-scope {
121
+ padding: var(--gap-xs) var(--gap-xs);
122
+ border: 1px solid var(--color-border);
123
+ border-radius: var(--radius-md) 0 0 var(--radius-md);
124
+ background: var(--color-bg-surface);
125
+ color: var(--color-text);
126
+ font-size: var(--font-size-sm);
127
+ border-right: none;
128
+ cursor: pointer;
129
+ }
130
+
131
+ .ml-search {
132
+ grid-column: 1 / -1;
133
+ border-bottom: 1px solid var(--color-border);
134
+ padding: 2px var(--gap-xs);
135
+ background: var(--color-bg-surface);
136
+ }
137
+
138
+ #search-input {
139
+ padding: var(--gap-xs) var(--gap-sm);
140
+ border: 1px solid var(--color-border);
141
+ border-radius: 0 var(--radius-md) var(--radius-md) 0;
142
+ background: var(--color-bg);
143
+ color: var(--color-text);
144
+ font-size: var(--font-size-sm);
145
+ flex: 1;
146
+
147
+ &::placeholder { color: var(--color-text-muted); }
148
+ &:focus { outline: 1px solid var(--color-accent); border-color: var(--color-accent); }
149
+ }
150
+
151
+ /* ── Folder Tree ── */
152
+
153
+ .folder-tree {
154
+ overflow-y: auto;
155
+ background: var(--color-bg-surface);
156
+ border-right: 1px solid var(--color-border);
157
+ padding: var(--gap-sm) 0;
158
+ }
159
+
160
+ .ft-account {
161
+ margin-bottom: var(--gap-sm);
162
+ }
163
+
164
+ .ft-account-header {
165
+ display: flex;
166
+ align-items: center;
167
+ gap: var(--gap-xs);
168
+ padding: var(--gap-xs) var(--gap-sm);
169
+ font-weight: 600;
170
+ font-size: var(--font-size-base);
171
+ color: var(--color-brand-dark);
172
+ cursor: pointer;
173
+ user-select: none;
174
+ }
175
+
176
+ .ft-toggle {
177
+ display: inline-block;
178
+ width: 1em;
179
+ text-align: center;
180
+ font-size: 0.8em;
181
+ color: var(--color-text-muted);
182
+ cursor: pointer;
183
+ flex-shrink: 0;
184
+ }
185
+
186
+ .ft-unified {
187
+ font-weight: 600;
188
+ color: var(--color-accent);
189
+ }
190
+
191
+ /* Item 12: Send-pending virtual row — pink-accented to match the pink-row
192
+ reconciliation state used elsewhere for local-only / not-yet-sent rows. */
193
+ .ft-send-pending {
194
+ color: oklch(0.55 0.18 25);
195
+ &::before {
196
+ content: "✉";
197
+ margin-right: 4px;
198
+ font-size: 0.9em;
199
+ }
200
+ }
201
+
202
+ .ft-folder {
203
+ display: flex;
204
+ align-items: center;
205
+ justify-content: space-between;
206
+ padding: var(--gap-xs) var(--gap-sm) var(--gap-xs) var(--gap-lg);
207
+ cursor: pointer;
208
+ font-size: var(--font-size-base);
209
+ font-weight: 500;
210
+ color: var(--color-brand-dark);
211
+ border-radius: 0;
212
+
213
+ &:hover { background: var(--color-bg-hover); }
214
+ &.selected { background: var(--color-bg-selected); color: var(--color-accent); font-weight: 600; }
215
+ }
216
+
217
+ .ft-folder-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
218
+
219
+ /* Case-duplicate warning — another folder exists with the same name in a
220
+ different case on the server. Hover for the full explanation via title. */
221
+ .ft-folder-duplicate .ft-folder-name::after {
222
+ content: " ⚠";
223
+ color: oklch(0.65 0.2 65);
224
+ font-weight: 600;
225
+ margin-left: 4px;
226
+ }
227
+
228
+ .ft-badge {
229
+ font-size: 0.7rem;
230
+ padding: 0.1rem 0.4rem;
231
+ border-radius: 999px;
232
+ background: var(--color-badge);
233
+ color: white;
234
+ font-weight: 600;
235
+ min-width: 1.2rem;
236
+ text-align: center;
237
+ }
238
+
239
+ .ft-badge-outbox {
240
+ background: oklch(0.55 0.18 25);
241
+ }
242
+
243
+ .ft-filter {
244
+ padding: 2px var(--gap-xs);
245
+ border-bottom: 1px solid var(--color-border);
246
+ background: var(--color-bg-surface);
247
+ flex-shrink: 0;
248
+ }
249
+
250
+ .ft-filter input {
251
+ width: 100%;
252
+ padding: 2px var(--gap-sm);
253
+ border: 1px solid var(--color-border);
254
+ border-radius: var(--radius-sm);
255
+ background: var(--color-bg);
256
+ color: var(--color-text);
257
+ font-size: var(--font-size-sm);
258
+ outline: none;
259
+ }
260
+
261
+ .ft-filter input:focus { border-color: var(--color-accent); }
262
+
263
+ .ft-folder.ft-filter-hidden,
264
+ .ft-account.ft-filter-hidden,
265
+ .ft-account-header.ft-filter-hidden { display: none; }
266
+
267
+ .folder-loading {
268
+ padding: var(--gap-lg);
269
+ color: var(--color-text-muted);
270
+ font-size: var(--font-size-sm);
271
+ }
272
+
273
+ .ft-folder.drop-target {
274
+ background: var(--color-accent);
275
+ color: white;
276
+ outline: 2px solid var(--color-brand-dark);
277
+ outline-offset: -2px;
278
+ }
279
+
280
+ .ft-folder.ft-syncing .ft-folder-name::after {
281
+ content: " \21BB"; /* ↻ clockwise arrow */
282
+ color: var(--color-accent);
283
+ animation: ft-spin 1s linear infinite;
284
+ display: inline-block;
285
+ }
286
+
287
+ @keyframes ft-spin {
288
+ from { transform: rotate(0deg); }
289
+ to { transform: rotate(360deg); }
290
+ }
291
+
292
+ .ft-total-count {
293
+ display: none;
294
+ margin-left: auto;
295
+ padding: 0 6px;
296
+ font-size: 0.75rem;
297
+ color: var(--color-text-muted);
298
+ opacity: 0.7;
299
+ }
300
+
301
+ .show-folder-counts .ft-total-count {
302
+ display: inline;
303
+ }
304
+
305
+ .ml-row.dragging {
306
+ opacity: 0.5;
307
+ }
308
+
309
+ /* ── Message List ── */
310
+
311
+ .message-list {
312
+ display: grid;
313
+ /* avatar | flag | from | date | subject */
314
+ grid-template-columns: 28px 1.2em minmax(120px, 200px) auto 1fr;
315
+ grid-template-rows: auto auto 1fr;
316
+ column-gap: var(--gap-sm);
317
+ overflow: hidden;
318
+ border-right: 1px solid var(--color-border);
319
+ }
320
+
321
+ /* Two-line view */
322
+ .message-list.two-line {
323
+ grid-template-columns: 28px 1.2em 1fr auto;
324
+ }
325
+
326
+ .message-list.two-line .ml-row {
327
+ grid-template-columns: subgrid;
328
+ grid-template-rows: auto auto;
329
+ }
330
+
331
+ .message-list.two-line .ml-avatar { grid-row: 1 / 3; align-self: center; grid-column: 1; }
332
+ .message-list.two-line .ml-flag { grid-row: 1 / 3; align-self: center; grid-column: 2; }
333
+ .message-list.two-line .ml-from { grid-column: 3; }
334
+ .message-list.two-line .ml-date { grid-column: 4; grid-row: 1; padding-right: var(--gap-md); }
335
+ .message-list.two-line .ml-subject {
336
+ grid-column: 3 / 5;
337
+ grid-row: 2;
338
+ color: oklch(0.55 0.10 250) !important;
339
+ font-size: var(--font-size-sm);
340
+ }
341
+
342
+ .ml-row.filter-hidden { display: none; }
343
+
344
+ .ml-header {
345
+ display: grid;
346
+ grid-template-columns: subgrid;
347
+ grid-column: 1 / -1;
348
+ padding: var(--gap-xs) var(--gap-sm);
349
+ border-bottom: 1px solid var(--color-border);
350
+ background: var(--color-bg-toolbar);
351
+ font-size: var(--font-size-sm);
352
+ font-weight: 700;
353
+ color: var(--color-brand-dark);
354
+ user-select: none;
355
+
356
+ .ml-col { cursor: pointer; &:hover { color: var(--color-text); } }
357
+ .ml-col-sortable { position: relative; padding-right: 14px; }
358
+ .ml-col-sort-asc::after,
359
+ .ml-col-sort-desc::after {
360
+ position: absolute;
361
+ right: 2px;
362
+ top: 50%;
363
+ transform: translateY(-50%);
364
+ font-size: 10px;
365
+ color: var(--color-accent);
366
+ }
367
+ .ml-col-sort-asc::after { content: "▲"; }
368
+ .ml-col-sort-desc::after { content: "▼"; }
369
+ }
370
+
371
+ /* Narrow-mode folder title above the list — hidden on wide where the window
372
+ title and toolbar already convey location. */
373
+ .ml-folder-title {
374
+ grid-column: 1 / -1;
375
+ display: none;
376
+ padding: var(--gap-sm) var(--gap-md);
377
+ border-bottom: 1px solid var(--color-border);
378
+ background: var(--color-bg-surface);
379
+ font-size: var(--font-size-lg);
380
+ font-weight: 600;
381
+ color: var(--color-text);
382
+ user-select: none;
383
+ }
384
+ .ml-folder-age {
385
+ font-weight: 400;
386
+ font-size: var(--font-size-sm);
387
+ color: var(--color-text-muted);
388
+ margin-left: var(--gap-xs);
389
+ }
390
+
391
+ /* Per-folder freshness dot — empty by default, colored once the folder has
392
+ a known last-sync time. Fresh (<5m) green, stale-soft (<30m) yellow,
393
+ stale (30m+) red. */
394
+ .ft-folder .ft-freshness {
395
+ display: inline-block;
396
+ width: 8px;
397
+ height: 8px;
398
+ margin-right: 6px;
399
+ border-radius: 50%;
400
+ background: transparent;
401
+ border: 1px solid color-mix(in oklch, var(--color-text-muted) 40%, transparent);
402
+ flex-shrink: 0;
403
+ }
404
+ .ft-folder.fresh .ft-freshness { background: #4a9; border-color: transparent; }
405
+ .ft-folder.stale-soft .ft-freshness { background: #d7a324; border-color: transparent; }
406
+ .ft-folder.stale .ft-freshness { background: #c74; border-color: transparent; }
407
+
408
+ .ml-body {
409
+ grid-column: 1 / -1;
410
+ overflow-y: auto;
411
+ display: grid;
412
+ grid-template-columns: subgrid;
413
+ align-content: start;
414
+ scrollbar-gutter: stable;
415
+ /* Android WebView / Chromium: without an explicit touch-action, the
416
+ * browser waits on JS touch listeners (passive or not) before deciding
417
+ * to scroll. That delay makes the first row feel like it got tapped
418
+ * before the scroll actually starts. pan-y tells the compositor: treat
419
+ * any vertical drag as a scroll, don't wait on JS. overscroll-behavior
420
+ * contains the scroll so we don't chain into the outer page / pull-to-
421
+ * refresh when the user flicks at top/bottom. */
422
+ touch-action: pan-y;
423
+ overscroll-behavior-y: contain;
424
+ }
425
+
426
+ .ml-row {
427
+ display: grid;
428
+ grid-template-columns: subgrid;
429
+ grid-column: 1 / -1;
430
+ padding: var(--gap-sm) var(--gap-sm);
431
+ border-bottom: 1px solid color-mix(in oklch, var(--color-border) 50%, transparent);
432
+ cursor: pointer;
433
+ /* Disable the 300ms double-tap-to-zoom delay on rows. Double-tap zoom
434
+ * makes no sense on a message row anyway; without this, Android often
435
+ * classifies a scroll-starting tap as a delayed-click because it's
436
+ * still in the double-tap wait window. */
437
+ touch-action: manipulation;
438
+ font-size: var(--font-size-base);
439
+ font-weight: 400;
440
+ color: var(--color-text);
441
+ align-items: baseline;
442
+ line-height: 1.35;
443
+
444
+ &:hover { background: var(--color-bg-hover); }
445
+ &.selected { background: var(--color-brand); color: var(--color-brand-dark); font-weight: 500; }
446
+ &.unread {
447
+ /* Thunderbird-level emphasis: true bold (700) rather than semibold
448
+ * (600). At smaller row heights the weight contrast is the cue the
449
+ * eye tracks — color shifts alone read as noise on a dense list. */
450
+ font-weight: 700;
451
+ color: var(--color-unread);
452
+ }
453
+ }
454
+
455
+ .ml-flag { text-align: center; color: var(--color-text-muted); font-size: 0.9em; cursor: pointer; }
456
+ .flagged-only .ml-row:not(.flagged) { display: none; }
457
+ .ml-row.flagged .ml-flag { color: oklch(0.75 0.15 60); } /* orange/gold star */
458
+ .ml-row.flagged { background: color-mix(in oklch, oklch(0.75 0.15 60) 8%, transparent); }
459
+
460
+ .ml-from { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
461
+ .ml-account-tag {
462
+ display: inline-block;
463
+ width: 1.1em; height: 1.1em;
464
+ line-height: 1.1em;
465
+ text-align: center;
466
+ font-size: 0.7rem;
467
+ font-weight: bold;
468
+ border-radius: 2px;
469
+ margin-right: 4px;
470
+ color: #fff;
471
+ background: var(--color-accent);
472
+ vertical-align: baseline;
473
+ }
474
+ .ml-account-tag[title="gmail"] { background: #d93025; }
475
+ .ml-account-tag[title="bobma"] { background: #1a73e8; }
476
+ .ml-folder-tag {
477
+ display: inline-block;
478
+ padding: 0 6px;
479
+ font-size: 0.72rem;
480
+ font-weight: 500;
481
+ border-radius: 3px;
482
+ margin-right: 4px;
483
+ color: var(--color-text);
484
+ background: color-mix(in oklch, var(--color-accent) 18%, transparent);
485
+ vertical-align: baseline;
486
+ max-width: 10em;
487
+ overflow: hidden;
488
+ text-overflow: ellipsis;
489
+ }
490
+ .ml-thread-pill {
491
+ display: inline-block;
492
+ padding: 0 6px;
493
+ font-size: 0.72rem;
494
+ font-weight: 600;
495
+ border-radius: 999px;
496
+ margin-right: 6px;
497
+ color: #fff;
498
+ background: var(--color-accent);
499
+ vertical-align: baseline;
500
+ min-width: 1.5em;
501
+ text-align: center;
502
+ cursor: pointer;
503
+ }
504
+ .ml-thread-pill:hover { filter: brightness(1.15); }
505
+
506
+ /* Popup that lists the messages in a thread, anchored below the clicked pill. */
507
+ .ml-thread-popup {
508
+ position: fixed;
509
+ min-width: 320px;
510
+ max-width: 600px;
511
+ max-height: 60vh;
512
+ overflow-y: auto;
513
+ background: var(--color-bg);
514
+ color: var(--color-text);
515
+ border: 1px solid var(--color-border);
516
+ border-radius: var(--radius-md);
517
+ box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
518
+ padding: var(--gap-xs);
519
+ z-index: 1500;
520
+ font-family: var(--font-ui);
521
+ font-size: var(--font-size-sm);
522
+ }
523
+ .ml-thread-popup-item {
524
+ display: grid;
525
+ grid-template-columns: minmax(0, 1fr) auto;
526
+ gap: 4px var(--gap-sm);
527
+ padding: 6px 10px;
528
+ border-radius: var(--radius-sm);
529
+ cursor: pointer;
530
+ }
531
+ .ml-thread-popup-item:hover { background: var(--color-bg-hover); }
532
+ .ml-thread-popup-item.unread .ml-thread-popup-from,
533
+ .ml-thread-popup-item.unread .ml-thread-popup-subject { font-weight: 700; }
534
+ .ml-thread-popup-from {
535
+ grid-column: 1;
536
+ grid-row: 1;
537
+ overflow: hidden;
538
+ text-overflow: ellipsis;
539
+ white-space: nowrap;
540
+ }
541
+ .ml-thread-popup-date {
542
+ grid-column: 2;
543
+ grid-row: 1;
544
+ color: var(--color-text-muted);
545
+ font-variant-numeric: tabular-nums;
546
+ }
547
+ .ml-thread-popup-subject {
548
+ grid-column: 1 / -1;
549
+ grid-row: 2;
550
+ color: var(--color-text-muted);
551
+ overflow: hidden;
552
+ text-overflow: ellipsis;
553
+ white-space: nowrap;
554
+ }
555
+
556
+ /* Generic modal — used by the JSONC config editor launched from Settings */
557
+ .mailx-modal-backdrop {
558
+ position: fixed;
559
+ inset: 0;
560
+ background: rgba(0, 0, 0, 0.4);
561
+ display: flex;
562
+ align-items: center;
563
+ justify-content: center;
564
+ z-index: 2000;
565
+ }
566
+ .mailx-modal {
567
+ background: var(--color-bg);
568
+ color: var(--color-text);
569
+ padding: var(--gap-lg);
570
+ border-radius: var(--radius-md);
571
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
572
+ min-width: 420px;
573
+ max-width: 90vw;
574
+ display: flex;
575
+ flex-direction: column;
576
+ gap: var(--gap-md);
577
+ font-family: var(--font-ui);
578
+ }
579
+ .mailx-modal-wide {
580
+ width: 80vw;
581
+ max-width: 95vw;
582
+ max-height: 95vh;
583
+ height: 85vh;
584
+ resize: both;
585
+ overflow: auto;
586
+ min-width: 480px;
587
+ min-height: 320px;
588
+ }
589
+ .mailx-modal-title {
590
+ font-size: var(--font-size-lg);
591
+ font-weight: 600;
592
+ display: flex;
593
+ align-items: center;
594
+ gap: var(--gap-sm);
595
+ }
596
+ .mailx-modal-title-text {
597
+ flex: 1;
598
+ }
599
+ .mailx-modal-close {
600
+ appearance: none;
601
+ background: transparent;
602
+ border: none;
603
+ color: var(--color-text-muted);
604
+ font-size: 20px;
605
+ line-height: 1;
606
+ cursor: pointer;
607
+ padding: 2px 8px;
608
+ border-radius: var(--radius-sm);
609
+
610
+ &:hover {
611
+ background: var(--color-bg-surface);
612
+ color: var(--color-text);
613
+ }
614
+ }
615
+ .mailx-modal-label {
616
+ display: flex;
617
+ flex-direction: column;
618
+ gap: 4px;
619
+ font-size: var(--font-size-sm);
620
+ color: var(--color-text-muted);
621
+ }
622
+ .mailx-modal-input {
623
+ padding: 6px 8px;
624
+ border: 1px solid var(--color-border);
625
+ border-radius: var(--radius-sm);
626
+ background: var(--color-bg-surface);
627
+ color: var(--color-text);
628
+ font-family: var(--font-ui);
629
+ font-size: var(--font-size-base);
630
+ }
631
+ .mailx-modal-textarea {
632
+ flex: 1;
633
+ min-height: 200px;
634
+ resize: vertical;
635
+ font-family: var(--font-mono);
636
+ font-size: 13px;
637
+ white-space: pre;
638
+ tab-size: 2;
639
+ }
640
+
641
+ /* JSONC editor with line-number gutter. Gutter + textarea share the same
642
+ line-height so numbers stay aligned; textarea owns the scroll and the
643
+ gutter syncs via JS. Error line is highlighted red in the gutter so the
644
+ "Line N, col M" error points at a visible marker. */
645
+ .jsonc-editor-wrap {
646
+ flex: 1;
647
+ display: flex;
648
+ min-height: 200px;
649
+ border: 1px solid var(--color-border);
650
+ border-radius: var(--radius-sm);
651
+ overflow: hidden;
652
+ background: var(--color-bg-surface);
653
+ }
654
+ .jsonc-gutter {
655
+ flex: 0 0 auto;
656
+ min-width: 3em;
657
+ padding: 6px 6px 6px 10px;
658
+ background: oklch(0.94 0.005 250);
659
+ border-right: 1px solid var(--color-border);
660
+ color: var(--color-text-muted);
661
+ font-family: var(--font-mono);
662
+ font-size: 13px;
663
+ line-height: 1.5;
664
+ text-align: right;
665
+ user-select: none;
666
+ overflow: hidden;
667
+ white-space: pre;
668
+ tab-size: 2;
669
+ }
670
+ .jsonc-gutter-line {
671
+ line-height: 1.5;
672
+ font-variant-numeric: tabular-nums;
673
+ }
674
+ .jsonc-gutter-error {
675
+ background: oklch(0.65 0.2 25);
676
+ color: #fff;
677
+ font-weight: 600;
678
+ border-radius: 2px;
679
+ padding: 0 4px;
680
+ margin: 0 -4px;
681
+ }
682
+ .jsonc-editor-wrap .jsonc-textarea {
683
+ flex: 1;
684
+ border: 0;
685
+ border-radius: 0;
686
+ line-height: 1.5;
687
+ resize: none;
688
+ /* The outer wrap draws the focus ring so gutter + area move together */
689
+ }
690
+ .jsonc-editor-wrap:focus-within {
691
+ outline: 2px solid var(--color-accent);
692
+ outline-offset: -1px;
693
+ }
694
+ .jsonc-editor-wrap:has(.mailx-modal-input-error) {
695
+ outline: 2px solid oklch(0.65 0.2 25);
696
+ outline-offset: -1px;
697
+ }
698
+ .mailx-modal-input:focus {
699
+ outline: 2px solid var(--color-accent);
700
+ outline-offset: -1px;
701
+ }
702
+ .mailx-modal-input-error {
703
+ outline: 2px solid oklch(0.65 0.2 25) !important;
704
+ outline-offset: -1px;
705
+ background: color-mix(in oklch, oklch(0.65 0.2 25) 6%, var(--color-bg-surface));
706
+ }
707
+ .mailx-modal-input-error::selection {
708
+ background: oklch(0.65 0.2 25);
709
+ color: #fff;
710
+ }
711
+
712
+ /* Split content area — textarea on the left, help on the right */
713
+ .mailx-modal-split {
714
+ display: grid;
715
+ grid-template-columns: minmax(0, 1fr) minmax(240px, 360px);
716
+ gap: var(--gap-md);
717
+ flex: 1;
718
+ min-height: 0;
719
+
720
+ &:has(.mailx-help-collapsed) {
721
+ grid-template-columns: minmax(0, 1fr) auto;
722
+ }
723
+ }
724
+ @media (max-width: 900px) {
725
+ .mailx-modal-split { grid-template-columns: 1fr; }
726
+ }
727
+ .mailx-modal-split-left, .mailx-modal-split-right {
728
+ display: flex;
729
+ flex-direction: column;
730
+ min-height: 0;
731
+ }
732
+
733
+ .mailx-help-panel {
734
+ background: var(--color-bg-surface);
735
+ border: 1px solid var(--color-border);
736
+ border-radius: var(--radius-sm);
737
+ padding: var(--gap-sm);
738
+ overflow: auto;
739
+ max-height: 60vh;
740
+ font-size: var(--font-size-sm);
741
+ line-height: 1.4;
742
+
743
+ &.mailx-help-collapsed .mailx-help-body { display: none; }
744
+ &.mailx-help-collapsed { max-height: none; padding: 4px; }
745
+ }
746
+ .mailx-help-title { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--gap-xs); }
747
+ .mailx-help-toggle {
748
+ background: none;
749
+ border: none;
750
+ color: var(--color-text);
751
+ font-weight: 600;
752
+ cursor: pointer;
753
+ font-size: var(--font-size-sm);
754
+ padding: 2px 4px;
755
+ }
756
+ .mailx-help-toggle:hover { background: var(--color-bg-hover); border-radius: var(--radius-sm); }
757
+
758
+ .mailx-help-body {
759
+ & h1, & h2, & h3 { margin-top: var(--gap-sm); margin-bottom: 4px; font-size: 1em; }
760
+ & h1 { font-size: 1.1em; }
761
+ & p { margin: 4px 0; }
762
+ & ul { margin: 4px 0 4px var(--gap-md); padding: 0; }
763
+ & li { margin: 2px 0; }
764
+ & code {
765
+ font-family: var(--font-mono);
766
+ font-size: 0.9em;
767
+ background: var(--color-bg);
768
+ padding: 1px 4px;
769
+ border-radius: 3px;
770
+ }
771
+ & a { color: var(--color-accent); }
772
+ }
773
+ .mailx-help-code {
774
+ font-family: var(--font-mono);
775
+ font-size: 12px;
776
+ background: var(--color-bg);
777
+ border: 1px solid var(--color-border);
778
+ border-radius: var(--radius-sm);
779
+ padding: var(--gap-xs);
780
+ overflow-x: auto;
781
+ margin: 4px 0;
782
+ white-space: pre;
783
+ }
784
+ .mailx-help-code code { background: none; padding: 0; }
785
+ .mailx-modal-error {
786
+ color: oklch(0.65 0.2 25);
787
+ font-size: var(--font-size-sm);
788
+ background: color-mix(in oklch, oklch(0.65 0.2 25) 10%, transparent);
789
+ padding: 6px 10px;
790
+ border-radius: var(--radius-sm);
791
+ white-space: pre-wrap;
792
+ }
793
+ .mailx-modal-buttons {
794
+ display: flex;
795
+ gap: var(--gap-sm);
796
+ align-items: center;
797
+ }
798
+ .mailx-modal-spacer { flex: 1; }
799
+ .mailx-modal-btn {
800
+ padding: 6px 14px;
801
+ border: 1px solid var(--color-border);
802
+ border-radius: var(--radius-sm);
803
+ background: var(--color-bg-surface);
804
+ color: var(--color-text);
805
+ cursor: pointer;
806
+ font-size: var(--font-size-sm);
807
+ }
808
+ .mailx-modal-btn:hover { background: var(--color-bg-hover); }
809
+ .mailx-modal-btn-primary {
810
+ background: var(--color-accent);
811
+ color: #fff;
812
+ border-color: transparent;
813
+ font-weight: 500;
814
+ }
815
+ .mailx-modal-btn-primary:hover {
816
+ filter: brightness(1.1);
817
+ /* Add a border-shadow on hover so the button stays visibly distinct from
818
+ the modal background regardless of theme — `filter: brightness` alone
819
+ could push the accent close to the modal background on some palettes,
820
+ making the button look like it disappeared. */
821
+ box-shadow: 0 0 0 2px var(--color-accent);
822
+ outline: 1px solid var(--color-bg);
823
+ outline-offset: -1px;
824
+ }
825
+
826
+ /* About dialog */
827
+ .mailx-about { font-size: var(--font-size-sm); line-height: 1.5; }
828
+ .mailx-about-dl {
829
+ display: grid;
830
+ grid-template-columns: auto 1fr;
831
+ gap: 4px var(--gap-md);
832
+ margin: 0;
833
+
834
+ & dt { color: var(--color-text-muted); font-weight: 500; }
835
+ & dd { margin: 0; word-break: break-word; }
836
+ }
837
+ .mailx-about-section {
838
+ font-weight: 600;
839
+ margin-top: var(--gap-sm);
840
+ color: var(--color-text-muted);
841
+ font-size: 0.8rem;
842
+ text-transform: uppercase;
843
+ letter-spacing: 0.05em;
844
+ }
845
+ .mailx-about-accounts ul {
846
+ margin: 4px 0 0 var(--gap-md);
847
+ padding: 0;
848
+ }
849
+ .mailx-about-foot {
850
+ margin-top: var(--gap-sm);
851
+ padding-top: var(--gap-sm);
852
+ border-top: 1px solid var(--color-border);
853
+ color: var(--color-text-muted);
854
+ font-size: 0.8rem;
855
+ text-align: center;
856
+ }
857
+
858
+ .ml-subject {
859
+ overflow: hidden;
860
+ text-overflow: ellipsis;
861
+ white-space: nowrap;
862
+
863
+ .ml-preview {
864
+ color: var(--color-text-muted);
865
+ font-weight: 400;
866
+ margin-left: var(--gap-xs);
867
+ }
868
+ }
869
+ .no-snippets .ml-preview { display: none; }
870
+ .ml-date { white-space: nowrap; text-align: right; color: var(--color-text-muted); font-size: var(--font-size-sm); font-variant-numeric: tabular-nums; }
871
+ /* Not-downloaded indicator: small dot before the date */
872
+ .ml-row.not-downloaded .ml-date::before {
873
+ content: "○ ";
874
+ color: var(--color-text-muted);
875
+ opacity: 0.7;
876
+ }
877
+ .ml-row:not(.not-downloaded) .ml-date::before {
878
+ content: "● ";
879
+ color: #4a9;
880
+ opacity: 0.5;
881
+ }
882
+
883
+ /* Reply marker — messages whose In-Reply-To points at another message get a
884
+ subtle left-edge accent so threaded replies visibly distinguish from top-
885
+ level posts without needing thread-grouping mode on. Works regardless of
886
+ whether thread-grouping is enabled. */
887
+ .ml-row.is-reply::before {
888
+ content: "";
889
+ position: absolute;
890
+ left: 0;
891
+ top: 2px;
892
+ bottom: 2px;
893
+ width: 2px;
894
+ background: oklch(0.70 0.12 250); /* muted blue */
895
+ border-radius: 0 1px 1px 0;
896
+ pointer-events: none;
897
+ opacity: 0.5;
898
+ }
899
+ .ml-row { position: relative; }
900
+
901
+ /* S1 slice C — local action (move/flag/delete) queued but server hasn't
902
+ ACK'd. Reuses the same date-column dot as the download indicator so
903
+ "still on client, not yet on server" sits in the same visual slot as
904
+ "body downloaded". Color, not row background — the row keeps the
905
+ normal/unread/selected styling so the blue accent isn't fighting pink. */
906
+ .ml-row.pending-reconcile .ml-date::before {
907
+ color: oklch(0.65 0.22 350); /* pink dot */
908
+ opacity: 0.9;
909
+ }
910
+
911
+ /* Filter: only this conversation — rows not in the current thread hide.
912
+ The selected row stays visible regardless so toggling doesn't leave the
913
+ list empty when the selection is a singleton thread. */
914
+ .ml-row.thread-filter-hidden { display: none; }
915
+
916
+ /* Sender avatar — Thunderbird-style 24-px circle with the sender's first
917
+ initial. Background color is hashed from the sender's address so the
918
+ same person keeps the same color across rows. In multi-select mode
919
+ (#ml-body.multi-select-on) the avatar swaps to a checkmark per row,
920
+ filled when selected, hollow when not — matches the Thunderbird /
921
+ Gmail / Apple Mail pattern. */
922
+ .ml-avatar {
923
+ width: 24px;
924
+ height: 24px;
925
+ border-radius: 50%;
926
+ background: oklch(0.62 0.14 250);
927
+ color: #fff;
928
+ font-size: 0.78rem;
929
+ font-weight: 600;
930
+ line-height: 24px;
931
+ text-align: center;
932
+ user-select: none;
933
+ flex-shrink: 0;
934
+ align-self: center;
935
+ cursor: pointer;
936
+ }
937
+ #ml-body.multi-select-on .ml-avatar {
938
+ background: transparent !important;
939
+ color: var(--color-text-muted);
940
+ border: 2px solid currentColor;
941
+ line-height: 20px;
942
+ }
943
+ #ml-body.multi-select-on .ml-avatar::before { content: ""; }
944
+ #ml-body.multi-select-on .ml-row.selected .ml-avatar {
945
+ background: var(--color-brand, oklch(0.55 0.18 250)) !important;
946
+ color: #fff;
947
+ border-color: var(--color-brand, oklch(0.55 0.18 250));
948
+ }
949
+ /* Replace the initial with a check when selected in multi-mode. The
950
+ `font-size: 0` trick blanks the text node we set in JS without having
951
+ to clear it; the ::after glyph then fills the space. */
952
+ #ml-body.multi-select-on .ml-avatar { font-size: 0; }
953
+ #ml-body.multi-select-on .ml-avatar::after { content: ""; }
954
+ #ml-body.multi-select-on .ml-row.selected .ml-avatar::after {
955
+ content: "✓";
956
+ font-size: 0.95rem;
957
+ line-height: 20px;
958
+ font-weight: 700;
959
+ }
960
+
961
+ /* Add an avatar slot to the header so columns line up. Header is a sibling
962
+ subgrid; first cell is empty (avatar column). */
963
+ .ml-header { grid-template-columns: subgrid; }
964
+
965
+ /* Duplicate-message-id tag in unified inbox — shown when the same
966
+ Message-ID appears across 2+ accounts (same letter delivered to both,
967
+ mailing-list Bcc, etc.). Subtle teal badge; tooltip explains. */
968
+ .ml-dupe-tag {
969
+ display: inline-block;
970
+ color: oklch(0.55 0.14 195);
971
+ font-weight: 600;
972
+ margin-right: 0.3em;
973
+ user-select: none;
974
+ }
975
+
976
+ /* Per-row ⋮ touch-menu button removed 2026-04-24 — user feedback: "nice
977
+ idea but better when we have a second-stage plan strategy". Touch users
978
+ still reach the menu via long-press → multi-select → bulk-bar, or by
979
+ using a stylus/mouse for contextmenu. Revisit when we've decided what
980
+ additional per-message actions belong here. */
981
+
982
+ /* ── Alarm popup (P17 / Q104) ── */
983
+ /* Fullscreen backdrop + centered panel; mirrors .mailx-modal* patterns but
984
+ kept in its own namespace so alarm behavior (snooze/dismiss) can evolve
985
+ without dragging the whole modal system along. */
986
+ .alarm-overlay {
987
+ position: fixed;
988
+ inset: 0;
989
+ background: rgba(0, 0, 0, 0.45);
990
+ z-index: 9000;
991
+ display: flex;
992
+ align-items: center;
993
+ justify-content: center;
994
+ }
995
+ .alarm-panel {
996
+ background: var(--color-bg);
997
+ color: var(--color-text);
998
+ border: 1px solid var(--color-border);
999
+ border-radius: 8px;
1000
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
1001
+ min-width: 380px;
1002
+ max-width: 560px;
1003
+ width: 90vw;
1004
+ display: flex;
1005
+ flex-direction: column;
1006
+ max-height: 80vh;
1007
+ }
1008
+ .alarm-head {
1009
+ display: flex;
1010
+ align-items: center;
1011
+ gap: var(--gap-sm);
1012
+ padding: var(--gap-sm) var(--gap-md);
1013
+ border-bottom: 1px solid var(--color-border);
1014
+ font-weight: 600;
1015
+ }
1016
+ .alarm-icon { font-size: 1.4em; }
1017
+ .alarm-title { flex: 1; }
1018
+ .alarm-close {
1019
+ border: 0;
1020
+ background: transparent;
1021
+ color: var(--color-text-muted);
1022
+ cursor: pointer;
1023
+ font-size: 1.4em;
1024
+ line-height: 1;
1025
+ padding: 0 0.4em;
1026
+ }
1027
+ .alarm-close:hover { color: var(--color-text); }
1028
+ .alarm-list {
1029
+ padding: var(--gap-sm) var(--gap-md);
1030
+ overflow-y: auto;
1031
+ display: flex;
1032
+ flex-direction: column;
1033
+ gap: var(--gap-xs);
1034
+ }
1035
+ .alarm-row {
1036
+ display: flex;
1037
+ align-items: center;
1038
+ gap: var(--gap-sm);
1039
+ padding: var(--gap-xs) 0;
1040
+ border-bottom: 1px solid color-mix(in oklch, var(--color-border) 50%, transparent);
1041
+ }
1042
+ .alarm-row:last-child { border-bottom: none; }
1043
+ .alarm-row-main {
1044
+ flex: 1;
1045
+ display: flex;
1046
+ align-items: center;
1047
+ gap: var(--gap-xs);
1048
+ min-width: 0;
1049
+ }
1050
+ .alarm-row-kind { font-size: 1.1em; }
1051
+ .alarm-row-title {
1052
+ font-weight: 500;
1053
+ overflow: hidden;
1054
+ text-overflow: ellipsis;
1055
+ white-space: nowrap;
1056
+ flex: 1;
1057
+ }
1058
+ .alarm-row-when {
1059
+ color: var(--color-text-muted);
1060
+ font-size: var(--font-size-sm);
1061
+ font-variant-numeric: tabular-nums;
1062
+ white-space: nowrap;
1063
+ }
1064
+ .alarm-row-actions { display: flex; gap: var(--gap-xs); }
1065
+ .alarm-row-link,
1066
+ .alarm-row-dismiss {
1067
+ border: 0;
1068
+ background: transparent;
1069
+ color: var(--color-text-muted);
1070
+ cursor: pointer;
1071
+ font-size: 1em;
1072
+ padding: 0 0.3em;
1073
+ border-radius: 3px;
1074
+ }
1075
+ .alarm-row-link:hover,
1076
+ .alarm-row-dismiss:hover {
1077
+ background: var(--color-bg-hover);
1078
+ color: var(--color-text);
1079
+ }
1080
+ .alarm-foot {
1081
+ display: flex;
1082
+ align-items: center;
1083
+ gap: var(--gap-sm);
1084
+ padding: var(--gap-sm) var(--gap-md);
1085
+ border-top: 1px solid var(--color-border);
1086
+ background: var(--color-bg-toolbar);
1087
+ border-radius: 0 0 8px 8px;
1088
+ }
1089
+ .alarm-snooze-label {
1090
+ font-size: var(--font-size-sm);
1091
+ color: var(--color-text-muted);
1092
+ display: flex;
1093
+ align-items: center;
1094
+ gap: var(--gap-xs);
1095
+ }
1096
+ .alarm-snooze-sel {
1097
+ background: var(--color-bg);
1098
+ color: var(--color-text);
1099
+ border: 1px solid var(--color-border);
1100
+ border-radius: 4px;
1101
+ padding: 0.25em 0.5em;
1102
+ font-size: var(--font-size-sm);
1103
+ }
1104
+ .alarm-btn {
1105
+ border: 1px solid var(--color-border);
1106
+ background: var(--color-bg);
1107
+ color: var(--color-text);
1108
+ cursor: pointer;
1109
+ padding: 0.4em 1em;
1110
+ border-radius: 4px;
1111
+ font-size: var(--font-size-sm);
1112
+ }
1113
+ .alarm-btn:hover { background: var(--color-bg-hover); }
1114
+ .alarm-btn-primary {
1115
+ background: var(--color-brand, oklch(0.65 0.14 250));
1116
+ color: #fff;
1117
+ border-color: var(--color-brand, oklch(0.65 0.14 250));
1118
+ }
1119
+ .alarm-btn-primary:hover { filter: brightness(1.1); }
1120
+
1121
+ /* Bulk-actions bar retired 2026-04-24 — trash + spam moved to the main
1122
+ toolbar; other bulk ops are reachable via right-click context menu.
1123
+ CSS removed so future readers aren't confused by dead selectors. */
1124
+
1125
+ /* Multi-select mode (entered by long-press on touch or Ctrl/Shift click on
1126
+ desktop). Add a left-edge accent bar so it's visually clear the list is
1127
+ in selection mode, not navigation mode. */
1128
+
1129
+ /* Multi-select mode (entered by long-press on touch or Ctrl/Shift click on
1130
+ desktop). Add a left-edge accent bar so it's visually clear the list is
1131
+ in selection mode, not navigation mode. */
1132
+ #ml-body.multi-select-on .ml-row::before {
1133
+ content: "";
1134
+ position: absolute;
1135
+ left: 0;
1136
+ top: 0;
1137
+ bottom: 0;
1138
+ width: 3px;
1139
+ background: var(--color-brand, oklch(0.65 0.14 250));
1140
+ opacity: 0.25;
1141
+ }
1142
+ #ml-body.multi-select-on .ml-row.selected::before {
1143
+ opacity: 1;
1144
+ }
1145
+
1146
+ /* Info banner inside a modal — used by the Add-contact dialog to surface
1147
+ "already in address book" duplicate notices. Amber tone so it reads as
1148
+ "heads up" not "error". */
1149
+ .mailx-modal-info {
1150
+ padding: var(--gap-sm) var(--gap-md);
1151
+ background: oklch(0.95 0.05 75);
1152
+ border: 1px solid oklch(0.80 0.10 75);
1153
+ border-radius: var(--radius-sm);
1154
+ color: oklch(0.35 0.08 75);
1155
+ font-size: var(--font-size-sm);
1156
+ margin-bottom: var(--gap-sm);
1157
+ }
1158
+
1159
+ /* Offline indicator — sits in the status bar; amber tone so it's visible
1160
+ but doesn't scream (being offline is normal local-first behavior, not
1161
+ an error). */
1162
+ .status-offline {
1163
+ color: oklch(0.65 0.18 65);
1164
+ font-weight: 600;
1165
+ font-size: var(--font-size-sm);
1166
+ padding: 0 6px;
1167
+ }
1168
+
1169
+ /* S51 — calendar sidebar (Thunderbird Lightning Events & Tasks pane).
1170
+ Right-docked, fixed width. Visible by default; user hides via View menu.
1171
+ Hides automatically on narrow screens (< 1100px) — Android uses the
1172
+ native calendar app. When hidden, the main grid does NOT reserve a column
1173
+ for it, so there's no blank strip on the right. */
1174
+ .calendar-sidebar {
1175
+ grid-area: cal-side;
1176
+ border-left: 1px solid var(--color-border);
1177
+ background: var(--color-bg);
1178
+ display: none; /* Opt-in: only show when body.calendar-sidebar-on */
1179
+ flex-direction: column;
1180
+ overflow: hidden;
1181
+ font-size: var(--font-size-sm);
1182
+ }
1183
+ body.calendar-sidebar-on .calendar-sidebar { display: flex; }
1184
+
1185
+ @media (max-width: 1100px) {
1186
+ .calendar-sidebar,
1187
+ body.calendar-sidebar-on .calendar-sidebar { display: none; }
1188
+ }
1189
+ .cal-side-head {
1190
+ display: flex;
1191
+ align-items: center;
1192
+ gap: var(--gap-xs);
1193
+ padding: var(--gap-sm);
1194
+ border-bottom: 1px solid var(--color-border);
1195
+ }
1196
+ .cal-side-date { flex: 1; }
1197
+ .cal-side-date strong { font-size: 1.4em; }
1198
+ .cal-side-date-month { color: var(--color-text-muted); font-size: 0.85em; }
1199
+ .cal-side-nav {
1200
+ background: transparent;
1201
+ border: 1px solid var(--color-border);
1202
+ border-radius: var(--radius-sm);
1203
+ padding: 1px 6px;
1204
+ cursor: pointer;
1205
+ font-size: 0.95em;
1206
+ color: var(--color-text);
1207
+ }
1208
+ .cal-side-nav:hover { background: var(--color-bg-hover); }
1209
+ .cal-side-actions {
1210
+ padding: var(--gap-xs) var(--gap-sm);
1211
+ border-bottom: 1px solid var(--color-border);
1212
+ }
1213
+ .cal-side-new {
1214
+ width: 100%;
1215
+ padding: 4px 8px;
1216
+ background: transparent;
1217
+ border: 1px dashed var(--color-border);
1218
+ border-radius: var(--radius-sm);
1219
+ cursor: pointer;
1220
+ color: var(--color-text);
1221
+ font-size: var(--font-size-sm);
1222
+ }
1223
+ .cal-side-new:hover { background: var(--color-bg-hover); }
1224
+ .cal-side-body {
1225
+ flex: 1;
1226
+ overflow-y: auto;
1227
+ padding: var(--gap-xs) 0;
1228
+ }
1229
+ .cal-side-day {
1230
+ padding: 4px var(--gap-sm);
1231
+ background: var(--color-bg-surface);
1232
+ font-weight: 600;
1233
+ color: var(--color-text);
1234
+ border-bottom: 1px solid var(--color-border);
1235
+ }
1236
+ .cal-side-event {
1237
+ display: flex;
1238
+ align-items: baseline;
1239
+ gap: 6px;
1240
+ padding: 3px var(--gap-sm) 3px 18px;
1241
+ cursor: default;
1242
+ }
1243
+ .cal-side-event:hover { background: var(--color-bg-hover); }
1244
+ .cal-side-event-dot {
1245
+ display: inline-block;
1246
+ width: 8px;
1247
+ height: 8px;
1248
+ border-radius: 50%;
1249
+ flex: 0 0 8px;
1250
+ }
1251
+ .cal-side-event-dot.l { background: oklch(0.70 0.18 70); } /* local — amber */
1252
+ .cal-side-event-dot.g { background: oklch(0.65 0.20 250); } /* google — blue */
1253
+ .cal-side-event-time { color: var(--color-text); min-width: 44px; font-variant-numeric: tabular-nums; }
1254
+ .cal-side-event-title { flex: 1; }
1255
+ .cal-side-event-recur {
1256
+ color: var(--color-text-muted);
1257
+ margin-left: 4px;
1258
+ font-size: 0.85em;
1259
+ opacity: 0.8;
1260
+ }
1261
+ .cal-side-opt {
1262
+ display: block;
1263
+ padding: 2px 0;
1264
+ font-size: 0.85em;
1265
+ color: var(--color-text-muted);
1266
+ cursor: pointer;
1267
+ }
1268
+ .cal-side-opt input[type=number] { margin-left: 4px; }
1269
+ .cal-side-event { cursor: pointer; }
1270
+ .cal-side-auth-error {
1271
+ color: oklch(0.55 0.18 25);
1272
+ font-weight: 600;
1273
+ padding: var(--gap-sm);
1274
+ background: oklch(0.96 0.04 25);
1275
+ border: 1px solid oklch(0.80 0.12 25);
1276
+ border-radius: var(--radius-sm);
1277
+ font-style: normal !important;
1278
+ line-height: 1.4;
1279
+ text-align: left !important;
1280
+ }
1281
+ .cal-side-empty {
1282
+ padding: var(--gap-md) var(--gap-sm);
1283
+ color: var(--color-text-muted);
1284
+ text-align: center;
1285
+ font-style: italic;
1286
+ }
1287
+ .cal-side-foot {
1288
+ border-top: 1px solid var(--color-border);
1289
+ padding: var(--gap-xs) var(--gap-sm);
1290
+ font-size: var(--font-size-sm);
1291
+ max-height: 35%;
1292
+ overflow-y: auto;
1293
+ }
1294
+ .cal-side-foot label { display: block; padding: 2px 0; cursor: pointer; }
1295
+ .cal-side-task-head {
1296
+ font-weight: 600;
1297
+ padding: var(--gap-xs) 0;
1298
+ color: var(--color-text-muted);
1299
+ }
1300
+ .cal-side-task {
1301
+ display: flex;
1302
+ align-items: center;
1303
+ gap: 6px;
1304
+ padding: 2px 0;
1305
+
1306
+ .cal-side-task-delete {
1307
+ margin-left: auto;
1308
+ opacity: 0;
1309
+ background: transparent;
1310
+ border: 0;
1311
+ cursor: pointer;
1312
+ color: var(--color-text-muted);
1313
+ padding: 0 4px;
1314
+ font-size: 14px;
1315
+ line-height: 1;
1316
+ transition: opacity 0.15s, color 0.15s;
1317
+ }
1318
+ &:hover .cal-side-task-delete { opacity: 1; }
1319
+ .cal-side-task-delete:hover { color: oklch(0.55 0.22 25); }
1320
+ }
1321
+ .cal-side-task-title {
1322
+ flex: 1;
1323
+ overflow: hidden;
1324
+ text-overflow: ellipsis;
1325
+ white-space: nowrap;
1326
+ }
1327
+ .cal-side-task-title.done {
1328
+ text-decoration: line-through;
1329
+ color: var(--color-text-muted);
1330
+ }
1331
+ .cal-side-task-header-row {
1332
+ display: flex;
1333
+ align-items: center;
1334
+ gap: var(--gap-xs);
1335
+ padding: 2px 0;
1336
+
1337
+ label { flex: 1; }
1338
+ .cal-side-new { width: auto; padding: 2px 8px; font-size: 0.85em; }
1339
+ }
1340
+ /* Refresh button visual feedback — the ↻ glyph spins for ~600 ms when a
1341
+ pull is in flight so the user sees that their click did something. */
1342
+ @keyframes cal-side-spin { to { transform: rotate(360deg); } }
1343
+ .cal-side-refreshing { animation: cal-side-spin 0.6s linear; pointer-events: none; }
1344
+
1345
+ .ml-empty {
1346
+ grid-column: 1 / -1;
1347
+ display: flex;
1348
+ align-items: center;
1349
+ justify-content: center;
1350
+ height: 100%;
1351
+ color: var(--color-text-muted);
1352
+ font-size: var(--font-size-base);
1353
+ }
1354
+
1355
+ .mv-empty {
1356
+ display: flex;
1357
+ align-items: center;
1358
+ justify-content: center;
1359
+ height: 100%;
1360
+ color: var(--color-text-muted);
1361
+ font-size: var(--font-size-base);
1362
+ }
1363
+
1364
+ /* ── System-generated message plaque ──
1365
+ * Visually distinguished from email content so the user knows the message is
1366
+ * from mailx itself (errors, status notices), not part of the rendered email.
1367
+ * Inset card with a "mailx" tag chip in the corner. */
1368
+ .mv-system-message {
1369
+ position: relative;
1370
+ margin: var(--gap-lg);
1371
+ padding: var(--gap-lg) var(--gap-lg) var(--gap-md);
1372
+ background: var(--color-bg-surface);
1373
+ border: 1px dashed var(--color-border);
1374
+ border-radius: var(--radius-md);
1375
+ font-family: var(--font-family-base);
1376
+ font-size: var(--font-size-sm);
1377
+ color: var(--color-text);
1378
+ max-width: 640px;
1379
+ box-shadow: 0 1px 2px rgba(0,0,0,0.04);
1380
+
1381
+ .mv-system-tag {
1382
+ position: absolute;
1383
+ top: -0.6em;
1384
+ left: var(--gap-md);
1385
+ padding: 0.1em 0.6em;
1386
+ background: var(--color-bg);
1387
+ border: 1px solid var(--color-border);
1388
+ border-radius: var(--radius-sm);
1389
+ font-size: 0.7rem;
1390
+ font-weight: 600;
1391
+ text-transform: uppercase;
1392
+ letter-spacing: 0.06em;
1393
+ color: var(--color-text-muted);
1394
+ }
1395
+ .mv-system-title {
1396
+ font-weight: 600;
1397
+ margin-bottom: var(--gap-xs);
1398
+ color: var(--color-text);
1399
+ }
1400
+ .mv-system-body {
1401
+ color: var(--color-text-muted);
1402
+ white-space: pre-wrap;
1403
+ word-break: break-word;
1404
+ line-height: 1.4;
1405
+ }
1406
+ .mv-system-actions {
1407
+ margin-top: var(--gap-sm);
1408
+ display: flex;
1409
+ gap: var(--gap-sm);
1410
+ }
1411
+ .mv-system-btn {
1412
+ padding: 0.3em 0.9em;
1413
+ border: 1px solid var(--color-border);
1414
+ border-radius: var(--radius-sm);
1415
+ background: var(--color-bg);
1416
+ color: var(--color-text);
1417
+ cursor: pointer;
1418
+ font-size: var(--font-size-sm);
1419
+ &:hover { background: var(--color-bg-hover); }
1420
+ }
1421
+ /* Error variant — red accent on tag, title, and left edge */
1422
+ &.mv-system-error {
1423
+ border-left: 3px solid oklch(0.55 0.22 25);
1424
+ .mv-system-tag { color: oklch(0.55 0.22 25); border-color: oklch(0.55 0.22 25); }
1425
+ .mv-system-title { color: oklch(0.55 0.22 25); }
1426
+ }
1427
+ }
1428
+
1429
+ /* ── Message Viewer ── */
1430
+
1431
+ .message-viewer {
1432
+ display: flex;
1433
+ flex-direction: column;
1434
+ overflow: hidden;
1435
+ }
1436
+
1437
+ .mv-header {
1438
+ padding: var(--gap-sm) var(--gap-md);
1439
+ border-bottom: 1px solid var(--color-border);
1440
+ background: var(--color-bg-surface);
1441
+ font-size: var(--font-size-sm);
1442
+ line-height: 1.5;
1443
+
1444
+ .mv-toolbar {
1445
+ display: flex;
1446
+ align-items: center;
1447
+ gap: var(--gap-xs);
1448
+ padding-bottom: var(--gap-xs);
1449
+ border-bottom: 1px solid var(--color-border);
1450
+ margin-bottom: var(--gap-xs);
1451
+ }
1452
+ .mv-header-info { }
1453
+ .mv-header-actions { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex-shrink: 0; }
1454
+ .mv-from { font-weight: 600; }
1455
+ .mv-to { color: var(--color-text-muted); }
1456
+ .mv-subject { font-size: var(--font-size-lg); font-weight: 600; margin-top: var(--gap-xs); }
1457
+ .mv-date { color: var(--color-text-muted); font-size: var(--font-size-sm); }
1458
+ .mv-unsubscribe {
1459
+ font-size: var(--font-size-sm);
1460
+ color: var(--color-danger);
1461
+ cursor: pointer;
1462
+ text-decoration: underline;
1463
+ white-space: nowrap;
1464
+ }
1465
+ .mv-action {
1466
+ font-size: var(--font-size-sm);
1467
+ padding: 2px 6px;
1468
+ border: 1px solid var(--color-border);
1469
+ border-radius: var(--radius-sm);
1470
+ background: transparent;
1471
+ color: var(--color-text-muted);
1472
+ cursor: pointer;
1473
+ white-space: nowrap;
1474
+ }
1475
+ .mv-action:hover { background: var(--color-bg-hover); color: var(--color-text); }
1476
+ .mv-details {
1477
+ font-size: var(--font-size-sm);
1478
+ color: var(--color-text-muted);
1479
+ border-top: 1px solid var(--color-border);
1480
+ padding-top: var(--gap-xs);
1481
+ margin-top: var(--gap-xs);
1482
+ line-height: 1.6;
1483
+ }
1484
+ .mv-details-label {
1485
+ display: inline-block;
1486
+ min-width: 7em;
1487
+ color: var(--color-text);
1488
+ font-weight: 600;
1489
+ }
1490
+ .mv-details-row {
1491
+ display: flex;
1492
+ align-items: center;
1493
+ gap: 6px;
1494
+ padding: 2px 0;
1495
+ }
1496
+ .mv-details-value {
1497
+ flex: 1;
1498
+ font-family: var(--font-mono);
1499
+ font-size: 0.85em;
1500
+ word-break: break-all;
1501
+ }
1502
+ .mv-details-copy {
1503
+ background: none;
1504
+ border: none;
1505
+ cursor: pointer;
1506
+ color: var(--color-text-muted);
1507
+ font-size: 1rem;
1508
+ padding: 0 4px;
1509
+ border-radius: 3px;
1510
+
1511
+ &:hover { background: var(--color-bg-hover); color: var(--color-text); }
1512
+ }
1513
+ .mv-action-primary {
1514
+ background: var(--color-brand-dark) !important;
1515
+ color: white !important;
1516
+ border-color: var(--color-brand-dark) !important;
1517
+ }
1518
+ .mv-action-primary:hover { opacity: 0.85; }
1519
+ }
1520
+
1521
+ .mv-remote-banner {
1522
+ background: oklch(0.45 0.12 60);
1523
+ color: white;
1524
+ font-size: var(--font-size-sm);
1525
+ font-weight: 600;
1526
+ }
1527
+
1528
+ /* Flagged sender or domain — red strip above the normal banner. */
1529
+ .mv-rb-flagged {
1530
+ background: oklch(0.42 0.20 25);
1531
+ color: white;
1532
+ padding: var(--gap-xs) var(--gap-md);
1533
+ font-weight: 700;
1534
+ letter-spacing: 0.02em;
1535
+ }
1536
+ .mv-remote-banner-flagged { box-shadow: inset 0 0 0 2px oklch(0.55 0.22 25); }
1537
+ .mv-rb-flag-btn { background: oklch(0.42 0.20 25); }
1538
+
1539
+ /* External reputation hit (Spamhaus DBL etc) — orange strip, distinct from
1540
+ the user's manual red flag. Renders below the user-flag strip when both
1541
+ are present so the precedence is visible. */
1542
+ .mv-rb-reputation {
1543
+ background: oklch(0.55 0.18 50);
1544
+ color: white;
1545
+ padding: var(--gap-xs) var(--gap-md);
1546
+ font-weight: 600;
1547
+ letter-spacing: 0.02em;
1548
+ }
1549
+ .mv-remote-banner-reputation { box-shadow: inset 0 0 0 2px oklch(0.65 0.20 50); }
1550
+
1551
+ .mv-rb-summary {
1552
+ display: flex;
1553
+ align-items: center;
1554
+ gap: var(--gap-sm);
1555
+ padding: var(--gap-xs) var(--gap-md);
1556
+ cursor: pointer;
1557
+ flex-wrap: wrap;
1558
+ }
1559
+
1560
+ .mv-rb-toggle {
1561
+ font-size: 0.8em;
1562
+ width: 1em;
1563
+ display: inline-block;
1564
+ flex-shrink: 0;
1565
+ }
1566
+
1567
+ .mv-rb-buttons {
1568
+ display: flex;
1569
+ flex-wrap: wrap;
1570
+ gap: var(--gap-xs);
1571
+ margin-left: auto;
1572
+ }
1573
+
1574
+ .mv-rb-details {
1575
+ padding: var(--gap-xs) var(--gap-md) var(--gap-sm);
1576
+ border-top: 1px solid rgba(255,255,255,0.2);
1577
+ }
1578
+
1579
+ .mv-rb-info {
1580
+ font-weight: 400;
1581
+ line-height: 1.6;
1582
+ margin-bottom: var(--gap-sm);
1583
+ }
1584
+
1585
+ .mv-rb-actions {
1586
+ display: flex;
1587
+ flex-wrap: wrap;
1588
+ gap: var(--gap-xs);
1589
+ }
1590
+
1591
+ .mv-rb-label {
1592
+ color: rgba(255,255,255,0.7);
1593
+ font-weight: 600;
1594
+ display: inline-block;
1595
+ min-width: 6em;
1596
+ }
1597
+
1598
+ .mv-remote-banner button {
1599
+ padding: var(--gap-xs) var(--gap-sm);
1600
+ border: 1px solid white;
1601
+ border-radius: var(--radius-sm);
1602
+ background: transparent;
1603
+ color: white;
1604
+ font-size: var(--font-size-sm);
1605
+ cursor: pointer;
1606
+ font-weight: 600;
1607
+ }
1608
+
1609
+ .mv-remote-banner button:hover {
1610
+ background: rgba(255,255,255,0.2);
1611
+ }
1612
+
1613
+ .mv-body {
1614
+ flex: 1;
1615
+ overflow: hidden;
1616
+ background: var(--color-bg-surface);
1617
+
1618
+ iframe {
1619
+ width: 100%;
1620
+ height: 100%;
1621
+ border: none;
1622
+ }
1623
+ }
1624
+
1625
+ .mv-attachments {
1626
+ display: flex;
1627
+ flex-wrap: wrap;
1628
+ gap: var(--gap-xs);
1629
+ padding: var(--gap-sm) var(--gap-md);
1630
+ border-top: 1px solid var(--color-border);
1631
+ background: var(--color-bg-toolbar);
1632
+ }
1633
+
1634
+ .mv-att-chip {
1635
+ display: inline-flex;
1636
+ align-items: center;
1637
+ gap: var(--gap-xs);
1638
+ padding: var(--gap-xs) var(--gap-sm);
1639
+ border: 1px solid var(--color-border);
1640
+ border-radius: var(--radius-sm);
1641
+ font-size: var(--font-size-sm);
1642
+ cursor: pointer;
1643
+ color: var(--color-text);
1644
+ text-decoration: none;
1645
+
1646
+ &:hover { background: var(--color-bg-hover); }
1647
+ }
1648
+
1649
+ /* ── Status Bar ── */
1650
+
1651
+ .status-bar {
1652
+ display: flex;
1653
+ align-items: center;
1654
+ gap: var(--gap-lg);
1655
+ padding: 0 var(--gap-sm);
1656
+ background: var(--color-bg-toolbar);
1657
+ border-top: 1px solid var(--color-border);
1658
+ font-size: var(--font-size-sm);
1659
+ color: var(--color-text-muted);
1660
+ }
1661
+
1662
+ /* Diagnostics ⚠ badge next to status-sync — inactivity timeouts and similar
1663
+ server-misbehavior counters. Hover for per-account detail. */
1664
+ .status-diag {
1665
+ color: oklch(0.70 0.18 55); /* amber */
1666
+ cursor: help;
1667
+ font-size: var(--font-size-base);
1668
+ margin-left: calc(var(--gap-xs) * -1);
1669
+ }
1670
+ .status-action {
1671
+ border: 1px solid oklch(0.65 0.15 25);
1672
+ background: transparent;
1673
+ color: oklch(0.75 0.15 25);
1674
+ padding: 1px 8px;
1675
+ border-radius: var(--radius-sm);
1676
+ font-size: var(--font-size-sm);
1677
+ cursor: pointer;
1678
+ margin-left: var(--gap-xs);
1679
+ }
1680
+ .status-action:hover { background: oklch(0.65 0.15 25); color: #fff; }
1681
+ .status-action:disabled { opacity: 0.5; cursor: default; }
1682
+
1683
+ /* ── Address Book ── */
1684
+ .ab-toolbar {
1685
+ display: flex;
1686
+ gap: var(--gap-sm);
1687
+ align-items: center;
1688
+ }
1689
+ .ab-toolbar input {
1690
+ flex: 1;
1691
+ }
1692
+ .ab-count {
1693
+ font-size: var(--font-size-sm);
1694
+ color: var(--color-text-muted);
1695
+ }
1696
+ .ab-list {
1697
+ flex: 1;
1698
+ overflow: auto;
1699
+ border: 1px solid var(--color-border);
1700
+ border-radius: var(--radius-sm);
1701
+ min-height: 240px;
1702
+ }
1703
+ .ab-row {
1704
+ display: grid;
1705
+ grid-template-columns: 180px minmax(220px, 1fr) 80px 50px 80px 96px;
1706
+ gap: var(--gap-sm);
1707
+ padding: 4px 8px;
1708
+ align-items: center;
1709
+ border-bottom: 1px solid var(--color-border-faint, rgba(0,0,0,0.05));
1710
+ font-size: var(--font-size-sm);
1711
+
1712
+ &:hover { background: var(--color-bg-hover); }
1713
+ &.ab-header {
1714
+ font-weight: 600;
1715
+ background: var(--color-bg-surface);
1716
+ position: sticky;
1717
+ top: 0;
1718
+ z-index: 1;
1719
+ }
1720
+ }
1721
+ .ab-name, .ab-email { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1722
+ .ab-name-input { width: 100%; box-sizing: border-box; }
1723
+ .ab-source { font-size: 0.75rem; color: var(--color-text-muted); text-transform: uppercase; }
1724
+ .ab-count-cell { text-align: right; color: var(--color-text-muted); }
1725
+ .ab-last { color: var(--color-text-muted); font-size: 0.85em; }
1726
+ .ab-actions { display: flex; gap: 2px; justify-content: flex-end; }
1727
+ .ab-actions button {
1728
+ background: none;
1729
+ border: none;
1730
+ cursor: pointer;
1731
+ padding: 2px 6px;
1732
+ border-radius: 3px;
1733
+ font-size: 0.9rem;
1734
+
1735
+ &:hover { background: var(--color-bg-hover); }
1736
+ }
1737
+ .ab-empty {
1738
+ padding: 24px;
1739
+ text-align: center;
1740
+ color: var(--color-text-muted);
1741
+ }
1742
+
1743
+ /* ── Calendar ── */
1744
+ .cal-grid {
1745
+ display: grid;
1746
+ grid-template-columns: 380px 1fr;
1747
+ gap: var(--gap-md);
1748
+ flex: 1;
1749
+ min-height: 0;
1750
+ }
1751
+ .cal-month, .cal-upcoming {
1752
+ display: flex;
1753
+ flex-direction: column;
1754
+ min-height: 0;
1755
+ }
1756
+ .cal-upcoming { overflow: auto; }
1757
+ .cal-nav {
1758
+ display: flex;
1759
+ align-items: center;
1760
+ gap: var(--gap-sm);
1761
+ padding: 4px 0;
1762
+ }
1763
+ .cal-nav-title { flex: 1; font-weight: 600; }
1764
+ .cal-nav-btn {
1765
+ background: none;
1766
+ border: 1px solid var(--color-border);
1767
+ border-radius: var(--radius-sm);
1768
+ padding: 2px 8px;
1769
+ cursor: pointer;
1770
+ font-size: 0.9rem;
1771
+
1772
+ &:hover { background: var(--color-bg-hover); }
1773
+ }
1774
+ .cal-month-grid {
1775
+ display: grid;
1776
+ grid-template-columns: repeat(7, 1fr);
1777
+ gap: 2px;
1778
+ }
1779
+ .cal-dow {
1780
+ text-align: center;
1781
+ font-size: 0.75rem;
1782
+ color: var(--color-text-muted);
1783
+ padding: 4px 0;
1784
+ }
1785
+ .cal-day {
1786
+ aspect-ratio: 1;
1787
+ border: 1px solid transparent;
1788
+ background: none;
1789
+ cursor: pointer;
1790
+ border-radius: var(--radius-sm);
1791
+ font-size: 0.85rem;
1792
+ color: var(--color-text);
1793
+
1794
+ &.cal-day-blank { visibility: hidden; cursor: default; }
1795
+ &:hover:not(.cal-day-blank) { background: var(--color-bg-hover); }
1796
+ &.cal-day-today { font-weight: 700; color: var(--color-accent); }
1797
+ &.cal-day-selected { background: var(--color-accent); color: #fff; }
1798
+ &.cal-day-has-event::after {
1799
+ content: "•";
1800
+ display: block;
1801
+ margin-top: -4px;
1802
+ font-size: 0.6rem;
1803
+ }
1804
+ }
1805
+ .cal-section-title {
1806
+ font-weight: 600;
1807
+ margin-bottom: var(--gap-sm);
1808
+ color: var(--color-text-muted);
1809
+ }
1810
+ .cal-event {
1811
+ border-left: 3px solid var(--color-accent);
1812
+ padding: 6px 8px;
1813
+ margin-bottom: 6px;
1814
+ background: var(--color-bg-surface);
1815
+ border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
1816
+ position: relative;
1817
+ }
1818
+ .cal-event-time { font-size: 0.75rem; color: var(--color-text-muted); }
1819
+ .cal-event-title { font-weight: 500; }
1820
+ .cal-event-loc { font-size: 0.85rem; color: var(--color-text-muted); }
1821
+ .cal-event-del {
1822
+ position: absolute;
1823
+ right: 4px;
1824
+ top: 4px;
1825
+ background: none;
1826
+ border: none;
1827
+ cursor: pointer;
1828
+ color: var(--color-text-muted);
1829
+ font-size: 1.1rem;
1830
+
1831
+ &:hover { color: oklch(0.65 0.2 25); }
1832
+ }
1833
+ .cal-empty { color: var(--color-text-muted); padding: 12px 0; }
1834
+ .cal-source-note { font-size: 0.75rem; color: var(--color-text-muted); }
1835
+
1836
+ /* ── Tasks ── */
1837
+ .tk-toolbar { padding-bottom: var(--gap-sm); }
1838
+ .tk-toolbar input { width: 100%; box-sizing: border-box; }
1839
+ .tk-filters {
1840
+ display: flex;
1841
+ gap: 4px;
1842
+ align-items: center;
1843
+ padding-bottom: var(--gap-sm);
1844
+ border-bottom: 1px solid var(--color-border);
1845
+ }
1846
+ .tk-filter-btn {
1847
+ background: none;
1848
+ border: 1px solid transparent;
1849
+ padding: 4px 10px;
1850
+ cursor: pointer;
1851
+ border-radius: var(--radius-sm);
1852
+ color: var(--color-text-muted);
1853
+ font-size: var(--font-size-sm);
1854
+
1855
+ &:hover { background: var(--color-bg-hover); }
1856
+ &.tk-filter-active {
1857
+ background: var(--color-bg-surface);
1858
+ border-color: var(--color-border);
1859
+ color: var(--color-text);
1860
+ font-weight: 500;
1861
+ }
1862
+ }
1863
+ .tk-spacer { flex: 1; }
1864
+ .tk-count { font-size: var(--font-size-sm); color: var(--color-text-muted); }
1865
+ .tk-list {
1866
+ flex: 1;
1867
+ overflow: auto;
1868
+ min-height: 240px;
1869
+ }
1870
+ .tk-row {
1871
+ display: grid;
1872
+ grid-template-columns: 24px 24px minmax(180px, 1fr) auto 80px 28px 28px;
1873
+ gap: var(--gap-sm);
1874
+ padding: 6px 4px;
1875
+ align-items: center;
1876
+ border-bottom: 1px solid var(--color-border-faint, rgba(0,0,0,0.05));
1877
+
1878
+ &:hover { background: var(--color-bg-hover); }
1879
+ &.tk-done .tk-title { text-decoration: line-through; color: var(--color-text-muted); }
1880
+ }
1881
+ .tk-prio {
1882
+ text-align: center;
1883
+ font-weight: 700;
1884
+
1885
+ &.tk-prio-3 { color: oklch(0.65 0.2 25); }
1886
+ &.tk-prio-2 { color: oklch(0.7 0.18 60); }
1887
+ &.tk-prio-1 { color: var(--color-text-muted); }
1888
+ }
1889
+ .tk-title {
1890
+ outline: none;
1891
+ padding: 2px 4px;
1892
+ border-radius: 3px;
1893
+
1894
+ &:focus { background: var(--color-bg-surface); box-shadow: inset 0 0 0 1px var(--color-accent); }
1895
+ }
1896
+ .tk-tags {
1897
+ color: var(--color-accent);
1898
+ font-size: 0.85em;
1899
+ }
1900
+ .tk-due {
1901
+ text-align: right;
1902
+ color: var(--color-text-muted);
1903
+ font-size: 0.85em;
1904
+
1905
+ &.tk-overdue { color: oklch(0.65 0.2 25); font-weight: 500; }
1906
+ }
1907
+ .tk-snooze, .tk-del {
1908
+ background: none;
1909
+ border: none;
1910
+ cursor: pointer;
1911
+ color: var(--color-text-muted);
1912
+ padding: 2px 4px;
1913
+ border-radius: 3px;
1914
+
1915
+ &:hover { background: var(--color-bg-hover); color: var(--color-text); }
1916
+ }
1917
+ .tk-empty {
1918
+ padding: 24px;
1919
+ text-align: center;
1920
+ color: var(--color-text-muted);
1921
+ }
1922
+
1923
+ /* Server-search orthogonal checkbox */
1924
+ .search-server-check {
1925
+ display: inline-flex;
1926
+ align-items: center;
1927
+ gap: 4px;
1928
+ margin-left: 6px;
1929
+ padding: 2px 6px;
1930
+ font-size: 0.85rem;
1931
+ color: var(--color-text-muted);
1932
+ cursor: pointer;
1933
+ border-radius: var(--radius-sm);
1934
+
1935
+ &:has(input:checked) {
1936
+ color: var(--color-accent);
1937
+ font-weight: 500;
1938
+ }
1939
+ }
1940
+
1941
+ /* ── Outbox / Pink-row view ── */
1942
+ .ob-info {
1943
+ color: var(--color-text-muted);
1944
+ font-size: var(--font-size-sm);
1945
+ padding-bottom: var(--gap-sm);
1946
+ }
1947
+ .ob-list {
1948
+ flex: 1;
1949
+ overflow: auto;
1950
+ min-height: 200px;
1951
+ }
1952
+ .ob-row {
1953
+ border: 1px solid var(--color-border);
1954
+ border-radius: var(--radius-sm);
1955
+ padding: 8px 12px;
1956
+ margin-bottom: 8px;
1957
+ position: relative;
1958
+ font-size: 0.9rem;
1959
+ }
1960
+ .ob-pink {
1961
+ /* Visible-reconciliation-state: local-only not yet on the server. */
1962
+ background: color-mix(in oklch, oklch(0.75 0.15 350) 15%, var(--color-bg-surface));
1963
+ border-color: oklch(0.7 0.15 350);
1964
+ }
1965
+ .ob-row-hdr {
1966
+ display: flex;
1967
+ gap: 8px;
1968
+ align-items: baseline;
1969
+ flex-wrap: wrap;
1970
+ margin-bottom: 4px;
1971
+ }
1972
+ .ob-acct {
1973
+ font-size: 0.75rem;
1974
+ color: var(--color-text-muted);
1975
+ background: var(--color-bg);
1976
+ padding: 1px 6px;
1977
+ border-radius: 3px;
1978
+ text-transform: uppercase;
1979
+ }
1980
+ .ob-subject { font-weight: 600; flex: 1; }
1981
+ .ob-created { color: var(--color-text-muted); font-size: 0.8rem; }
1982
+ .ob-badge {
1983
+ font-size: 0.75rem;
1984
+ padding: 1px 6px;
1985
+ border-radius: 10px;
1986
+ background: var(--color-bg);
1987
+ color: var(--color-text-muted);
1988
+ }
1989
+ .ob-claimed { background: oklch(0.7 0.15 200); color: #fff; }
1990
+ .ob-retry { background: oklch(0.75 0.15 60); color: #fff; }
1991
+ .ob-row-meta { font-size: 0.85rem; color: var(--color-text-muted); }
1992
+ .ob-row-path {
1993
+ font-family: var(--font-mono);
1994
+ font-size: 0.75rem;
1995
+ color: var(--color-text-muted);
1996
+ margin-top: 4px;
1997
+ word-break: break-all;
1998
+ }
1999
+ .ob-row-actions { margin-top: 6px; }
2000
+ .ob-cancel {
2001
+ background: none;
2002
+ border: 1px solid oklch(0.65 0.2 25);
2003
+ color: oklch(0.65 0.2 25);
2004
+ padding: 3px 10px;
2005
+ border-radius: var(--radius-sm);
2006
+ cursor: pointer;
2007
+ font-size: 0.85rem;
2008
+
2009
+ &:hover:not(:disabled) { background: oklch(0.65 0.2 25); color: #fff; }
2010
+ &:disabled { opacity: 0.5; cursor: not-allowed; }
2011
+ }
2012
+ .ob-empty { padding: 24px; text-align: center; color: var(--color-text-muted); }
2013
+
2014
+ /* ── Startup Overlay ── */
2015
+
2016
+ .startup-overlay {
2017
+ position: fixed;
2018
+ inset: var(--toolbar-height) 0 var(--statusbar-height) 0;
2019
+ display: flex;
2020
+ align-items: center;
2021
+ justify-content: center;
2022
+ background: var(--color-bg);
2023
+ z-index: 100;
2024
+ transition: opacity 0.3s ease;
2025
+ }
2026
+
2027
+ .startup-overlay.hidden {
2028
+ opacity: 0;
2029
+ pointer-events: none;
2030
+ }
2031
+
2032
+ .startup-content {
2033
+ text-align: center;
2034
+ color: var(--color-text);
2035
+ }
2036
+
2037
+ .startup-spinner {
2038
+ width: 32px;
2039
+ height: 32px;
2040
+ margin: 0 auto var(--gap-md);
2041
+ border: 3px solid var(--color-border);
2042
+ border-top-color: var(--color-brand-dark);
2043
+ border-radius: 50%;
2044
+ animation: spin 1s linear infinite;
2045
+ }
2046
+
2047
+ #startup-status {
2048
+ font-size: var(--font-size-lg);
2049
+ }