@jant/core 0.3.26 → 0.3.28

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 (314) hide show
  1. package/dist/client/client.css +1 -0
  2. package/dist/client/client.js +31561 -0
  3. package/dist/index.js +15209 -15
  4. package/package.json +21 -15
  5. package/src/__tests__/helpers/app.ts +19 -3
  6. package/src/__tests__/helpers/db.ts +44 -0
  7. package/src/__tests__/helpers/lingui-core-macro-mock.ts +33 -0
  8. package/src/app.tsx +112 -173
  9. package/src/auth.ts +4 -1
  10. package/src/client.ts +13 -0
  11. package/src/db/migrations/0007_post_collections_m2m.sql +94 -0
  12. package/src/db/migrations/0008_add_collection_dividers.sql +8 -0
  13. package/src/db/migrations/0009_drop_collection_show_divider.sql +2 -0
  14. package/src/db/migrations/0010_add_performance_indexes.sql +16 -0
  15. package/src/db/schema.ts +24 -4
  16. package/src/i18n/locales/en.po +810 -385
  17. package/src/i18n/locales/en.ts +1 -1
  18. package/src/i18n/locales/zh-Hans.po +733 -522
  19. package/src/i18n/locales/zh-Hans.ts +1 -1
  20. package/src/i18n/locales/zh-Hant.po +733 -522
  21. package/src/i18n/locales/zh-Hant.ts +1 -1
  22. package/src/i18n/middleware.ts +7 -11
  23. package/src/index.ts +1 -1
  24. package/src/lib/__tests__/icons.test.ts +178 -0
  25. package/src/lib/__tests__/resolve-config.test.ts +184 -0
  26. package/src/lib/__tests__/schemas.test.ts +12 -6
  27. package/src/lib/__tests__/theme.test.ts +62 -0
  28. package/src/lib/__tests__/timezones.test.ts +1 -1
  29. package/src/lib/__tests__/url.test.ts +12 -0
  30. package/src/lib/__tests__/view.test.ts +1 -5
  31. package/src/lib/avatar-upload.ts +18 -10
  32. package/src/lib/collection-form-bridge.ts +52 -0
  33. package/src/lib/collections-reorder.ts +28 -0
  34. package/src/lib/compose-bridge.ts +251 -0
  35. package/src/lib/errors.ts +116 -0
  36. package/src/lib/excerpt.ts +1 -1
  37. package/src/lib/favicon.ts +3 -5
  38. package/src/lib/html.ts +22 -0
  39. package/src/lib/icon-catalog.ts +181 -0
  40. package/src/lib/icons.ts +202 -0
  41. package/src/lib/navigation.ts +18 -33
  42. package/src/lib/pagination.ts +3 -2
  43. package/src/lib/post-form-bridge.ts +136 -0
  44. package/src/lib/render.tsx +11 -4
  45. package/src/lib/resolve-config.ts +157 -0
  46. package/src/lib/schemas.ts +76 -12
  47. package/src/lib/settings-bridge.ts +139 -0
  48. package/src/lib/storage.ts +37 -16
  49. package/src/lib/theme.ts +5 -7
  50. package/src/lib/timeline.ts +4 -8
  51. package/src/lib/toast.ts +134 -0
  52. package/src/lib/upload.ts +71 -0
  53. package/src/lib/url.ts +9 -1
  54. package/src/lib/version.ts +16 -0
  55. package/src/lib/view.ts +9 -10
  56. package/src/middleware/__tests__/auth.test.ts +6 -28
  57. package/src/middleware/__tests__/onboarding.test.ts +1 -1
  58. package/src/middleware/auth.ts +6 -12
  59. package/src/middleware/config.ts +51 -0
  60. package/src/middleware/error-handler.ts +56 -0
  61. package/src/middleware/onboarding.ts +1 -1
  62. package/src/preset.css +6 -0
  63. package/src/routes/__tests__/compose.test.ts +104 -17
  64. package/src/routes/api/__tests__/collections.test.ts +93 -2
  65. package/src/routes/api/__tests__/posts.test.ts +2 -1
  66. package/src/routes/api/__tests__/settings.test.ts +1 -1
  67. package/src/routes/api/collections.ts +64 -68
  68. package/src/routes/api/nav-items.ts +21 -59
  69. package/src/routes/api/pages.ts +18 -46
  70. package/src/routes/api/posts.ts +64 -86
  71. package/src/routes/api/search.ts +6 -4
  72. package/src/routes/api/settings.ts +8 -24
  73. package/src/routes/api/upload.ts +55 -53
  74. package/src/routes/auth/__tests__/setup.test.ts +118 -0
  75. package/src/routes/auth/reset.tsx +17 -66
  76. package/src/routes/auth/setup.tsx +67 -11
  77. package/src/routes/auth/signin.tsx +44 -8
  78. package/src/routes/compose.tsx +194 -0
  79. package/src/routes/dash/__tests__/font-theme.test.ts +110 -0
  80. package/src/routes/dash/__tests__/pages.test.ts +2 -2
  81. package/src/routes/dash/__tests__/settings-avatar.test.ts +23 -12
  82. package/src/routes/dash/appearance.tsx +173 -0
  83. package/src/routes/dash/collections.tsx +80 -14
  84. package/src/routes/dash/index.tsx +12 -14
  85. package/src/routes/dash/media.tsx +46 -49
  86. package/src/routes/dash/pages.tsx +85 -37
  87. package/src/routes/dash/posts.tsx +60 -23
  88. package/src/routes/dash/redirects.tsx +43 -33
  89. package/src/routes/dash/settings.tsx +234 -214
  90. package/src/routes/feed/__tests__/rss.test.ts +7 -3
  91. package/src/routes/feed/rss.ts +11 -16
  92. package/src/routes/feed/sitemap.ts +15 -9
  93. package/src/routes/pages/__tests__/collections.test.ts +9 -8
  94. package/src/routes/pages/archive.tsx +2 -2
  95. package/src/routes/pages/collection.tsx +76 -9
  96. package/src/routes/pages/collections.tsx +3 -1
  97. package/src/routes/pages/featured.tsx +2 -2
  98. package/src/routes/pages/home.tsx +3 -3
  99. package/src/routes/pages/latest.tsx +2 -2
  100. package/src/routes/pages/page.tsx +2 -2
  101. package/src/routes/pages/post.tsx +2 -2
  102. package/src/routes/pages/search.tsx +2 -2
  103. package/src/services/__tests__/collection.test.ts +324 -34
  104. package/src/services/__tests__/media.test.ts +1 -1
  105. package/src/services/__tests__/page.test.ts +116 -1
  106. package/src/services/auth.ts +88 -0
  107. package/src/services/collection.ts +169 -30
  108. package/src/services/index.ts +8 -3
  109. package/src/services/media.ts +39 -12
  110. package/src/services/navigation.ts +17 -5
  111. package/src/services/page.ts +24 -4
  112. package/src/services/post.ts +87 -19
  113. package/src/services/search.ts +0 -1
  114. package/src/services/settings.ts +21 -13
  115. package/src/style.css +3 -0
  116. package/src/styles/components.css +42 -1
  117. package/src/styles/tokens.css +4 -0
  118. package/src/styles/ui.css +902 -73
  119. package/src/types/app-context.ts +25 -0
  120. package/src/types/bindings.ts +1 -0
  121. package/src/types/config.ts +60 -23
  122. package/src/types/entities.ts +12 -2
  123. package/src/types/lingui-react-macro.d.ts +3 -3
  124. package/src/types/operations.ts +2 -4
  125. package/src/types/views.ts +1 -3
  126. package/src/ui/__tests__/font-themes.test.ts +27 -8
  127. package/src/ui/color-themes.ts +1 -1
  128. package/src/ui/components/__tests__/jant-collection-form.test.ts +153 -0
  129. package/src/ui/components/__tests__/jant-compose-dialog.test.ts +512 -0
  130. package/src/ui/components/__tests__/jant-compose-editor.test.ts +272 -0
  131. package/src/ui/components/__tests__/jant-post-form.test.ts +172 -0
  132. package/src/ui/components/__tests__/jant-settings-avatar.test.ts +235 -0
  133. package/src/ui/components/__tests__/jant-settings-general.test.ts +319 -0
  134. package/src/ui/components/collection-types.ts +45 -0
  135. package/src/ui/components/compose-types.ts +75 -0
  136. package/src/ui/components/jant-collection-form.ts +512 -0
  137. package/src/ui/components/jant-compose-dialog.ts +494 -0
  138. package/src/ui/components/jant-compose-editor.ts +799 -0
  139. package/src/ui/components/jant-post-form.ts +290 -0
  140. package/src/ui/components/jant-settings-avatar.ts +231 -0
  141. package/src/ui/components/jant-settings-general.ts +436 -0
  142. package/src/ui/components/post-form-template.ts +260 -0
  143. package/src/ui/components/post-form-types.ts +87 -0
  144. package/src/ui/components/settings-types.ts +62 -0
  145. package/src/ui/compose/ComposeDialog.tsx +141 -385
  146. package/src/ui/compose/ComposePrompt.tsx +3 -3
  147. package/src/ui/dash/PostList.tsx +55 -61
  148. package/src/ui/dash/appearance/AdvancedContent.tsx +80 -0
  149. package/src/ui/dash/appearance/AppearanceNav.tsx +56 -0
  150. package/src/ui/dash/appearance/ColorThemeContent.tsx +129 -0
  151. package/src/ui/dash/appearance/FontThemeContent.tsx +98 -0
  152. package/src/ui/dash/collections/CollectionForm.tsx +130 -117
  153. package/src/ui/dash/collections/CollectionsListContent.tsx +102 -41
  154. package/src/ui/dash/collections/IconPickerGrid.tsx +50 -0
  155. package/src/ui/dash/collections/ViewCollectionContent.tsx +14 -3
  156. package/src/ui/dash/index.ts +1 -1
  157. package/src/ui/dash/posts/PostForm.tsx +248 -0
  158. package/src/ui/dash/settings/AccountContent.tsx +69 -80
  159. package/src/ui/dash/settings/GeneralContent.tsx +159 -478
  160. package/src/ui/dash/settings/SettingsNav.tsx +4 -4
  161. package/src/ui/font-themes.ts +115 -32
  162. package/src/ui/layouts/BaseLayout.tsx +49 -19
  163. package/src/ui/layouts/DashLayout.tsx +14 -9
  164. package/src/ui/layouts/SiteLayout.tsx +38 -23
  165. package/src/ui/pages/CollectionPage.tsx +12 -2
  166. package/src/ui/pages/CollectionsPage.tsx +27 -27
  167. package/src/ui/pages/HomePage.tsx +15 -6
  168. package/src/ui/pages/SearchPage.tsx +1 -2
  169. package/src/ui/shared/CollectionsSidebar.tsx +59 -0
  170. package/src/ui/shared/Pagination.tsx +2 -2
  171. package/dist/app.js +0 -265
  172. package/dist/auth.js +0 -36
  173. package/dist/client.js +0 -13
  174. package/dist/db/index.js +0 -10
  175. package/dist/db/schema.js +0 -224
  176. package/dist/i18n/Trans.js +0 -24
  177. package/dist/i18n/context.js +0 -58
  178. package/dist/i18n/detect.js +0 -26
  179. package/dist/i18n/i18n.js +0 -49
  180. package/dist/i18n/index.js +0 -44
  181. package/dist/i18n/locales/en.js +0 -1
  182. package/dist/i18n/locales/zh-Hans.js +0 -1
  183. package/dist/i18n/locales/zh-Hant.js +0 -1
  184. package/dist/i18n/locales.js +0 -13
  185. package/dist/i18n/middleware.js +0 -30
  186. package/dist/lib/avatar-upload.js +0 -134
  187. package/dist/lib/config.js +0 -143
  188. package/dist/lib/constants.js +0 -50
  189. package/dist/lib/excerpt.js +0 -76
  190. package/dist/lib/favicon.js +0 -102
  191. package/dist/lib/feed.js +0 -123
  192. package/dist/lib/image-processor.js +0 -187
  193. package/dist/lib/image.js +0 -97
  194. package/dist/lib/index.js +0 -7
  195. package/dist/lib/markdown.js +0 -83
  196. package/dist/lib/media-helpers.js +0 -49
  197. package/dist/lib/media-upload.js +0 -104
  198. package/dist/lib/nav-reorder.js +0 -27
  199. package/dist/lib/navigation.js +0 -79
  200. package/dist/lib/pagination.js +0 -44
  201. package/dist/lib/render.js +0 -53
  202. package/dist/lib/schemas.js +0 -174
  203. package/dist/lib/sqid.js +0 -72
  204. package/dist/lib/sse.js +0 -218
  205. package/dist/lib/storage.js +0 -164
  206. package/dist/lib/theme.js +0 -65
  207. package/dist/lib/time.js +0 -159
  208. package/dist/lib/timeline.js +0 -95
  209. package/dist/lib/timezones.js +0 -388
  210. package/dist/lib/url.js +0 -89
  211. package/dist/lib/view.js +0 -217
  212. package/dist/middleware/auth.js +0 -52
  213. package/dist/middleware/onboarding.js +0 -41
  214. package/dist/routes/api/collections.js +0 -124
  215. package/dist/routes/api/nav-items.js +0 -104
  216. package/dist/routes/api/pages.js +0 -91
  217. package/dist/routes/api/posts.js +0 -218
  218. package/dist/routes/api/search.js +0 -48
  219. package/dist/routes/api/settings.js +0 -68
  220. package/dist/routes/api/upload.js +0 -246
  221. package/dist/routes/auth/reset.js +0 -221
  222. package/dist/routes/auth/setup.js +0 -194
  223. package/dist/routes/auth/signin.js +0 -176
  224. package/dist/routes/compose.js +0 -48
  225. package/dist/routes/dash/collections.js +0 -115
  226. package/dist/routes/dash/index.js +0 -118
  227. package/dist/routes/dash/media.js +0 -106
  228. package/dist/routes/dash/pages.js +0 -294
  229. package/dist/routes/dash/posts.js +0 -244
  230. package/dist/routes/dash/redirects.js +0 -257
  231. package/dist/routes/dash/settings.js +0 -379
  232. package/dist/routes/feed/rss.js +0 -62
  233. package/dist/routes/feed/sitemap.js +0 -49
  234. package/dist/routes/pages/archive.js +0 -62
  235. package/dist/routes/pages/collection.js +0 -34
  236. package/dist/routes/pages/collections.js +0 -28
  237. package/dist/routes/pages/featured.js +0 -36
  238. package/dist/routes/pages/home.js +0 -64
  239. package/dist/routes/pages/latest.js +0 -45
  240. package/dist/routes/pages/page.js +0 -68
  241. package/dist/routes/pages/post.js +0 -44
  242. package/dist/routes/pages/search.js +0 -54
  243. package/dist/services/collection.js +0 -109
  244. package/dist/services/index.js +0 -24
  245. package/dist/services/media.js +0 -117
  246. package/dist/services/navigation.js +0 -91
  247. package/dist/services/page.js +0 -84
  248. package/dist/services/post.js +0 -229
  249. package/dist/services/redirect.js +0 -48
  250. package/dist/services/search.js +0 -67
  251. package/dist/services/settings.js +0 -68
  252. package/dist/types/bindings.js +0 -3
  253. package/dist/types/config.js +0 -147
  254. package/dist/types/constants.js +0 -27
  255. package/dist/types/entities.js +0 -3
  256. package/dist/types/lingui-react-macro.d.js +0 -9
  257. package/dist/types/operations.js +0 -3
  258. package/dist/types/props.js +0 -3
  259. package/dist/types/sortablejs.d.js +0 -5
  260. package/dist/types/views.js +0 -5
  261. package/dist/types.js +0 -11
  262. package/dist/ui/color-themes.js +0 -268
  263. package/dist/ui/compose/ComposeDialog.js +0 -467
  264. package/dist/ui/compose/ComposePrompt.js +0 -55
  265. package/dist/ui/dash/ActionButtons.js +0 -46
  266. package/dist/ui/dash/CrudPageHeader.js +0 -22
  267. package/dist/ui/dash/DangerZone.js +0 -36
  268. package/dist/ui/dash/FormatBadge.js +0 -27
  269. package/dist/ui/dash/ListItemRow.js +0 -21
  270. package/dist/ui/dash/PageForm.js +0 -195
  271. package/dist/ui/dash/PostForm.js +0 -395
  272. package/dist/ui/dash/PostList.js +0 -83
  273. package/dist/ui/dash/StatusBadge.js +0 -46
  274. package/dist/ui/dash/collections/CollectionForm.js +0 -152
  275. package/dist/ui/dash/collections/CollectionsListContent.js +0 -68
  276. package/dist/ui/dash/collections/ViewCollectionContent.js +0 -96
  277. package/dist/ui/dash/index.js +0 -10
  278. package/dist/ui/dash/media/MediaListContent.js +0 -166
  279. package/dist/ui/dash/media/ViewMediaContent.js +0 -212
  280. package/dist/ui/dash/pages/LinkFormContent.js +0 -130
  281. package/dist/ui/dash/pages/UnifiedPagesContent.js +0 -193
  282. package/dist/ui/dash/settings/AccountContent.js +0 -209
  283. package/dist/ui/dash/settings/AppearanceContent.js +0 -259
  284. package/dist/ui/dash/settings/GeneralContent.js +0 -536
  285. package/dist/ui/dash/settings/SettingsNav.js +0 -41
  286. package/dist/ui/feed/LinkCard.js +0 -72
  287. package/dist/ui/feed/NoteCard.js +0 -58
  288. package/dist/ui/feed/QuoteCard.js +0 -63
  289. package/dist/ui/feed/ThreadPreview.js +0 -48
  290. package/dist/ui/feed/TimelineFeed.js +0 -41
  291. package/dist/ui/feed/TimelineItem.js +0 -27
  292. package/dist/ui/font-themes.js +0 -36
  293. package/dist/ui/layouts/BaseLayout.js +0 -153
  294. package/dist/ui/layouts/DashLayout.js +0 -141
  295. package/dist/ui/layouts/SiteLayout.js +0 -169
  296. package/dist/ui/pages/ArchivePage.js +0 -143
  297. package/dist/ui/pages/CollectionPage.js +0 -70
  298. package/dist/ui/pages/CollectionsPage.js +0 -76
  299. package/dist/ui/pages/FeaturedPage.js +0 -24
  300. package/dist/ui/pages/HomePage.js +0 -24
  301. package/dist/ui/pages/PostPage.js +0 -55
  302. package/dist/ui/pages/SearchPage.js +0 -122
  303. package/dist/ui/pages/SinglePage.js +0 -23
  304. package/dist/ui/shared/EmptyState.js +0 -27
  305. package/dist/ui/shared/MediaGallery.js +0 -35
  306. package/dist/ui/shared/Pagination.js +0 -195
  307. package/dist/ui/shared/ThreadView.js +0 -108
  308. package/dist/ui/shared/index.js +0 -5
  309. package/dist/vendor/datastar.js +0 -1606
  310. package/src/lib/__tests__/config.test.ts +0 -192
  311. package/src/lib/config.ts +0 -167
  312. package/src/routes/compose.ts +0 -63
  313. package/src/ui/dash/PostForm.tsx +0 -360
  314. package/src/ui/dash/settings/AppearanceContent.tsx +0 -254
package/src/styles/ui.css CHANGED
@@ -81,6 +81,10 @@
81
81
  background-color: var(--site-nav-hover-bg);
82
82
  }
83
83
 
84
+ .p-name {
85
+ font-family: var(--font-heading);
86
+ }
87
+
84
88
  .site-logo {
85
89
  display: flex;
86
90
  align-items: center;
@@ -176,6 +180,75 @@
176
180
  padding: 0 var(--site-padding);
177
181
  }
178
182
 
183
+ /* --- Sidebar layout (shared by dashboard and site sidebar pages) ------- */
184
+
185
+ .sidebar-layout {
186
+ display: flex;
187
+ gap: var(--sidebar-gap);
188
+ }
189
+
190
+ .sidebar-nav {
191
+ width: var(--sidebar-width);
192
+ flex-shrink: 0;
193
+ }
194
+
195
+ .sidebar-main {
196
+ flex: 1;
197
+ min-width: 0;
198
+ max-width: var(--site-width);
199
+ }
200
+
201
+ @media (max-width: 959px) {
202
+ .sidebar-layout {
203
+ display: block;
204
+ }
205
+ .sidebar-nav {
206
+ display: none;
207
+ }
208
+ .sidebar-main {
209
+ max-width: none;
210
+ }
211
+ }
212
+
213
+ .site-header-sidebar {
214
+ max-width: calc(
215
+ var(--sidebar-width) + var(--sidebar-gap) + var(--site-width)
216
+ );
217
+ }
218
+
219
+ .site-footer-sidebar {
220
+ max-width: calc(
221
+ var(--sidebar-width) + var(--sidebar-gap) + var(--site-width)
222
+ );
223
+ }
224
+
225
+ /* =========================================================================
226
+ * Collection Cards
227
+ * ========================================================================= */
228
+
229
+ .collection-card {
230
+ display: block;
231
+ padding: var(--card-padding);
232
+ border: 1px solid var(--site-divider);
233
+ border-radius: var(--media-radius);
234
+ transition:
235
+ border-color 0.15s,
236
+ box-shadow 0.15s;
237
+ }
238
+
239
+ .collection-card:hover {
240
+ border-color: var(--site-text-secondary);
241
+ }
242
+
243
+ .collection-card-icon {
244
+ display: flex;
245
+ align-items: center;
246
+ justify-content: center;
247
+ width: 1.25rem;
248
+ height: 1.25rem;
249
+ flex-shrink: 0;
250
+ }
251
+
179
252
  /* =========================================================================
180
253
  * Timeline & Post Components
181
254
  * ========================================================================= */
@@ -295,170 +368,926 @@
295
368
  * Compose Dialog
296
369
  * ========================================================================= */
297
370
 
298
- /* Dialog — positioned near top of viewport */
371
+ @keyframes compose-fade-up {
372
+ from {
373
+ opacity: 0;
374
+ transform: translateY(6px);
375
+ }
376
+ to {
377
+ opacity: 1;
378
+ transform: translateY(0);
379
+ }
380
+ }
381
+
382
+ @keyframes compose-modal-in {
383
+ from {
384
+ opacity: 0;
385
+ transform: scale(0.97) translateY(8px);
386
+ }
387
+ to {
388
+ opacity: 1;
389
+ transform: scale(1) translateY(0);
390
+ }
391
+ }
392
+
393
+ /* --- Dialog shell ------------------------------------------------------- */
394
+
299
395
  .compose-dialog {
396
+ --compose-margin-top: max(80px, 10vh);
397
+
300
398
  padding: 0;
301
399
  border: none;
302
- border-radius: 16px;
303
- max-width: 560px;
304
- width: calc(100% - 32px);
305
- max-height: calc(100dvh - 64px);
306
- margin: max(80px, 10vh) auto auto;
400
+ border-radius: 20px;
401
+ width: calc(100% - 20px);
402
+ max-width: calc(var(--site-width) - var(--site-padding) * 2 - 20px);
403
+ max-height: calc(100dvh - var(--compose-margin-top) - 20px);
404
+ margin: var(--compose-margin-top) auto auto;
307
405
  background-color: var(--site-elevated-bg);
308
406
  color: var(--site-text-primary);
309
407
  box-shadow:
310
- 0 25px 50px -12px rgba(0, 0, 0, 0.25),
311
- 0 0 0 1px var(--site-column-outline);
408
+ 0 8px 40px rgba(0, 0, 0, 0.08),
409
+ 0 1px 3px rgba(0, 0, 0, 0.04);
410
+ border: 1px solid var(--site-column-outline);
411
+ overflow: hidden;
412
+ }
413
+
414
+ .compose-dialog[open] {
415
+ animation: compose-modal-in 0.32s cubic-bezier(0.22, 1, 0.36, 1) both;
312
416
  }
313
417
 
314
418
  .compose-dialog::backdrop {
315
- background-color: rgba(0, 0, 0, 0.5);
419
+ background-color: rgba(0, 0, 0, 0.3);
316
420
  }
317
421
 
318
422
  .compose-dialog-inner {
319
423
  display: flex;
320
424
  flex-direction: column;
321
- max-height: calc(100dvh - 64px);
425
+ max-height: calc(100dvh - var(--compose-margin-top) - 20px);
426
+ position: relative;
322
427
  }
323
428
 
429
+ .compose-dialog-inner > jant-compose-editor {
430
+ flex: 1;
431
+ min-height: 0;
432
+ display: flex;
433
+ flex-direction: column;
434
+ overflow: hidden;
435
+ position: relative;
436
+ }
437
+
438
+ /* --- Header ------------------------------------------------------------- */
439
+
324
440
  .compose-dialog-header {
325
441
  display: flex;
326
442
  align-items: center;
327
443
  justify-content: space-between;
328
- padding: 16px 20px;
329
- border-bottom: var(--card-border-width) solid var(--site-divider);
444
+ padding: 10px 12px;
445
+ position: relative;
330
446
  }
331
447
 
332
- .compose-dialog-title {
333
- font-size: 1rem;
334
- font-weight: 600;
335
- margin: 0;
448
+ @media (min-width: 700px) {
449
+ .compose-dialog-header {
450
+ padding: 12px 16px;
451
+ }
452
+ }
453
+
454
+ .compose-dialog-cancel {
455
+ padding: 4px 8px;
456
+ border: none;
457
+ background: none;
458
+ border-radius: 6px;
459
+ color: var(--site-text-secondary);
460
+ font-size: var(--text-sm);
461
+ cursor: pointer;
462
+ transition: color 0.15s ease-out;
463
+ flex-shrink: 0;
464
+ min-width: 60px;
465
+ text-align: left;
336
466
  }
337
467
 
338
- .compose-dialog-close {
468
+ .compose-dialog-cancel:hover {
469
+ color: var(--site-text-primary);
470
+ }
471
+
472
+ .compose-dialog-header-center {
473
+ position: absolute;
474
+ left: 50%;
475
+ transform: translateX(-50%);
476
+ }
477
+
478
+ .compose-dialog-header-btn {
339
479
  display: flex;
340
480
  align-items: center;
341
481
  justify-content: center;
342
- width: 28px;
343
- height: 28px;
344
- border-radius: 50%;
482
+ width: 32px;
483
+ height: 32px;
484
+ border-radius: 8px;
345
485
  border: none;
346
486
  background: none;
347
487
  color: var(--site-text-secondary);
348
488
  cursor: pointer;
349
- transition: background-color 0.15s;
489
+ transition:
490
+ background-color 0.15s ease-out,
491
+ color 0.15s ease-out;
350
492
  }
351
493
 
352
- .compose-dialog-close:hover {
494
+ .compose-dialog-header-btn:hover {
495
+ color: var(--site-text-primary);
353
496
  background-color: var(--site-nav-hover-bg);
354
497
  }
355
498
 
356
- .compose-dialog-body {
357
- padding: 16px 20px;
358
- overflow-y: auto;
359
- flex: 1;
499
+ .compose-dialog-header-btn:disabled {
500
+ opacity: 0.3;
501
+ cursor: not-allowed;
360
502
  }
361
503
 
362
- .compose-dialog-footer {
363
- display: flex;
364
- align-items: center;
365
- justify-content: space-between;
366
- padding-top: 12px;
367
- border-top: var(--card-border-width) solid var(--site-divider);
504
+ /* --- Format switcher with animated pill --------------------------------- */
505
+
506
+ .compose-segmented {
507
+ display: inline-flex;
508
+ background-color: var(--site-nav-hover-bg);
509
+ border-radius: 10px;
510
+ padding: 3px;
511
+ position: relative;
368
512
  }
369
513
 
370
- /* Format tabs — inline pill buttons */
371
- .compose-format-tabs {
372
- display: flex;
373
- gap: 4px;
374
- padding-bottom: 8px;
514
+ .compose-format-pill {
515
+ position: absolute;
516
+ top: 3px;
517
+ left: 3px;
518
+ width: calc((100% - 6px) / 3);
519
+ height: calc(100% - 6px);
520
+ background-color: var(--site-elevated-bg);
521
+ border-radius: 8px;
522
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
523
+ transition: left 0.28s cubic-bezier(0.22, 1, 0.36, 1);
524
+ z-index: 0;
375
525
  }
376
526
 
377
- .compose-format-tab {
378
- padding: 4px 12px;
379
- border-radius: 999px;
380
- border: 1px solid var(--site-column-outline);
381
- background: none;
527
+ .compose-format-pill-link {
528
+ left: calc(3px + (100% - 6px) / 3);
529
+ }
530
+
531
+ .compose-format-pill-quote {
532
+ left: calc(3px + (100% - 6px) * 2 / 3);
533
+ }
534
+
535
+ .compose-segmented-item {
536
+ position: relative;
537
+ z-index: 1;
538
+ flex: 1;
539
+ padding: 6px 16px;
540
+ border-radius: 8px;
541
+ border: none;
542
+ background: transparent;
382
543
  color: var(--site-text-secondary);
383
544
  font-size: var(--text-sm);
545
+ font-weight: 400;
384
546
  cursor: pointer;
385
- transition:
386
- background-color 0.15s,
387
- color 0.15s,
388
- border-color 0.15s;
547
+ transition: color 0.2s ease;
548
+ letter-spacing: 0.01em;
389
549
  }
390
550
 
391
- .compose-format-tab:hover {
551
+ .compose-segmented-item-active {
392
552
  color: var(--site-text-primary);
393
- border-color: var(--site-text-secondary);
553
+ font-weight: 500;
394
554
  }
395
555
 
396
- .compose-format-tab-active {
397
- color: var(--site-text-primary);
398
- background-color: var(--site-nav-hover-bg);
399
- border-color: var(--site-text-primary);
400
- font-weight: 500;
556
+ /* --- Body --------------------------------------------------------------- */
557
+
558
+ .compose-body {
559
+ flex: 1;
560
+ overflow-y: auto;
561
+ padding: 16px 20px 12px;
562
+ display: flex;
563
+ flex-direction: column;
401
564
  }
402
565
 
403
- /* Borderless title input */
404
- .compose-title-input {
405
- width: 100%;
406
- padding: 4px 0;
566
+ @media (min-width: 700px) {
567
+ .compose-body {
568
+ padding: 18px 24px 12px;
569
+ }
570
+ }
571
+
572
+ .compose-body::-webkit-scrollbar {
573
+ width: 3px;
574
+ }
575
+ .compose-body::-webkit-scrollbar-thumb {
576
+ background-color: var(--site-divider);
577
+ border-radius: 4px;
578
+ }
579
+
580
+ .compose-field-enter {
581
+ animation: compose-fade-up 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
582
+ }
583
+
584
+ /* --- Shared input reset ------------------------------------------------- */
585
+
586
+ .compose-input {
407
587
  border: none;
408
588
  outline: none;
409
589
  background: transparent;
590
+ resize: none;
591
+ width: 100%;
410
592
  color: var(--site-text-primary);
411
- font-size: var(--text-lg);
412
- font-weight: 600;
593
+ font-family: var(--font-body);
413
594
  }
414
595
 
415
- .compose-title-input::placeholder {
596
+ .compose-input::placeholder {
416
597
  color: var(--site-text-secondary);
598
+ }
599
+ .compose-input:focus::placeholder {
600
+ opacity: 0.6;
601
+ }
602
+
603
+ /* --- Note mode ---------------------------------------------------------- */
604
+
605
+ .compose-note-title-row {
606
+ display: flex;
607
+ align-items: center;
608
+ gap: 8px;
609
+ margin-bottom: 8px;
610
+ animation: compose-fade-up 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
611
+ }
612
+
613
+ .compose-note-title {
614
+ flex: 1;
615
+ font-family: var(--font-heading);
616
+ font-size: 1.125rem;
417
617
  font-weight: 400;
618
+ letter-spacing: -0.01em;
619
+ line-height: 1.3;
620
+ }
621
+
622
+ @media (min-width: 700px) {
623
+ .compose-note-title {
624
+ font-size: 1.25rem;
625
+ }
626
+ }
627
+
628
+ .compose-note-title-dismiss {
629
+ border: none;
630
+ background: transparent;
631
+ color: var(--site-text-secondary);
632
+ cursor: pointer;
633
+ font-size: var(--text-sm);
634
+ padding: 2px 4px;
635
+ border-radius: 6px;
636
+ flex-shrink: 0;
637
+ line-height: 1;
638
+ opacity: 0.6;
639
+ transition: opacity 0.15s ease;
640
+ }
641
+
642
+ .compose-note-title-dismiss:hover {
643
+ opacity: 1;
418
644
  }
419
645
 
420
- /* Borderless body textarea */
421
646
  .compose-body-input {
422
647
  width: 100%;
423
- padding: 4px 0;
648
+ padding: 0;
424
649
  border: none;
425
650
  outline: none;
426
651
  background: transparent;
427
652
  color: var(--site-text-primary);
428
653
  font-size: var(--text-base);
429
- line-height: var(--leading);
430
- resize: vertical;
654
+ font-family: var(--font-body);
655
+ line-height: 1.65;
656
+ letter-spacing: 0.005em;
657
+ resize: none;
431
658
  }
432
659
 
433
660
  .compose-body-input::placeholder {
434
661
  color: var(--site-text-secondary);
435
662
  }
436
663
 
437
- /* Bottom toolbar */
438
- .compose-toolbar {
439
- padding: 8px 0;
664
+ /* --- Link mode ---------------------------------------------------------- */
665
+
666
+ .compose-link-url-wrap {
667
+ display: flex;
668
+ align-items: center;
669
+ gap: 10px;
670
+ background-color: var(--site-nav-hover-bg);
671
+ border-radius: 12px;
672
+ padding: 10px 14px;
673
+ margin-bottom: 14px;
674
+ }
675
+
676
+ .compose-link-title {
677
+ font-family: var(--font-heading);
678
+ font-size: 1.03rem;
679
+ font-weight: 400;
680
+ letter-spacing: -0.005em;
681
+ margin-bottom: 14px;
682
+ padding-left: 2px;
683
+ }
684
+
685
+ @media (min-width: 700px) {
686
+ .compose-link-title {
687
+ font-size: 1.05rem;
688
+ }
689
+ }
690
+
691
+ /* --- Quote mode --------------------------------------------------------- */
692
+
693
+ .compose-quote-wrap {
694
+ position: relative;
695
+ background-color: var(--site-nav-hover-bg);
696
+ border-radius: 14px;
697
+ padding: 16px 18px 14px 36px;
698
+ margin-bottom: 10px;
699
+ }
700
+
701
+ @media (min-width: 700px) {
702
+ .compose-quote-wrap {
703
+ padding: 20px 22px 16px 40px;
704
+ }
705
+ }
706
+
707
+ .compose-quote-mark {
708
+ position: absolute;
709
+ top: 10px;
710
+ left: 14px;
711
+ font-size: 36px;
712
+ font-family: var(--font-heading);
713
+ color: var(--site-text-secondary);
714
+ opacity: 0.5;
715
+ line-height: 1;
716
+ user-select: none;
717
+ }
718
+
719
+ .compose-quote-text {
720
+ font-family: var(--font-heading);
721
+ font-size: var(--text-base);
722
+ font-style: italic;
723
+ line-height: 1.6;
724
+ letter-spacing: 0.005em;
725
+ }
726
+
727
+ @media (min-width: 700px) {
728
+ .compose-quote-text {
729
+ font-size: 1rem;
730
+ }
731
+ }
732
+
733
+ .compose-quote-author-row {
734
+ display: flex;
735
+ align-items: baseline;
736
+ gap: 8px;
737
+ padding-left: 6px;
738
+ margin-bottom: 4px;
739
+ }
740
+
741
+ .compose-quote-dash {
742
+ color: var(--site-text-secondary);
743
+ font-size: 1rem;
744
+ font-family: var(--font-heading);
745
+ user-select: none;
746
+ }
747
+
748
+ .compose-quote-author {
749
+ font-size: var(--text-sm);
750
+ font-weight: 500;
751
+ letter-spacing: 0.01em;
752
+ }
753
+
754
+ .compose-quote-source {
755
+ padding-left: 22px;
756
+ margin-bottom: 14px;
757
+ font-size: 0.78rem;
758
+ letter-spacing: 0.01em;
759
+ }
760
+
761
+ /* --- Shared elements ---------------------------------------------------- */
762
+
763
+ .compose-divider {
764
+ display: none;
765
+ }
766
+
767
+ .compose-thoughts {
768
+ font-size: var(--text-sm);
769
+ line-height: 1.6;
770
+ color: var(--site-text-secondary);
771
+ }
772
+
773
+ @media (min-width: 700px) {
774
+ .compose-thoughts {
775
+ font-size: 0.9rem;
776
+ }
777
+ }
778
+
779
+ /* --- Star rating -------------------------------------------------------- */
780
+
781
+ .compose-star-rating {
782
+ display: flex;
783
+ gap: 4px;
784
+ align-items: center;
785
+ margin-top: 12px;
786
+ padding-left: 2px;
787
+ animation: compose-fade-up 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
788
+ }
789
+
790
+ .compose-star {
791
+ border: none;
792
+ background: transparent;
793
+ cursor: pointer;
794
+ padding: 2px;
795
+ font-size: 18px;
796
+ color: var(--site-divider);
797
+ transition: all 0.15s ease;
798
+ line-height: 1;
799
+ }
800
+
801
+ .compose-star-filled {
802
+ color: var(--primary);
803
+ transform: scale(1.1);
804
+ }
805
+
806
+ .compose-star-label {
807
+ font-size: 0.6875rem;
808
+ color: var(--site-text-secondary);
809
+ margin-left: 4px;
810
+ }
811
+
812
+ /* --- Attached text badge ------------------------------------------------ */
813
+
814
+ .compose-attached-badge {
815
+ display: flex;
816
+ align-items: center;
817
+ gap: 8px;
818
+ margin-top: 14px;
819
+ background-color: var(--site-nav-hover-bg);
820
+ border-radius: 10px;
821
+ padding: 8px 12px;
822
+ cursor: pointer;
823
+ animation: compose-fade-up 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
824
+ transition: opacity 0.15s ease;
440
825
  }
441
826
 
442
- .compose-toolbar-btn {
827
+ .compose-attached-badge:hover {
828
+ opacity: 0.85;
829
+ }
830
+
831
+ .compose-attached-badge-dismiss {
832
+ border: none;
833
+ background: transparent;
834
+ color: var(--site-text-secondary);
835
+ cursor: pointer;
836
+ font-size: 0.75rem;
837
+ padding: 0 2px;
838
+ line-height: 1;
839
+ opacity: 0.6;
840
+ transition: opacity 0.15s ease;
841
+ }
842
+
843
+ .compose-attached-badge-dismiss:hover {
844
+ opacity: 1;
845
+ }
846
+
847
+ /* --- Attached text overlay panel ---------------------------------------- */
848
+
849
+ .compose-attached-panel {
850
+ position: absolute;
851
+ inset: 0;
852
+ z-index: 50;
853
+ background-color: var(--site-elevated-bg);
854
+ display: flex;
855
+ flex-direction: column;
856
+ border-radius: 20px;
857
+ animation: compose-fade-up 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
858
+ }
859
+
860
+ .compose-attached-panel-back {
861
+ border: none;
862
+ background: transparent;
443
863
  display: flex;
444
864
  align-items: center;
445
865
  justify-content: center;
446
866
  width: 32px;
447
867
  height: 32px;
448
868
  border-radius: 8px;
869
+ cursor: pointer;
870
+ color: var(--site-text-secondary);
871
+ transition: color 0.15s ease;
872
+ }
873
+
874
+ .compose-attached-panel-back:hover {
875
+ color: var(--site-text-primary);
876
+ }
877
+
878
+ .compose-attached-textarea {
879
+ flex: 1;
880
+ font-size: 0.84rem;
881
+ line-height: 1.65;
882
+ letter-spacing: 0.005em;
883
+ overflow-y: auto;
884
+ }
885
+
886
+ .compose-attached-textarea::-webkit-scrollbar {
887
+ width: 3px;
888
+ }
889
+ .compose-attached-textarea::-webkit-scrollbar-thumb {
890
+ background-color: var(--site-divider);
891
+ border-radius: 4px;
892
+ }
893
+
894
+ /* --- Tools row ---------------------------------------------------------- */
895
+
896
+ .compose-tools-row {
897
+ padding: 6px 10px;
898
+ display: flex;
899
+ align-items: center;
900
+ gap: 1px;
901
+ background-color: var(--site-elevated-bg);
902
+ }
903
+
904
+ @media (min-width: 700px) {
905
+ .compose-tools-row {
906
+ padding: 6px 16px;
907
+ gap: 2px;
908
+ }
909
+ }
910
+
911
+ .compose-tool-btn {
912
+ position: relative;
913
+ display: flex;
914
+ align-items: center;
915
+ justify-content: center;
916
+ width: 36px;
917
+ height: 36px;
918
+ border-radius: 10px;
449
919
  border: none;
450
- background: none;
920
+ background: transparent;
921
+ cursor: pointer;
922
+ transition: all 0.18s ease;
923
+ flex-shrink: 0;
451
924
  color: var(--site-text-secondary);
925
+ }
926
+
927
+ .compose-tool-btn:hover {
928
+ background-color: var(--site-nav-hover-bg);
929
+ }
930
+ .compose-tool-btn-active {
931
+ background-color: var(--site-nav-hover-bg);
932
+ }
933
+
934
+ .compose-tool-sep {
935
+ width: 1px;
936
+ height: 16px;
937
+ background-color: var(--site-divider);
938
+ margin: 0 2px;
939
+ border-radius: 1px;
940
+ flex-shrink: 0;
941
+ }
942
+
943
+ .compose-tool-tip {
944
+ position: absolute;
945
+ bottom: calc(100% + 8px);
946
+ left: 50%;
947
+ transform: translateX(-50%) scale(0.92);
948
+ background-color: var(--site-text-primary);
949
+ color: var(--site-elevated-bg);
950
+ font-size: 0.6875rem;
951
+ font-weight: 400;
952
+ letter-spacing: 0.02em;
953
+ padding: 4px 10px;
954
+ border-radius: 6px;
955
+ white-space: nowrap;
956
+ opacity: 0;
957
+ pointer-events: none;
958
+ transition: all 0.18s cubic-bezier(0.22, 1, 0.36, 1);
959
+ }
960
+
961
+ .compose-tool-btn:hover .compose-tool-tip {
962
+ opacity: 1;
963
+ transform: translateX(-50%) scale(1);
964
+ }
965
+
966
+ /* --- Action row --------------------------------------------------------- */
967
+
968
+ .compose-action-row {
969
+ padding: 8px 10px 12px;
970
+ display: flex;
971
+ align-items: center;
972
+ gap: 8px;
973
+ background-color: var(--site-elevated-bg);
974
+ }
975
+
976
+ @media (min-width: 700px) {
977
+ .compose-action-row {
978
+ padding: 8px 16px 12px;
979
+ }
980
+ }
981
+
982
+ .compose-collection-select {
983
+ display: inline-flex;
984
+ position: relative;
985
+ }
986
+
987
+ .compose-collection-trigger {
988
+ display: flex;
989
+ align-items: center;
990
+ gap: 6px;
991
+ border: none;
992
+ background: transparent;
993
+ border-radius: 9px;
994
+ padding: 6px 10px;
452
995
  cursor: pointer;
453
- transition:
454
- background-color 0.15s,
455
- color 0.15s;
996
+ transition: all 0.2s ease;
997
+ max-width: 100%;
998
+ color: var(--site-text-secondary);
999
+ font-size: var(--text-sm);
1000
+ }
1001
+
1002
+ .compose-collection-trigger:hover {
1003
+ background-color: var(--site-nav-hover-bg);
1004
+ }
1005
+
1006
+ .compose-collection-badge {
1007
+ font-size: 0.6875rem;
1008
+ min-width: 1.125rem;
1009
+ height: 1.125rem;
1010
+ padding: 0 4px;
1011
+ line-height: 1.125rem;
1012
+ }
1013
+
1014
+ .compose-collection-select [data-popover] {
1015
+ z-index: 100;
1016
+ min-width: 200px;
1017
+ max-width: 280px;
1018
+ }
1019
+
1020
+ .compose-collection-select [data-popover] [role="listbox"] {
1021
+ max-height: 12rem;
1022
+ overflow-y: auto;
1023
+ }
1024
+
1025
+ .compose-post-btn {
1026
+ font-size: 0.84rem;
1027
+ font-weight: 500;
1028
+ letter-spacing: 0.02em;
1029
+ color: var(--site-elevated-bg);
1030
+ background-color: var(--site-text-primary);
1031
+ border: none;
1032
+ border-radius: 10px;
1033
+ padding: 8px 18px;
1034
+ cursor: pointer;
1035
+ transition: opacity 0.2s ease;
1036
+ flex-shrink: 0;
1037
+ }
1038
+
1039
+ @media (min-width: 700px) {
1040
+ .compose-post-btn {
1041
+ padding: 8px 22px;
1042
+ }
1043
+ }
1044
+
1045
+ .compose-post-btn:hover {
1046
+ opacity: 0.85;
1047
+ }
1048
+ .compose-post-btn:disabled {
1049
+ opacity: 0.5;
1050
+ cursor: not-allowed;
456
1051
  }
457
1052
 
458
- .compose-toolbar-btn:hover {
1053
+ /* --- Dropdowns ---------------------------------------------------------- */
1054
+
1055
+ .compose-dropdown-backdrop {
1056
+ position: fixed;
1057
+ inset: 0;
1058
+ z-index: 99;
1059
+ }
1060
+
1061
+ .compose-dropdown {
1062
+ position: absolute;
1063
+ min-width: 170px;
1064
+ background-color: var(--site-elevated-bg);
1065
+ border-radius: 12px;
1066
+ border: 1px solid var(--site-column-outline);
1067
+ box-shadow:
1068
+ 0 8px 32px rgba(0, 0, 0, 0.1),
1069
+ 0 1px 4px rgba(0, 0, 0, 0.05);
1070
+ padding: 5px;
1071
+ z-index: 100;
1072
+ animation: compose-fade-up 0.18s cubic-bezier(0.22, 1, 0.36, 1) both;
1073
+ }
1074
+
1075
+ .compose-dropdown-right {
1076
+ top: calc(100% + 6px);
1077
+ right: 0;
1078
+ }
1079
+
1080
+ .compose-dropdown-item {
1081
+ display: flex;
1082
+ align-items: center;
1083
+ gap: 8px;
1084
+ width: 100%;
1085
+ padding: 8px 12px;
1086
+ border: none;
1087
+ background: transparent;
1088
+ border-radius: 8px;
1089
+ cursor: pointer;
1090
+ text-align: left;
1091
+ font-size: var(--text-sm);
459
1092
  color: var(--site-text-primary);
1093
+ transition: background-color 0.12s ease;
1094
+ }
1095
+
1096
+ .compose-dropdown-item:hover {
460
1097
  background-color: var(--site-nav-hover-bg);
461
1098
  }
1099
+ .compose-dropdown-item-muted {
1100
+ color: var(--site-text-secondary);
1101
+ }
1102
+ .compose-dropdown-item-danger {
1103
+ color: var(--destructive);
1104
+ }
1105
+
1106
+ .compose-dropdown-divider {
1107
+ height: 1px;
1108
+ background-color: var(--site-divider);
1109
+ margin: 3px 8px;
1110
+ }
1111
+
1112
+ /* --- Attachment gallery -------------------------------------------------- */
1113
+
1114
+ .compose-attachments {
1115
+ display: flex;
1116
+ gap: 8px;
1117
+ margin-top: 14px;
1118
+ padding: 2px 0;
1119
+ overflow-x: auto;
1120
+ scroll-snap-type: x mandatory;
1121
+ -webkit-overflow-scrolling: touch;
1122
+ scrollbar-width: none;
1123
+ -ms-overflow-style: none;
1124
+ animation: compose-fade-up 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
1125
+ }
1126
+
1127
+ .compose-attachments::-webkit-scrollbar {
1128
+ display: none;
1129
+ }
1130
+
1131
+ .compose-attachment {
1132
+ flex-shrink: 0;
1133
+ display: flex;
1134
+ flex-direction: column;
1135
+ align-items: start;
1136
+ gap: 4px;
1137
+ scroll-snap-align: start;
1138
+ max-width: 85%;
1139
+ }
1140
+
1141
+ /* Single attachment: full width, natural aspect ratio */
1142
+ .compose-attachment:only-child {
1143
+ max-width: 100%;
1144
+ }
1145
+
1146
+ .compose-attachment-thumb {
1147
+ position: relative;
1148
+ border-radius: var(--media-radius, 0.5rem);
1149
+ overflow: hidden;
1150
+ background-color: var(--site-nav-hover-bg);
1151
+ }
1152
+
1153
+ .compose-attachment-img {
1154
+ display: block;
1155
+ border-radius: var(--media-radius, 0.5rem);
1156
+ max-height: 320px;
1157
+ object-fit: contain;
1158
+ }
1159
+
1160
+ /* Single image: constrain to container width */
1161
+ .compose-attachment:only-child .compose-attachment-img {
1162
+ max-width: 100%;
1163
+ max-height: 384px;
1164
+ }
1165
+
1166
+ /* Multiple images: fixed height, cover */
1167
+ .compose-attachment:not(:only-child) .compose-attachment-img {
1168
+ height: 200px;
1169
+ width: auto;
1170
+ min-width: 120px;
1171
+ object-fit: cover;
1172
+ }
1173
+
1174
+ .compose-attachment-overlay {
1175
+ position: absolute;
1176
+ inset: 0;
1177
+ display: flex;
1178
+ align-items: center;
1179
+ justify-content: center;
1180
+ background-color: rgba(0, 0, 0, 0.35);
1181
+ color: white;
1182
+ border-radius: var(--media-radius, 0.5rem);
1183
+ }
1184
+
1185
+ .compose-attachment-error {
1186
+ background-color: rgba(220, 38, 38, 0.4);
1187
+ }
1188
+
1189
+ .compose-attachment-remove {
1190
+ position: absolute;
1191
+ top: 6px;
1192
+ right: 6px;
1193
+ width: 24px;
1194
+ height: 24px;
1195
+ border-radius: 50%;
1196
+ border: none;
1197
+ background-color: rgba(0, 0, 0, 0.55);
1198
+ color: white;
1199
+ font-size: 11px;
1200
+ line-height: 1;
1201
+ cursor: pointer;
1202
+ display: flex;
1203
+ align-items: center;
1204
+ justify-content: center;
1205
+ opacity: 0;
1206
+ transition: opacity 0.15s ease;
1207
+ }
1208
+
1209
+ .compose-attachment-thumb:hover .compose-attachment-remove {
1210
+ opacity: 1;
1211
+ }
1212
+
1213
+ /* Always show on touch devices */
1214
+ @media (hover: none) {
1215
+ .compose-attachment-remove {
1216
+ opacity: 1;
1217
+ }
1218
+ }
1219
+
1220
+ .compose-attachment-alt {
1221
+ border: none;
1222
+ background: transparent;
1223
+ cursor: pointer;
1224
+ font-size: 0.625rem;
1225
+ font-weight: 600;
1226
+ letter-spacing: 0.04em;
1227
+ color: var(--site-text-secondary);
1228
+ padding: 2px 4px;
1229
+ border-radius: 4px;
1230
+ transition: color 0.15s ease;
1231
+ }
1232
+
1233
+ .compose-attachment-alt:hover {
1234
+ color: var(--site-text-primary);
1235
+ }
1236
+
1237
+ .compose-attachment-alt-set {
1238
+ color: var(--primary);
1239
+ }
1240
+
1241
+ .compose-attachment-alt-set:hover {
1242
+ color: var(--primary);
1243
+ opacity: 0.8;
1244
+ }
1245
+
1246
+ /* --- Alt text overlay panel ---------------------------------------------- */
1247
+
1248
+ .compose-alt-panel {
1249
+ position: absolute;
1250
+ inset: 0;
1251
+ z-index: 50;
1252
+ background-color: var(--site-elevated-bg);
1253
+ display: flex;
1254
+ flex-direction: column;
1255
+ border-radius: 20px;
1256
+ animation: compose-fade-up 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
1257
+ }
1258
+
1259
+ .compose-alt-preview {
1260
+ display: flex;
1261
+ align-items: center;
1262
+ justify-content: center;
1263
+ padding: 12px 16px 0;
1264
+ max-height: 200px;
1265
+ overflow: hidden;
1266
+ }
1267
+
1268
+ .compose-alt-preview-img {
1269
+ max-width: 100%;
1270
+ max-height: 180px;
1271
+ border-radius: 10px;
1272
+ object-fit: contain;
1273
+ }
1274
+
1275
+ .compose-alt-textarea {
1276
+ flex: 1;
1277
+ font-size: 0.84rem;
1278
+ line-height: 1.65;
1279
+ letter-spacing: 0.005em;
1280
+ overflow-y: auto;
1281
+ }
1282
+
1283
+ .compose-alt-textarea::-webkit-scrollbar {
1284
+ width: 3px;
1285
+ }
1286
+
1287
+ .compose-alt-textarea::-webkit-scrollbar-thumb {
1288
+ background-color: var(--site-divider);
1289
+ border-radius: 4px;
1290
+ }
462
1291
 
463
1292
  /* =========================================================================
464
1293
  * Site Footer