@jant/core 0.3.35 → 0.3.36

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 (156) hide show
  1. package/dist/client/assets/module-RjUF93sV.js +716 -0
  2. package/dist/client/assets/native-48B9X9Wg.js +1 -0
  3. package/dist/client/assets/url-8Dj-5CLW.js +1 -0
  4. package/dist/client/client.css +1 -1
  5. package/dist/client/client.js +3109 -2294
  6. package/dist/index.js +3026 -2778
  7. package/package.json +13 -4
  8. package/src/__tests__/helpers/app.ts +1 -1
  9. package/src/__tests__/helpers/db.ts +6 -0
  10. package/src/app.tsx +1 -5
  11. package/src/{lib → client}/avatar-upload.ts +1 -1
  12. package/src/{lib → client}/collection-form-bridge.ts +2 -2
  13. package/src/{ui → client}/components/__tests__/jant-collection-form.test.ts +26 -9
  14. package/src/{ui → client}/components/__tests__/jant-compose-dialog.test.ts +46 -14
  15. package/src/{ui → client}/components/__tests__/jant-compose-editor.test.ts +64 -24
  16. package/src/{ui → client}/components/__tests__/jant-post-form.test.ts +24 -14
  17. package/src/{ui → client}/components/__tests__/jant-settings-general.test.ts +3 -3
  18. package/src/client/components/collection-sidebar-types.ts +45 -0
  19. package/src/{ui → client}/components/collection-types.ts +3 -4
  20. package/src/{ui → client}/components/compose-types.ts +3 -1
  21. package/src/{ui → client}/components/jant-collection-form.ts +301 -182
  22. package/src/client/components/jant-collection-sidebar.ts +801 -0
  23. package/src/{ui → client}/components/jant-compose-dialog.ts +231 -1
  24. package/src/client/components/jant-compose-editor.ts +1249 -0
  25. package/src/client/components/jant-compose-fullscreen.ts +338 -0
  26. package/src/client/components/jant-media-lightbox.ts +257 -0
  27. package/src/{ui → client}/components/jant-nav-manager.ts +143 -84
  28. package/src/{ui → client}/components/jant-post-form.ts +57 -8
  29. package/src/{ui → client}/components/jant-settings-general.ts +2 -2
  30. package/src/{ui → client}/components/nav-manager-types.ts +3 -0
  31. package/src/{ui → client}/components/post-form-template.ts +35 -31
  32. package/src/{ui → client}/components/post-form-types.ts +7 -3
  33. package/src/{lib → client}/compose-bridge.ts +9 -7
  34. package/src/client/lazy-slugify.ts +51 -0
  35. package/src/{lib → client}/media-upload.ts +16 -3
  36. package/src/{lib → client}/nav-manager-bridge.ts +1 -1
  37. package/src/client/page-slug-bridge.ts +42 -0
  38. package/src/{lib → client}/post-form-bridge.ts +2 -2
  39. package/src/{lib → client}/settings-bridge.ts +3 -3
  40. package/src/client/tiptap/bubble-menu.ts +205 -0
  41. package/src/client/tiptap/create-editor.ts +40 -0
  42. package/src/client/tiptap/exitable-marks.ts +73 -0
  43. package/src/client/tiptap/extensions.ts +60 -0
  44. package/src/client/tiptap/image-node.ts +488 -0
  45. package/src/client/tiptap/link-toolbar.ts +371 -0
  46. package/src/client/tiptap/more-break.ts +50 -0
  47. package/src/client/tiptap/paste-image.ts +140 -0
  48. package/src/client/tiptap/slash-commands.ts +328 -0
  49. package/src/{types → client/types}/sortablejs.d.ts +1 -1
  50. package/src/client.ts +24 -17
  51. package/src/db/migrations/0012_add_tiptap_columns.sql +2 -0
  52. package/src/db/migrations/0013_replace_featured_with_visibility.sql +8 -0
  53. package/src/db/schema.ts +6 -1
  54. package/src/i18n/locales/en.po +641 -215
  55. package/src/i18n/locales/en.ts +1 -1
  56. package/src/i18n/locales/zh-Hans.po +642 -204
  57. package/src/i18n/locales/zh-Hans.ts +1 -1
  58. package/src/i18n/locales/zh-Hant.po +642 -204
  59. package/src/i18n/locales/zh-Hant.ts +1 -1
  60. package/src/lib/__tests__/resolve-config.test.ts +2 -2
  61. package/src/lib/__tests__/schemas.test.ts +9 -6
  62. package/src/lib/__tests__/url.test.ts +2 -2
  63. package/src/lib/__tests__/view.test.ts +9 -9
  64. package/src/lib/emoji-catalog.ts +146 -0
  65. package/src/lib/feed.ts +1 -1
  66. package/src/lib/media-helpers.ts +10 -9
  67. package/src/lib/render.tsx +4 -3
  68. package/src/lib/resolve-config.ts +8 -1
  69. package/src/lib/schemas.ts +2 -3
  70. package/src/lib/summary.ts +92 -0
  71. package/src/lib/timeline.ts +2 -0
  72. package/src/lib/tiptap-render.ts +196 -0
  73. package/src/lib/upload.ts +97 -9
  74. package/src/lib/url.ts +7 -23
  75. package/src/lib/view.ts +33 -19
  76. package/src/middleware/error-handler.ts +3 -3
  77. package/src/preset.css +38 -0
  78. package/src/routes/api/collections.ts +20 -3
  79. package/src/routes/api/posts.ts +48 -33
  80. package/src/routes/api/upload.ts +7 -5
  81. package/src/routes/auth/reset.tsx +5 -4
  82. package/src/routes/auth/setup.tsx +26 -11
  83. package/src/routes/auth/signin.tsx +10 -7
  84. package/src/routes/compose.tsx +20 -11
  85. package/src/routes/dash/__tests__/settings-avatar.test.ts +43 -8
  86. package/src/routes/dash/index.tsx +7 -1
  87. package/src/routes/dash/media.tsx +3 -0
  88. package/src/routes/dash/pages.tsx +8 -2
  89. package/src/routes/dash/posts.tsx +6 -2
  90. package/src/routes/dash/redirects.tsx +15 -9
  91. package/src/routes/dash/settings.tsx +336 -32
  92. package/src/routes/feed/__tests__/rss.test.ts +7 -7
  93. package/src/routes/feed/rss.ts +8 -6
  94. package/src/routes/pages/__tests__/featured.test.ts +6 -7
  95. package/src/routes/pages/archive.tsx +11 -7
  96. package/src/routes/pages/collection.tsx +32 -15
  97. package/src/routes/pages/collections.tsx +11 -2
  98. package/src/routes/pages/featured.tsx +1 -1
  99. package/src/routes/pages/home.tsx +1 -1
  100. package/src/services/__tests__/post.test.ts +124 -33
  101. package/src/services/__tests__/settings.test.ts +3 -3
  102. package/src/services/page.ts +16 -3
  103. package/src/services/post.ts +96 -37
  104. package/src/services/search.ts +4 -2
  105. package/src/services/settings.ts +6 -2
  106. package/src/styles/components.css +240 -60
  107. package/src/styles/tokens.css +10 -0
  108. package/src/styles/ui.css +1157 -81
  109. package/src/types/bindings.ts +5 -0
  110. package/src/types/config.ts +23 -1
  111. package/src/types/constants.ts +3 -0
  112. package/src/types/entities.ts +9 -2
  113. package/src/types/operations.ts +9 -3
  114. package/src/types/props.ts +3 -3
  115. package/src/types/views.ts +3 -2
  116. package/src/ui/compose/ComposeDialog.tsx +24 -7
  117. package/src/ui/dash/PageForm.tsx +2 -0
  118. package/src/ui/dash/PostList.tsx +5 -5
  119. package/src/ui/dash/StatusBadge.tsx +13 -5
  120. package/src/ui/dash/appearance/AdvancedContent.tsx +52 -61
  121. package/src/ui/dash/appearance/ColorThemeContent.tsx +30 -35
  122. package/src/ui/dash/appearance/FontThemeContent.tsx +65 -73
  123. package/src/ui/dash/appearance/NavigationContent.tsx +107 -96
  124. package/src/ui/dash/media/MediaListContent.tsx +9 -4
  125. package/src/ui/dash/media/ViewMediaContent.tsx +2 -2
  126. package/src/ui/dash/pages/PagesContent.tsx +2 -1
  127. package/src/ui/dash/posts/PostForm.tsx +19 -7
  128. package/src/ui/dash/settings/AccountContent.tsx +133 -138
  129. package/src/ui/dash/settings/AvatarContent.tsx +70 -0
  130. package/src/ui/dash/settings/GeneralContent.tsx +3 -62
  131. package/src/ui/dash/settings/SettingsRootContent.tsx +236 -0
  132. package/src/ui/layouts/DashLayout.tsx +157 -75
  133. package/src/ui/layouts/SiteLayout.tsx +13 -13
  134. package/src/ui/pages/ArchivePage.tsx +10 -7
  135. package/src/ui/pages/CollectionPage.tsx +6 -35
  136. package/src/ui/pages/CollectionsPage.tsx +2 -1
  137. package/src/ui/pages/FeaturedPage.tsx +2 -1
  138. package/src/ui/pages/HomePage.tsx +1 -1
  139. package/src/ui/pages/SearchPage.tsx +1 -1
  140. package/src/ui/shared/CollectionsSidebar.tsx +228 -3
  141. package/src/ui/shared/MediaGallery.tsx +179 -41
  142. package/src/lib/collections-reorder.ts +0 -28
  143. package/src/routes/dash/appearance.tsx +0 -240
  144. package/src/routes/dash/collections.tsx +0 -211
  145. package/src/ui/components/jant-compose-editor.ts +0 -814
  146. package/src/ui/dash/appearance/AppearanceNav.tsx +0 -60
  147. package/src/ui/dash/collections/CollectionForm.tsx +0 -166
  148. package/src/ui/dash/collections/CollectionsListContent.tsx +0 -146
  149. package/src/ui/dash/collections/IconPickerGrid.tsx +0 -50
  150. package/src/ui/dash/collections/ViewCollectionContent.tsx +0 -103
  151. package/src/ui/dash/settings/SettingsNav.tsx +0 -52
  152. /package/src/{ui → client}/components/__tests__/jant-settings-avatar.test.ts +0 -0
  153. /package/src/{ui → client}/components/jant-settings-avatar.ts +0 -0
  154. /package/src/{ui → client}/components/settings-types.ts +0 -0
  155. /package/src/{lib → client}/image-processor.ts +0 -0
  156. /package/src/{lib → client}/toast.ts +0 -0
package/src/styles/ui.css CHANGED
@@ -211,46 +211,23 @@
211
211
  padding: 0px var(--site-padding) var(--space-xl);
212
212
  }
213
213
 
214
- /* --- Sidebar layout (shared by dashboard and site sidebar pages) ------- */
214
+ /* --- Sidebar layout (collections pages) -------------------------------- */
215
215
 
216
- .sidebar-layout {
217
- display: flex;
218
- gap: var(--sidebar-gap);
216
+ .site-container-sidebar {
217
+ position: relative;
219
218
  }
220
219
 
221
220
  .sidebar-nav {
221
+ position: absolute;
222
+ right: calc(100% + var(--sidebar-gap));
223
+ top: 0;
222
224
  width: var(--sidebar-width);
223
- flex-shrink: 0;
224
- }
225
-
226
- .sidebar-main {
227
- flex: 1;
228
- min-width: 0;
229
- max-width: var(--site-width);
230
225
  }
231
226
 
232
- @media (max-width: 959px) {
233
- .sidebar-layout {
234
- display: block;
235
- }
227
+ @media (max-width: 1079px) {
236
228
  .sidebar-nav {
237
229
  display: none;
238
230
  }
239
- .sidebar-main {
240
- max-width: none;
241
- }
242
- }
243
-
244
- .site-header-sidebar {
245
- max-width: calc(
246
- var(--sidebar-width) + var(--sidebar-gap) + var(--site-width)
247
- );
248
- }
249
-
250
- .site-footer-sidebar {
251
- max-width: calc(
252
- var(--sidebar-width) + var(--sidebar-gap) + var(--site-width)
253
- );
254
231
  }
255
232
 
256
233
  /* =========================================================================
@@ -431,6 +408,12 @@
431
408
 
432
409
  /* --- Dialog shell ------------------------------------------------------- */
433
410
 
411
+ /* Prevent body scroll when any compose dialog is open */
412
+ body:has(.compose-dialog[open]),
413
+ body:has(.compose-fullscreen-dialog[open]) {
414
+ overflow: hidden;
415
+ }
416
+
434
417
  .compose-dialog {
435
418
  --compose-margin-top: max(80px, 10vh);
436
419
 
@@ -448,7 +431,7 @@
448
431
  0 8px 40px rgba(0, 0, 0, 0.08),
449
432
  0 1px 3px rgba(0, 0, 0, 0.04);
450
433
  border: 1px solid var(--site-column-outline);
451
- overflow: hidden;
434
+ overflow: visible;
452
435
  }
453
436
 
454
437
  .compose-dialog[open] {
@@ -464,6 +447,8 @@
464
447
  flex-direction: column;
465
448
  max-height: calc(100dvh - var(--compose-margin-top) - 20px);
466
449
  position: relative;
450
+ border-radius: inherit;
451
+ overflow: hidden;
467
452
  }
468
453
 
469
454
  .compose-dialog-inner > jant-compose-editor {
@@ -839,7 +824,7 @@
839
824
  }
840
825
 
841
826
  .compose-star-filled {
842
- color: var(--primary);
827
+ color: oklch(0.75 0.15 70);
843
828
  transform: scale(1.1);
844
829
  }
845
830
 
@@ -893,10 +878,21 @@
893
878
  background-color: var(--site-elevated-bg);
894
879
  display: flex;
895
880
  flex-direction: column;
896
- border-radius: 20px;
881
+ border-radius: 10px;
897
882
  animation: compose-fade-up 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
898
883
  }
899
884
 
885
+ .compose-attached-charcount {
886
+ position: absolute;
887
+ right: 12px;
888
+ }
889
+
890
+ @media (min-width: 700px) {
891
+ .compose-attached-charcount {
892
+ right: 16px;
893
+ }
894
+ }
895
+
900
896
  .compose-attached-panel-back {
901
897
  border: none;
902
898
  background: transparent;
@@ -967,10 +963,24 @@
967
963
  .compose-tool-btn:hover {
968
964
  background-color: var(--site-nav-hover-bg);
969
965
  }
966
+
970
967
  .compose-tool-btn-active {
968
+ color: var(--site-text-primary);
971
969
  background-color: var(--site-nav-hover-bg);
972
970
  }
973
971
 
972
+ .compose-tool-btn-add {
973
+ width: auto;
974
+ gap: 4px;
975
+ padding: 0 10px 0 8px;
976
+ }
977
+
978
+ .compose-tool-label {
979
+ font-size: 0.8125rem;
980
+ font-weight: 500;
981
+ white-space: nowrap;
982
+ }
983
+
974
984
  .compose-tool-sep {
975
985
  width: 1px;
976
986
  height: 16px;
@@ -980,27 +990,14 @@
980
990
  flex-shrink: 0;
981
991
  }
982
992
 
983
- .compose-tool-tip {
984
- position: absolute;
985
- bottom: calc(100% + 8px);
986
- left: 50%;
987
- transform: translateX(-50%) scale(0.92);
988
- background-color: var(--site-text-primary);
989
- color: var(--site-elevated-bg);
990
- font-size: 0.6875rem;
991
- font-weight: 400;
992
- letter-spacing: 0.02em;
993
- padding: 4px 10px;
994
- border-radius: 6px;
995
- white-space: nowrap;
996
- opacity: 0;
997
- pointer-events: none;
998
- transition: all 0.18s cubic-bezier(0.22, 1, 0.36, 1);
999
- }
993
+ /* --- Emoji picker ------------------------------------------------------- */
1000
994
 
1001
- .compose-tool-btn:hover .compose-tool-tip {
1002
- opacity: 1;
1003
- transform: translateX(-50%) scale(1);
995
+ .compose-emoji-picker {
996
+ position: fixed;
997
+ z-index: 100;
998
+ border-radius: 12px;
999
+ overflow: hidden;
1000
+ box-shadow: 0 8px 32px rgb(0 0 0 / 0.25);
1004
1001
  }
1005
1002
 
1006
1003
  /* --- Action row --------------------------------------------------------- */
@@ -1222,8 +1219,25 @@
1222
1219
  border-radius: var(--media-radius, 0.5rem);
1223
1220
  }
1224
1221
 
1225
- .compose-attachment-error {
1226
- background-color: rgba(220, 38, 38, 0.4);
1222
+ .compose-attachment-retry {
1223
+ background-color: rgba(0, 0, 0, 0.5);
1224
+ cursor: pointer;
1225
+ border: none;
1226
+ padding: 0;
1227
+ transition: background-color 0.15s;
1228
+ }
1229
+
1230
+ .compose-attachment-retry:hover {
1231
+ background-color: rgba(0, 0, 0, 0.6);
1232
+ }
1233
+
1234
+ .compose-attachment-retry svg {
1235
+ opacity: 0.85;
1236
+ transition: opacity 0.15s;
1237
+ }
1238
+
1239
+ .compose-attachment-retry:hover svg {
1240
+ opacity: 1;
1227
1241
  }
1228
1242
 
1229
1243
  .compose-attachment-remove {
@@ -1275,15 +1289,70 @@
1275
1289
  }
1276
1290
 
1277
1291
  .compose-attachment-alt-set {
1278
- color: var(--primary);
1292
+ color: oklch(0.6 0.15 155);
1279
1293
  }
1280
1294
 
1281
1295
  .compose-attachment-alt-set:hover {
1282
- color: var(--primary);
1296
+ color: oklch(0.6 0.15 155);
1283
1297
  opacity: 0.8;
1284
1298
  }
1285
1299
 
1286
- /* --- Alt text overlay panel ---------------------------------------------- */
1300
+ /* --- Video play icon overlay (compose) ----------------------------------- */
1301
+
1302
+ .compose-attachment-play-icon {
1303
+ position: absolute;
1304
+ inset: 0;
1305
+ display: flex;
1306
+ align-items: center;
1307
+ justify-content: center;
1308
+ pointer-events: none;
1309
+ }
1310
+
1311
+ .compose-attachment-play-icon svg {
1312
+ filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.4));
1313
+ opacity: 0.85;
1314
+ }
1315
+
1316
+ /* --- File card (compose: audio + PDF) ----------------------------------- */
1317
+
1318
+ .compose-attachment-file-card {
1319
+ display: flex;
1320
+ flex-direction: column;
1321
+ align-items: center;
1322
+ justify-content: center;
1323
+ gap: 6px;
1324
+ min-width: 120px;
1325
+ min-height: 100px;
1326
+ padding: 16px 12px;
1327
+ background-color: var(--site-nav-hover-bg);
1328
+ border-radius: var(--media-radius, 0.5rem);
1329
+ text-align: center;
1330
+ }
1331
+
1332
+ .compose-attachment:not(:only-child) .compose-attachment-file-card {
1333
+ min-height: 200px;
1334
+ }
1335
+
1336
+ .compose-attachment-file-icon {
1337
+ color: var(--site-text-secondary);
1338
+ }
1339
+
1340
+ .compose-attachment-file-name {
1341
+ font-size: 0.6875rem;
1342
+ font-weight: 500;
1343
+ color: var(--site-text-primary);
1344
+ max-width: 100%;
1345
+ overflow: hidden;
1346
+ text-overflow: ellipsis;
1347
+ white-space: nowrap;
1348
+ }
1349
+
1350
+ .compose-attachment-file-size {
1351
+ font-size: 0.625rem;
1352
+ color: var(--site-text-secondary);
1353
+ }
1354
+
1355
+ /* --- Alt text overlay panel (Threads-style, covers entire dialog) ------- */
1287
1356
 
1288
1357
  .compose-alt-panel {
1289
1358
  position: absolute;
@@ -1292,57 +1361,1064 @@
1292
1361
  background-color: var(--site-elevated-bg);
1293
1362
  display: flex;
1294
1363
  flex-direction: column;
1295
- border-radius: 20px;
1364
+ border-radius: 10px;
1296
1365
  animation: compose-fade-up 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
1297
1366
  }
1298
1367
 
1368
+ .compose-alt-header {
1369
+ display: flex;
1370
+ align-items: center;
1371
+ gap: 8px;
1372
+ padding: 10px 12px;
1373
+ border-bottom: 1px solid var(--site-divider);
1374
+ position: relative;
1375
+ }
1376
+
1377
+ @media (min-width: 700px) {
1378
+ .compose-alt-header {
1379
+ padding: 12px 16px;
1380
+ }
1381
+ }
1382
+
1383
+ .compose-alt-title {
1384
+ position: absolute;
1385
+ left: 50%;
1386
+ transform: translateX(-50%);
1387
+ font-size: var(--text-sm);
1388
+ font-weight: 600;
1389
+ letter-spacing: -0.005em;
1390
+ white-space: nowrap;
1391
+ }
1392
+
1299
1393
  .compose-alt-preview {
1300
1394
  display: flex;
1301
1395
  align-items: center;
1302
1396
  justify-content: center;
1303
- padding: 12px 16px 0;
1304
- max-height: 200px;
1397
+ padding: 20px 24px;
1398
+ flex: 1;
1399
+ min-height: 0;
1305
1400
  overflow: hidden;
1306
1401
  }
1307
1402
 
1308
1403
  .compose-alt-preview-img {
1309
1404
  max-width: 100%;
1310
- max-height: 180px;
1405
+ max-height: 320px;
1311
1406
  border-radius: 10px;
1312
1407
  object-fit: contain;
1313
1408
  }
1314
1409
 
1315
- .compose-alt-textarea {
1316
- flex: 1;
1317
- font-size: 0.84rem;
1318
- line-height: 1.65;
1410
+ .compose-alt-input-row {
1411
+ padding: 0 20px;
1412
+ border-top: 1px solid var(--site-divider);
1413
+ }
1414
+
1415
+ @media (min-width: 700px) {
1416
+ .compose-alt-input-row {
1417
+ padding: 0 24px;
1418
+ }
1419
+ }
1420
+
1421
+ .compose-alt-input {
1422
+ font-size: 0.9rem;
1423
+ padding: 14px 0;
1319
1424
  letter-spacing: 0.005em;
1320
- overflow-y: auto;
1321
1425
  }
1322
1426
 
1323
- .compose-alt-textarea::-webkit-scrollbar {
1324
- width: 3px;
1427
+ .compose-alt-footer {
1428
+ display: flex;
1429
+ align-items: center;
1430
+ justify-content: space-between;
1431
+ padding: 8px 12px 12px;
1432
+ border-top: 1px solid var(--site-divider);
1325
1433
  }
1326
1434
 
1327
- .compose-alt-textarea::-webkit-scrollbar-thumb {
1328
- background-color: var(--site-divider);
1435
+ @media (min-width: 700px) {
1436
+ .compose-alt-footer {
1437
+ padding: 8px 16px 12px;
1438
+ }
1439
+ }
1440
+
1441
+ /* =========================================================================
1442
+ * Media Lightbox
1443
+ * ========================================================================= */
1444
+
1445
+ @keyframes lightbox-fade-in {
1446
+ from {
1447
+ opacity: 0;
1448
+ }
1449
+ to {
1450
+ opacity: 1;
1451
+ }
1452
+ }
1453
+
1454
+ @keyframes lightbox-scale-in {
1455
+ from {
1456
+ opacity: 0;
1457
+ transform: scale(0.95);
1458
+ }
1459
+ to {
1460
+ opacity: 1;
1461
+ transform: scale(1);
1462
+ }
1463
+ }
1464
+
1465
+ .media-lightbox {
1466
+ padding: 0;
1467
+ border: none;
1468
+ background: transparent;
1469
+ width: 100%;
1470
+ height: 100%;
1471
+ max-width: 100%;
1472
+ max-height: 100%;
1473
+ outline: none;
1474
+ }
1475
+
1476
+ .media-lightbox[open] {
1477
+ animation: lightbox-fade-in 0.2s ease both;
1478
+ }
1479
+
1480
+ .media-lightbox::backdrop {
1481
+ background-color: rgba(0, 0, 0, 0.85);
1482
+ }
1483
+
1484
+ .media-lightbox-content {
1485
+ display: flex;
1486
+ align-items: center;
1487
+ justify-content: center;
1488
+ width: 100%;
1489
+ height: 100%;
1490
+ position: relative;
1491
+ outline: none;
1492
+ }
1493
+
1494
+ .media-lightbox-img {
1495
+ max-width: 90vw;
1496
+ max-height: 90vh;
1497
+ object-fit: contain;
1329
1498
  border-radius: 4px;
1499
+ animation: lightbox-scale-in 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
1500
+ }
1501
+
1502
+ .media-lightbox-close {
1503
+ position: fixed;
1504
+ top: 16px;
1505
+ left: 16px;
1506
+ z-index: 10;
1507
+ display: flex;
1508
+ align-items: center;
1509
+ justify-content: center;
1510
+ width: 40px;
1511
+ height: 40px;
1512
+ border-radius: 50%;
1513
+ border: none;
1514
+ background-color: rgba(0, 0, 0, 0.5);
1515
+ backdrop-filter: blur(8px);
1516
+ -webkit-backdrop-filter: blur(8px);
1517
+ color: white;
1518
+ cursor: pointer;
1519
+ transition: background-color 0.15s;
1520
+ }
1521
+
1522
+ .media-lightbox-close:hover {
1523
+ background-color: rgba(0, 0, 0, 0.7);
1524
+ }
1525
+
1526
+ .media-lightbox-nav {
1527
+ position: fixed;
1528
+ top: 50%;
1529
+ transform: translateY(-50%);
1530
+ z-index: 10;
1531
+ display: flex;
1532
+ align-items: center;
1533
+ justify-content: center;
1534
+ width: 44px;
1535
+ height: 44px;
1536
+ border-radius: 50%;
1537
+ border: none;
1538
+ background-color: rgba(0, 0, 0, 0.5);
1539
+ backdrop-filter: blur(8px);
1540
+ -webkit-backdrop-filter: blur(8px);
1541
+ color: white;
1542
+ cursor: pointer;
1543
+ transition: background-color 0.15s;
1544
+ }
1545
+
1546
+ .media-lightbox-nav:hover {
1547
+ background-color: rgba(0, 0, 0, 0.7);
1548
+ }
1549
+
1550
+ .media-lightbox-nav-prev {
1551
+ left: 16px;
1552
+ }
1553
+
1554
+ .media-lightbox-nav-next {
1555
+ right: 16px;
1556
+ }
1557
+
1558
+ .media-lightbox-counter {
1559
+ position: fixed;
1560
+ top: 20px;
1561
+ left: 50%;
1562
+ transform: translateX(-50%);
1563
+ z-index: 10;
1564
+ font-size: 0.8125rem;
1565
+ color: rgba(255, 255, 255, 0.7);
1566
+ font-variant-numeric: tabular-nums;
1567
+ user-select: none;
1568
+ }
1569
+
1570
+ @media (max-width: 640px) {
1571
+ .media-lightbox-img {
1572
+ max-width: 100vw;
1573
+ max-height: 85vh;
1574
+ border-radius: 0;
1575
+ }
1576
+
1577
+ .media-lightbox-close {
1578
+ width: 36px;
1579
+ height: 36px;
1580
+ top: 12px;
1581
+ left: 12px;
1582
+ }
1583
+
1584
+ .media-lightbox-nav {
1585
+ width: 36px;
1586
+ height: 36px;
1587
+ }
1588
+
1589
+ .media-lightbox-nav-prev {
1590
+ left: 8px;
1591
+ }
1592
+
1593
+ .media-lightbox-nav-next {
1594
+ right: 8px;
1595
+ }
1330
1596
  }
1331
1597
 
1332
1598
  /* =========================================================================
1333
- * Site Footer
1599
+ * Feed Media: Video, Audio, PDF
1334
1600
  * ========================================================================= */
1335
1601
 
1336
- .site-footer {
1337
- max-width: var(--site-width);
1338
- margin: var(--space-xl) auto 0;
1339
- padding: 0 var(--site-padding) var(--space-xl);
1340
- color: var(--site-text-secondary);
1341
- font-size: var(--text-sm);
1602
+ /* --- Video play overlay (feed) ----------------------------------------- */
1603
+
1604
+ .media-video-wrap {
1605
+ position: relative;
1606
+ display: block;
1607
+ cursor: pointer;
1608
+ overflow: hidden;
1609
+ border-radius: var(--media-radius, 0.5rem);
1342
1610
  }
1343
1611
 
1344
- .site-footer > .site-container {
1345
- border-top: 0.5px solid var(--site-divider);
1346
- padding-top: var(--content-gap);
1612
+ .media-video-wrap video {
1613
+ display: block;
1614
+ width: 100%;
1615
+ max-height: 24rem;
1616
+ object-fit: contain;
1617
+ border-radius: var(--media-radius, 0.5rem);
1618
+ background-color: black;
1619
+ }
1620
+
1621
+ .media-video-play-overlay {
1622
+ position: absolute;
1623
+ inset: 0;
1624
+ display: flex;
1625
+ align-items: center;
1626
+ justify-content: center;
1627
+ pointer-events: none;
1628
+ transition: opacity 0.15s;
1629
+ }
1630
+
1631
+ .media-video-play-overlay svg {
1632
+ width: 48px;
1633
+ height: 48px;
1634
+ filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.4));
1635
+ opacity: 0.85;
1636
+ }
1637
+
1638
+ /* --- Audio card (feed) -------------------------------------------------- */
1639
+
1640
+ .media-audio-card {
1641
+ display: flex;
1642
+ align-items: center;
1643
+ gap: 12px;
1644
+ padding: 12px 16px;
1645
+ background-color: var(--site-nav-hover-bg);
1646
+ border-radius: var(--media-radius, 0.5rem);
1647
+ margin-top: 0.75rem;
1648
+ }
1649
+
1650
+ .media-audio-icon {
1651
+ flex-shrink: 0;
1652
+ color: var(--site-text-secondary);
1653
+ }
1654
+
1655
+ .media-audio-name {
1656
+ font-size: var(--text-sm);
1657
+ font-weight: 500;
1658
+ color: var(--site-text-primary);
1659
+ min-width: 0;
1660
+ overflow: hidden;
1661
+ text-overflow: ellipsis;
1662
+ white-space: nowrap;
1663
+ }
1664
+
1665
+ .media-audio-player {
1666
+ flex: 1;
1667
+ min-width: 0;
1668
+ height: 32px;
1669
+ }
1670
+
1671
+ .media-audio-player audio {
1672
+ width: 100%;
1673
+ height: 32px;
1674
+ }
1675
+
1676
+ /* --- PDF card (feed) ---------------------------------------------------- */
1677
+
1678
+ .media-pdf-card {
1679
+ display: flex;
1680
+ align-items: center;
1681
+ gap: 12px;
1682
+ padding: 12px 16px;
1683
+ background-color: var(--site-nav-hover-bg);
1684
+ border-radius: var(--media-radius, 0.5rem);
1685
+ margin-top: 0.75rem;
1686
+ text-decoration: none;
1687
+ color: var(--site-text-primary);
1688
+ transition:
1689
+ background-color 0.15s,
1690
+ border-color 0.15s;
1691
+ border: 1px solid transparent;
1692
+ }
1693
+
1694
+ .media-pdf-card:hover {
1695
+ border-color: var(--site-divider);
1696
+ }
1697
+
1698
+ .media-pdf-icon {
1699
+ flex-shrink: 0;
1700
+ color: var(--site-text-secondary);
1701
+ }
1702
+
1703
+ .media-pdf-name {
1704
+ font-size: var(--text-sm);
1705
+ font-weight: 500;
1706
+ min-width: 0;
1707
+ overflow: hidden;
1708
+ text-overflow: ellipsis;
1709
+ white-space: nowrap;
1710
+ }
1711
+
1712
+ .media-pdf-size {
1713
+ font-size: 0.6875rem;
1714
+ color: var(--site-text-secondary);
1715
+ flex-shrink: 0;
1716
+ margin-left: auto;
1717
+ }
1718
+
1719
+ /* --- Lightbox video ----------------------------------------------------- */
1720
+
1721
+ .media-lightbox-video {
1722
+ max-width: 90vw;
1723
+ max-height: 90vh;
1724
+ border-radius: 4px;
1725
+ animation: lightbox-scale-in 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
1726
+ background-color: black;
1727
+ }
1728
+
1729
+ @media (max-width: 640px) {
1730
+ .media-lightbox-video {
1731
+ max-width: 100vw;
1732
+ max-height: 85vh;
1733
+ border-radius: 0;
1734
+ }
1735
+ }
1736
+
1737
+ /* =========================================================================
1738
+ * Site Footer
1739
+ * ========================================================================= */
1740
+
1741
+ .site-footer {
1742
+ max-width: var(--site-width);
1743
+ margin: var(--space-xl) auto 0;
1744
+ padding: 0 var(--site-padding) var(--space-xl);
1745
+ color: var(--site-text-secondary);
1746
+ font-size: var(--text-sm);
1747
+ }
1748
+
1749
+ .site-footer > .site-container {
1750
+ border-top: 0.5px solid var(--site-divider);
1751
+ padding-top: var(--content-gap);
1752
+ }
1753
+
1754
+ /* =========================================================================
1755
+ * Tiptap Editor
1756
+ * ========================================================================= */
1757
+
1758
+ .compose-tiptap-body {
1759
+ flex: 1;
1760
+ min-height: 0;
1761
+ }
1762
+
1763
+ .compose-tiptap-body .tiptap {
1764
+ outline: none;
1765
+ min-height: 120px;
1766
+ font-size: var(--text-base);
1767
+ line-height: 1.65;
1768
+ letter-spacing: 0.005em;
1769
+ color: var(--site-text-primary);
1770
+ font-family: var(--font-body);
1771
+ }
1772
+
1773
+ .compose-tiptap-thoughts .tiptap {
1774
+ min-height: 72px;
1775
+ }
1776
+
1777
+ /* Placeholder */
1778
+ .compose-tiptap-body .tiptap p.is-editor-empty:first-child::before {
1779
+ content: attr(data-placeholder);
1780
+ float: left;
1781
+ color: var(--site-text-secondary);
1782
+ opacity: 0.5;
1783
+ pointer-events: none;
1784
+ height: 0;
1785
+ }
1786
+
1787
+ /* Tiptap prose styling */
1788
+ .compose-tiptap-body .tiptap h1 {
1789
+ font-family: var(--font-heading);
1790
+ font-size: 1.5rem;
1791
+ font-weight: 600;
1792
+ line-height: 1.3;
1793
+ margin: 0.75em 0 0.25em;
1794
+ }
1795
+
1796
+ .compose-tiptap-body .tiptap h2 {
1797
+ font-family: var(--font-heading);
1798
+ font-size: 1.25rem;
1799
+ font-weight: 600;
1800
+ line-height: 1.35;
1801
+ margin: 0.75em 0 0.25em;
1802
+ }
1803
+
1804
+ .compose-tiptap-body .tiptap h3 {
1805
+ font-family: var(--font-heading);
1806
+ font-size: 1.1rem;
1807
+ font-weight: 600;
1808
+ line-height: 1.4;
1809
+ margin: 0.75em 0 0.25em;
1810
+ }
1811
+
1812
+ .compose-tiptap-body .tiptap p {
1813
+ margin: 0.25em 0;
1814
+ }
1815
+
1816
+ .compose-tiptap-body .tiptap ul {
1817
+ list-style-type: disc;
1818
+ padding-left: 1.5em;
1819
+ margin: 0.25em 0;
1820
+ }
1821
+
1822
+ .compose-tiptap-body .tiptap ol {
1823
+ list-style-type: decimal;
1824
+ padding-left: 1.5em;
1825
+ margin: 0.25em 0;
1826
+ }
1827
+
1828
+ .compose-tiptap-body .tiptap li {
1829
+ margin: 0.15em 0;
1830
+ }
1831
+
1832
+ .compose-tiptap-body .tiptap blockquote {
1833
+ border-left: 3px solid var(--site-divider);
1834
+ padding-left: 1em;
1835
+ margin: 0.5em 0;
1836
+ color: var(--site-text-secondary);
1837
+ }
1838
+
1839
+ .compose-tiptap-body .tiptap pre {
1840
+ background: var(--site-elevated-bg);
1841
+ border-radius: 6px;
1842
+ padding: 0.75em 1em;
1843
+ margin: 0.5em 0;
1844
+ overflow-x: auto;
1845
+ font-size: 0.85em;
1846
+ }
1847
+
1848
+ .compose-tiptap-body .tiptap code {
1849
+ background: var(--site-elevated-bg);
1850
+ border-radius: 3px;
1851
+ padding: 0.15em 0.3em;
1852
+ font-size: 0.9em;
1853
+ }
1854
+
1855
+ .compose-tiptap-body .tiptap pre code {
1856
+ background: none;
1857
+ border-radius: 0;
1858
+ padding: 0;
1859
+ font-size: inherit;
1860
+ }
1861
+
1862
+ .compose-tiptap-body .tiptap hr {
1863
+ border: none;
1864
+ border-top: 1px solid var(--site-divider);
1865
+ margin: 1em 0;
1866
+ }
1867
+
1868
+ /* --- Table in editor -------------------------------------------------- */
1869
+
1870
+ .compose-tiptap-body .tiptap table {
1871
+ border-collapse: collapse;
1872
+ width: 100%;
1873
+ margin: 0.75em 0;
1874
+ overflow: hidden;
1875
+ }
1876
+
1877
+ .compose-tiptap-body .tiptap td,
1878
+ .compose-tiptap-body .tiptap th {
1879
+ border: 1px solid var(--site-divider);
1880
+ padding: 0.4em 0.6em;
1881
+ vertical-align: top;
1882
+ min-width: 1em;
1883
+ position: relative;
1884
+ }
1885
+
1886
+ .compose-tiptap-body .tiptap th {
1887
+ font-weight: 600;
1888
+ background: var(--site-elevated-bg);
1889
+ }
1890
+
1891
+ .compose-tiptap-body .tiptap .selectedCell {
1892
+ background: oklch(from var(--site-accent) l c h / 0.12);
1893
+ }
1894
+
1895
+ /* --- Image figure in editor ------------------------------------------- */
1896
+
1897
+ .tiptap-image-figure {
1898
+ margin: 0.75em 0;
1899
+ position: relative;
1900
+
1901
+ /* Toolbar palette — soft charcoal, not pure black */
1902
+ --_img-toolbar-bg: oklch(0.25 0.01 260 / 0.82);
1903
+ --_img-toolbar-text: #f5f5f5;
1904
+ --_img-toolbar-hover: oklch(1 0 0 / 0.12);
1905
+ --_img-toolbar-active: oklch(1 0 0 / 0.22);
1906
+ --_img-toolbar-sep: oklch(1 0 0 / 0.15);
1907
+ }
1908
+
1909
+ :is(.dark, [data-theme="dark"]) .tiptap-image-figure {
1910
+ --_img-toolbar-bg: oklch(0.32 0.01 260 / 0.88);
1911
+ }
1912
+
1913
+ .tiptap-image-container {
1914
+ position: relative;
1915
+ border-radius: 6px;
1916
+ border: 2px solid transparent;
1917
+ transition: border-color 0.15s;
1918
+ }
1919
+
1920
+ /* Hover hint */
1921
+ .tiptap-image-figure:hover .tiptap-image-container {
1922
+ border-color: var(--site-divider);
1923
+ }
1924
+
1925
+ /* Selected ring */
1926
+ .tiptap-image-figure[data-selected="true"] .tiptap-image-container {
1927
+ border-color: var(--primary);
1928
+ }
1929
+
1930
+ .tiptap-image-figure img {
1931
+ width: 100%;
1932
+ max-height: 500px;
1933
+ object-fit: contain;
1934
+ border-radius: 4px;
1935
+ display: block;
1936
+ }
1937
+
1938
+ /* Layout variants — in compact dialog, wide/full just fill the container */
1939
+ .tiptap-image-figure[data-layout="wide"],
1940
+ .tiptap-image-figure[data-layout="full"] {
1941
+ width: 100%;
1942
+ }
1943
+
1944
+ .tiptap-image-figure[data-layout="full"] .tiptap-image-container {
1945
+ border-radius: 0;
1946
+ border-left: none;
1947
+ border-right: none;
1948
+ }
1949
+
1950
+ .tiptap-image-figure[data-layout="full"] img {
1951
+ border-radius: 0;
1952
+ }
1953
+
1954
+ /* Fullscreen editor — enough room for real breakout */
1955
+ .compose-fullscreen .tiptap-image-figure[data-layout="wide"] {
1956
+ width: 1200px;
1957
+ max-width: 100vw;
1958
+ margin-left: 50%;
1959
+ transform: translateX(-50%);
1960
+ }
1961
+
1962
+ .compose-fullscreen .tiptap-image-figure[data-layout="full"] {
1963
+ width: 100vw;
1964
+ margin-left: 50%;
1965
+ transform: translateX(-50%);
1966
+ }
1967
+
1968
+ .tiptap-image-figure[data-layout="full"] img {
1969
+ border-radius: 0;
1970
+ }
1971
+
1972
+ /* Centered toolbar — hidden until selected */
1973
+ .tiptap-image-toolbar {
1974
+ display: none;
1975
+ position: absolute;
1976
+ top: 8px;
1977
+ left: 50%;
1978
+ transform: translateX(-50%);
1979
+ background: var(--_img-toolbar-bg);
1980
+ backdrop-filter: blur(8px);
1981
+ color: var(--_img-toolbar-text);
1982
+ border-radius: 8px;
1983
+ padding: 4px;
1984
+ gap: 2px;
1985
+ align-items: center;
1986
+ z-index: 2;
1987
+ }
1988
+
1989
+ .tiptap-image-figure[data-selected="true"] .tiptap-image-toolbar {
1990
+ display: flex;
1991
+ }
1992
+
1993
+ .tiptap-image-toolbar button {
1994
+ display: flex;
1995
+ align-items: center;
1996
+ justify-content: center;
1997
+ width: 28px;
1998
+ height: 28px;
1999
+ border-radius: 6px;
2000
+ background: transparent;
2001
+ color: var(--_img-toolbar-text);
2002
+ border: none;
2003
+ cursor: pointer;
2004
+ }
2005
+
2006
+ .tiptap-image-toolbar button svg {
2007
+ width: 16px;
2008
+ height: 16px;
2009
+ flex-shrink: 0;
2010
+ }
2011
+
2012
+ .tiptap-image-toolbar button:hover {
2013
+ background: var(--_img-toolbar-hover);
2014
+ }
2015
+
2016
+ .tiptap-image-toolbar button.is-active {
2017
+ background: var(--_img-toolbar-active);
2018
+ }
2019
+
2020
+ .tiptap-toolbar-sep {
2021
+ width: 1px;
2022
+ height: 16px;
2023
+ background: var(--_img-toolbar-sep);
2024
+ flex-shrink: 0;
2025
+ }
2026
+
2027
+ /* Caption bar — shown when selected, directly below image */
2028
+ .tiptap-image-caption-bar {
2029
+ display: none;
2030
+ align-items: center;
2031
+ gap: 6px;
2032
+ padding: 6px 0;
2033
+ margin-top: 4px;
2034
+ }
2035
+
2036
+ .tiptap-image-figure[data-selected="true"] .tiptap-image-caption-bar {
2037
+ display: flex;
2038
+ }
2039
+
2040
+ .tiptap-image-caption-bar input {
2041
+ flex: 1;
2042
+ border: none;
2043
+ outline: none;
2044
+ background: transparent;
2045
+ font-size: 0.85rem;
2046
+ color: var(--site-text-secondary);
2047
+ text-align: center;
2048
+ }
2049
+
2050
+ .tiptap-image-alt-btn {
2051
+ font-size: 0.7rem;
2052
+ font-weight: 600;
2053
+ padding: 2px 6px;
2054
+ border-radius: 4px;
2055
+ border: 1px solid var(--site-divider);
2056
+ background: transparent;
2057
+ cursor: pointer;
2058
+ flex-shrink: 0;
2059
+ }
2060
+
2061
+ .tiptap-image-alt-btn.is-active {
2062
+ background: var(--primary);
2063
+ color: var(--primary-foreground);
2064
+ border-color: transparent;
2065
+ }
2066
+
2067
+ /* Static figcaption (shown when not selected) */
2068
+ .tiptap-image-figcaption {
2069
+ text-align: center;
2070
+ font-size: 0.85rem;
2071
+ color: var(--site-text-secondary);
2072
+ margin-top: 0.4em;
2073
+ }
2074
+
2075
+ .tiptap-image-figcaption:empty {
2076
+ display: none;
2077
+ }
2078
+
2079
+ .tiptap-image-figure[data-selected="true"] .tiptap-image-figcaption {
2080
+ display: none;
2081
+ }
2082
+
2083
+ .compose-tiptap-body .tiptap a {
2084
+ color: var(--site-accent);
2085
+ text-decoration: underline;
2086
+ text-underline-offset: 2px;
2087
+ }
2088
+
2089
+ .compose-tiptap-body .tiptap s {
2090
+ text-decoration: line-through;
2091
+ }
2092
+
2093
+ /* MoreBreak visual node */
2094
+ .tiptap-more-break {
2095
+ border-top: 2px dashed var(--site-divider);
2096
+ text-align: center;
2097
+ padding: 4px 0;
2098
+ margin: 0.75em 0;
2099
+ color: var(--site-text-secondary);
2100
+ font-size: 0.75rem;
2101
+ letter-spacing: 0.05em;
2102
+ text-transform: uppercase;
2103
+ user-select: none;
2104
+ cursor: default;
2105
+ }
2106
+
2107
+ .tiptap-more-break.ProseMirror-selectednode {
2108
+ border-color: var(--site-accent);
2109
+ color: var(--site-accent);
2110
+ }
2111
+
2112
+ /* Slash command dropdown */
2113
+ .tiptap-slash-menu {
2114
+ position: fixed;
2115
+ z-index: 10000;
2116
+ background: var(--site-elevated-bg);
2117
+ border: 1px solid var(--site-divider);
2118
+ border-radius: 8px;
2119
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
2120
+ padding: 4px;
2121
+ min-width: 200px;
2122
+ max-height: 320px;
2123
+ overflow-y: auto;
2124
+ }
2125
+
2126
+ .tiptap-slash-item {
2127
+ display: flex;
2128
+ align-items: center;
2129
+ gap: 10px;
2130
+ padding: 8px 12px;
2131
+ border-radius: 6px;
2132
+ cursor: pointer;
2133
+ font-size: 0.875rem;
2134
+ color: var(--site-text-primary);
2135
+ transition: background 0.1s;
2136
+ }
2137
+
2138
+ .tiptap-slash-item:hover,
2139
+ .tiptap-slash-item.is-selected {
2140
+ background: var(--site-nav-hover-bg);
2141
+ }
2142
+
2143
+ .tiptap-slash-item-icon {
2144
+ display: flex;
2145
+ align-items: center;
2146
+ justify-content: center;
2147
+ width: 24px;
2148
+ height: 24px;
2149
+ font-size: 0.8rem;
2150
+ color: var(--site-text-secondary);
2151
+ flex-shrink: 0;
2152
+ }
2153
+
2154
+ .tiptap-slash-item-label {
2155
+ flex: 1;
2156
+ }
2157
+
2158
+ /* Bubble menu — floating toolbar on text selection */
2159
+ .tiptap-bubble-menu {
2160
+ position: fixed;
2161
+ z-index: 10000;
2162
+ display: flex;
2163
+ align-items: center;
2164
+ gap: 2px;
2165
+ padding: 4px;
2166
+ background: var(--color-foreground);
2167
+ border-radius: 8px;
2168
+ box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);
2169
+ }
2170
+
2171
+ .tiptap-bubble-menu::after {
2172
+ content: "";
2173
+ position: absolute;
2174
+ bottom: -4px;
2175
+ left: 50%;
2176
+ transform: translateX(-50%);
2177
+ border-left: 5px solid transparent;
2178
+ border-right: 5px solid transparent;
2179
+ border-top: 5px solid var(--color-foreground);
2180
+ }
2181
+
2182
+ .tiptap-bubble-btn {
2183
+ display: flex;
2184
+ align-items: center;
2185
+ justify-content: center;
2186
+ width: 28px;
2187
+ height: 28px;
2188
+ border-radius: 6px;
2189
+ border: none;
2190
+ background: transparent;
2191
+ color: var(--color-background);
2192
+ cursor: pointer;
2193
+ }
2194
+
2195
+ .tiptap-bubble-btn svg {
2196
+ width: 16px;
2197
+ height: 16px;
2198
+ flex-shrink: 0;
2199
+ }
2200
+
2201
+ .tiptap-bubble-btn:hover {
2202
+ background: oklch(from var(--color-background) l c h / 0.15);
2203
+ }
2204
+
2205
+ .tiptap-bubble-btn.is-active {
2206
+ background: oklch(from var(--color-background) l c h / 0.22);
2207
+ }
2208
+
2209
+ .tiptap-bubble-sep {
2210
+ width: 1px;
2211
+ height: 16px;
2212
+ background: oklch(from var(--color-background) l c h / 0.2);
2213
+ flex-shrink: 0;
2214
+ }
2215
+
2216
+ /* Link input popup — light speech-bubble with URL field */
2217
+ .tiptap-link-input {
2218
+ position: fixed;
2219
+ z-index: 10001;
2220
+ display: flex;
2221
+ align-items: center;
2222
+ gap: 4px;
2223
+ padding: 4px 4px 4px 10px;
2224
+ background: var(--color-background);
2225
+ border: 1px solid var(--color-border);
2226
+ border-radius: 8px;
2227
+ box-shadow: 0 4px 14px rgba(0, 0, 0, 0.1);
2228
+ }
2229
+
2230
+ .tiptap-link-input::before {
2231
+ content: "";
2232
+ position: absolute;
2233
+ bottom: -7px;
2234
+ left: 50%;
2235
+ transform: translateX(-50%);
2236
+ border-left: 6px solid transparent;
2237
+ border-right: 6px solid transparent;
2238
+ border-top: 6px solid var(--color-border);
2239
+ }
2240
+
2241
+ .tiptap-link-input::after {
2242
+ content: "";
2243
+ position: absolute;
2244
+ bottom: -5px;
2245
+ left: 50%;
2246
+ transform: translateX(-50%);
2247
+ border-left: 5px solid transparent;
2248
+ border-right: 5px solid transparent;
2249
+ border-top: 5px solid var(--color-background);
2250
+ }
2251
+
2252
+ .tiptap-link-input-field {
2253
+ border: none;
2254
+ outline: none;
2255
+ background: transparent;
2256
+ font-size: 0.875rem;
2257
+ min-width: 240px;
2258
+ color: var(--color-foreground);
2259
+ }
2260
+
2261
+ .tiptap-link-input-field::placeholder {
2262
+ color: var(--color-muted-foreground);
2263
+ }
2264
+
2265
+ .tiptap-link-input-confirm {
2266
+ display: flex;
2267
+ align-items: center;
2268
+ justify-content: center;
2269
+ width: 28px;
2270
+ height: 28px;
2271
+ border-radius: 6px;
2272
+ border: none;
2273
+ background: transparent;
2274
+ color: var(--color-muted-foreground);
2275
+ cursor: pointer;
2276
+ flex-shrink: 0;
2277
+ }
2278
+
2279
+ .tiptap-link-input-confirm:hover {
2280
+ background: var(--color-accent);
2281
+ color: var(--color-foreground);
2282
+ }
2283
+
2284
+ /* Link preview tooltip — dark with URL + edit/delete buttons */
2285
+ .tiptap-link-preview {
2286
+ position: fixed;
2287
+ z-index: 10001;
2288
+ display: flex;
2289
+ align-items: center;
2290
+ gap: 4px;
2291
+ padding: 4px 4px 4px 10px;
2292
+ background: var(--color-foreground);
2293
+ border-radius: 8px;
2294
+ box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);
2295
+ max-width: 360px;
2296
+ }
2297
+
2298
+ .tiptap-link-preview::after {
2299
+ content: "";
2300
+ position: absolute;
2301
+ bottom: -4px;
2302
+ left: 50%;
2303
+ transform: translateX(-50%);
2304
+ border-left: 5px solid transparent;
2305
+ border-right: 5px solid transparent;
2306
+ border-top: 5px solid var(--color-foreground);
2307
+ }
2308
+
2309
+ .tiptap-link-preview-url {
2310
+ font-size: 0.8125rem;
2311
+ color: var(--color-background);
2312
+ opacity: 0.7;
2313
+ overflow: hidden;
2314
+ text-overflow: ellipsis;
2315
+ white-space: nowrap;
2316
+ max-width: 220px;
2317
+ }
2318
+
2319
+ .tiptap-link-preview-btn {
2320
+ display: flex;
2321
+ align-items: center;
2322
+ justify-content: center;
2323
+ width: 28px;
2324
+ height: 28px;
2325
+ border-radius: 6px;
2326
+ border: none;
2327
+ background: transparent;
2328
+ color: var(--color-background);
2329
+ opacity: 0.7;
2330
+ cursor: pointer;
2331
+ flex-shrink: 0;
2332
+ }
2333
+
2334
+ .tiptap-link-preview-btn:hover {
2335
+ background: oklch(from var(--color-background) l c h / 0.15);
2336
+ opacity: 1;
2337
+ }
2338
+
2339
+ .tiptap-link-preview-btn svg {
2340
+ width: 14px;
2341
+ height: 14px;
2342
+ flex-shrink: 0;
2343
+ }
2344
+
2345
+ /* Fullscreen editor dialog — enters browser top layer via showModal() */
2346
+ .compose-fullscreen-dialog {
2347
+ padding: 0;
2348
+ border: none;
2349
+ outline: none;
2350
+ margin: 0;
2351
+ width: 100vw;
2352
+ max-width: 100vw;
2353
+ height: 100dvh;
2354
+ max-height: 100dvh;
2355
+ background: var(--site-bg, var(--color-background, #fff));
2356
+ overscroll-behavior: contain;
2357
+ }
2358
+
2359
+ .compose-fullscreen-dialog::backdrop {
2360
+ background: transparent;
2361
+ }
2362
+
2363
+ .compose-fullscreen {
2364
+ display: flex;
2365
+ flex-direction: column;
2366
+ height: 100%;
2367
+ }
2368
+
2369
+ .compose-fullscreen-toolbar {
2370
+ display: flex;
2371
+ align-items: center;
2372
+ padding: 12px 16px;
2373
+ border-bottom: 1px solid var(--site-divider);
2374
+ gap: 8px;
2375
+ }
2376
+
2377
+ .compose-fullscreen-content {
2378
+ flex: 1;
2379
+ overflow-y: auto;
2380
+ display: flex;
2381
+ justify-content: center;
2382
+ }
2383
+
2384
+ .compose-fullscreen-inner {
2385
+ width: 100%;
2386
+ max-width: var(--site-width);
2387
+ padding: 32px 16px;
2388
+ display: flex;
2389
+ flex-direction: column;
2390
+ gap: 8px;
2391
+ }
2392
+
2393
+ .compose-fullscreen-title {
2394
+ border: none;
2395
+ outline: none;
2396
+ background: transparent;
2397
+ width: 100%;
2398
+ font-family: var(--font-heading);
2399
+ font-size: 1.5rem;
2400
+ font-weight: 500;
2401
+ color: var(--site-text-primary);
2402
+ line-height: 1.3;
2403
+ }
2404
+
2405
+ .compose-fullscreen-title::placeholder {
2406
+ color: var(--site-text-secondary);
2407
+ opacity: 0.5;
2408
+ }
2409
+
2410
+ .compose-fullscreen .compose-tiptap-body .tiptap {
2411
+ min-height: 400px;
2412
+ }
2413
+
2414
+ .compose-fullscreen-plus-menu {
2415
+ position: relative;
2416
+ }
2417
+
2418
+ .compose-fullscreen-plus-dropdown {
2419
+ position: absolute;
2420
+ top: 100%;
2421
+ left: 0;
2422
+ margin-top: 4px;
1347
2423
  }
1348
2424
  }