create-feedbax 0.2.0 → 0.2.2

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 (143) hide show
  1. package/README.md +17 -5
  2. package/dist/cli.js +2610 -291
  3. package/dist/index.js +2375 -200
  4. package/package.json +7 -7
  5. package/template/.feedbax-template.sha256 +1 -1
  6. package/template/.gitignore.template +1 -0
  7. package/template/.npmignore.template +1 -0
  8. package/template/.nvmrc +1 -0
  9. package/template/AGENTS.md +13 -0
  10. package/template/CONNECTED.md +418 -0
  11. package/template/README.md +97 -0
  12. package/template/components.json +1 -1
  13. package/template/eslint.config.mjs +23 -0
  14. package/template/feedbax-vite.ts +79 -0
  15. package/template/migrations/0001_connected.sql +6 -0
  16. package/template/migrations/0002_participation.sql +8 -0
  17. package/template/migrations/0003_images.sql +3 -0
  18. package/template/migrations/0004_followed_status.sql +9 -0
  19. package/template/migrations/0005_github.sql +4 -0
  20. package/template/migrations/0006_integration.sql +3 -0
  21. package/template/migrations/0007_ownership.sql +2 -0
  22. package/template/migrations/0008_integration_recovery.sql +5 -0
  23. package/template/migrations/0009_observed_history.sql +3 -0
  24. package/template/package.json +39 -34
  25. package/template/src/authorized-draft-post.tsx +1 -0
  26. package/template/src/changelog-page.tsx +63 -54
  27. package/template/src/changelog-runtime.ts +2 -1
  28. package/template/src/cloudflare-workers.d.ts +9 -0
  29. package/template/src/comment-creation.test.tsx +95 -7
  30. package/template/src/comment-thread-page.ts +11 -1
  31. package/template/src/components/command-palette.tsx +59 -30
  32. package/template/src/components/connected-identity-provider.tsx +135 -0
  33. package/template/src/components/device-profile-provider.tsx +41 -26
  34. package/template/src/components/follow-post-button.tsx +78 -0
  35. package/template/src/components/header.tsx +2 -0
  36. package/template/src/components/image-attachments.tsx +187 -0
  37. package/template/src/components/loader.tsx +48 -5
  38. package/template/src/components/notification-inbox.tsx +232 -0
  39. package/template/src/components/portal-footer.tsx +14 -0
  40. package/template/src/components/post-history.tsx +101 -0
  41. package/template/src/components/profile-menu.tsx +37 -0
  42. package/template/src/components/ui/components/command.tsx +30 -29
  43. package/template/src/components/ui/components/message-scroller.tsx +2 -2
  44. package/template/src/components/ui/components/scroll-area.tsx +0 -1
  45. package/template/src/components/ui/components/switch.tsx +29 -0
  46. package/template/src/components/ui/styles/globals.css +1 -1
  47. package/template/src/configured-feedback.test.ts +82 -0
  48. package/template/src/configured-feedback.ts +61 -0
  49. package/template/src/connected-identity.test.ts +148 -0
  50. package/template/src/connected-identity.ts +127 -0
  51. package/template/src/connected-participation.test.tsx +67 -0
  52. package/template/src/connected-runtime.test.ts +244 -0
  53. package/template/src/connected-runtime.ts +176 -0
  54. package/template/src/connected-social.test.tsx +158 -0
  55. package/template/src/feedback-cache-invalidation.ts +3 -0
  56. package/template/src/feedback-runtime.ts +123 -13
  57. package/template/src/feedbax/changelog/index.test.ts +35 -0
  58. package/template/src/feedbax/changelog/index.ts +5 -1
  59. package/template/src/feedbax/changelog/notion-changelog.test.ts +1 -1
  60. package/template/src/feedbax/changelog/notion-changelog.ts +1 -1
  61. package/template/src/feedbax/config/index.test.ts +73 -1
  62. package/template/src/feedbax/config/index.ts +205 -9
  63. package/template/src/feedbax/feedback/comment-storage.ts +38 -0
  64. package/template/src/feedbax/feedback/connected-feedback.ts +235 -0
  65. package/template/src/feedbax/feedback/connected.test.ts +272 -0
  66. package/template/src/feedbax/feedback/connected.ts +225 -0
  67. package/template/src/feedbax/feedback/email-delivery.test.ts +65 -0
  68. package/template/src/feedbax/feedback/email-delivery.ts +66 -0
  69. package/template/src/feedbax/feedback/feedback-storage.ts +1 -0
  70. package/template/src/feedbax/feedback/github-comments.ts +390 -0
  71. package/template/src/feedbax/feedback/github-feedback.test.ts +1138 -0
  72. package/template/src/feedbax/feedback/github-feedback.ts +581 -0
  73. package/template/src/feedbax/feedback/github-request.ts +120 -0
  74. package/template/src/feedbax/feedback/github-service-client.ts +56 -0
  75. package/template/src/feedbax/feedback/identity-handoff.test.ts +81 -0
  76. package/template/src/feedbax/feedback/identity-handoff.ts +119 -0
  77. package/template/src/feedbax/feedback/image-feedback.ts +114 -0
  78. package/template/src/feedbax/feedback/images.test.ts +223 -0
  79. package/template/src/feedbax/feedback/images.ts +350 -0
  80. package/template/src/feedbax/feedback/index.ts +226 -16
  81. package/template/src/feedbax/feedback/integration-auth.ts +138 -0
  82. package/template/src/feedbax/feedback/notion-comments.ts +2 -35
  83. package/template/src/feedbax/feedback/notion-image-review.ts +55 -0
  84. package/template/src/feedbax/feedback/observed-history.test.ts +150 -0
  85. package/template/src/feedbax/feedback/observed-history.ts +219 -0
  86. package/template/src/feedbax/feedback/ownership.ts +170 -0
  87. package/template/src/feedbax/feedback/participation.test.ts +653 -0
  88. package/template/src/feedbax/feedback/participation.ts +502 -0
  89. package/template/src/history-runtime.test.ts +80 -0
  90. package/template/src/history-runtime.ts +37 -0
  91. package/template/src/images-runtime.test.ts +133 -0
  92. package/template/src/images-runtime.ts +125 -0
  93. package/template/src/index.css +103 -440
  94. package/template/src/integration-runtime.test.ts +365 -0
  95. package/template/src/integration-runtime.ts +289 -0
  96. package/template/src/lazy-post-detail-overlay.tsx +13 -2
  97. package/template/src/my-feedback-page.test.tsx +152 -0
  98. package/template/src/my-feedback-page.tsx +398 -0
  99. package/template/src/my-feedback-runtime.test.ts +93 -0
  100. package/template/src/my-feedback-runtime.ts +154 -0
  101. package/template/src/overlay-post-detail.test.tsx +59 -8
  102. package/template/src/overlay-post-detail.tsx +20 -69
  103. package/template/src/participation-client.ts +63 -0
  104. package/template/src/participation-runtime.test.ts +35 -0
  105. package/template/src/participation-runtime.ts +255 -0
  106. package/template/src/portal-comments.ts +35 -5
  107. package/template/src/portal-feedback-form.tsx +29 -6
  108. package/template/src/portal-feedback-runtime.ts +3 -0
  109. package/template/src/portal-feedback-server-function.ts +6 -3
  110. package/template/src/portal-feedback-submission.ts +19 -0
  111. package/template/src/portal-server-entry.ts +13 -0
  112. package/template/src/post-creation-flow.tsx +2 -2
  113. package/template/src/post-detail-content.test.tsx +233 -0
  114. package/template/src/post-detail-content.tsx +162 -0
  115. package/template/src/post-detail-query.ts +34 -0
  116. package/template/src/post-results.tsx +1 -1
  117. package/template/src/public-cache-policy.test.ts +11 -4
  118. package/template/src/public-cache-policy.ts +1 -1
  119. package/template/src/public-feedback-index.tsx +9 -39
  120. package/template/src/public-feedback-page.test.tsx +65 -0
  121. package/template/src/public-feedback-page.ts +12 -1
  122. package/template/src/public-portal-error.tsx +1 -1
  123. package/template/src/public-post-detail-skeleton.tsx +54 -0
  124. package/template/src/public-post-detail.tsx +437 -271
  125. package/template/src/public-post-route.test.tsx +39 -3
  126. package/template/src/public-post-route.tsx +15 -28
  127. package/template/src/public-release-links.test.ts +120 -0
  128. package/template/src/public-release-links.ts +130 -0
  129. package/template/src/public-roadmap-route.test.tsx +38 -2
  130. package/template/src/public-roadmap-view.tsx +56 -23
  131. package/template/src/public-shell.test.tsx +26 -0
  132. package/template/src/routeTree.gen.ts +70 -3
  133. package/template/src/router.tsx +2 -0
  134. package/template/src/routes/__root.tsx +3 -5
  135. package/template/src/routes/email-preferences.tsx +77 -0
  136. package/template/src/routes/my-feedback.tsx +16 -0
  137. package/template/src/routes/submit.tsx +1 -1
  138. package/template/src/safe-public-failure.ts +3 -1
  139. package/template/src/server.ts +87 -2
  140. package/template/src/submission-intent.ts +26 -0
  141. package/template/src/trusted-feedback-handler.test.ts +1 -1
  142. package/template/src/vote-toggle.tsx +42 -9
  143. package/template/vite.config.ts +2 -0
@@ -1,4 +1,4 @@
1
- @import "@feedbax/ui/globals.css";
1
+ @import "./components/ui/styles/globals.css";
2
2
 
3
3
  :root {
4
4
  --portal-ink: var(--foreground);
@@ -154,13 +154,7 @@
154
154
 
155
155
  body {
156
156
  margin: 0;
157
- background:
158
- linear-gradient(
159
- color-mix(in srgb, var(--foreground) 3.5%, transparent) 1px,
160
- transparent 1px
161
- ),
162
- var(--portal-paper);
163
- background-size: 100% 4rem;
157
+ background: var(--portal-paper);
164
158
  color: var(--portal-ink);
165
159
  }
166
160
 
@@ -181,6 +175,14 @@ textarea:focus-visible {
181
175
  outline-offset: 3px;
182
176
  }
183
177
 
178
+ input[data-slot="command-input"]:focus-visible {
179
+ outline: none;
180
+ }
181
+
182
+ [data-slot="command-input-wrapper"]:focus-within {
183
+ box-shadow: inset 0 -1px 0 var(--ring);
184
+ }
185
+
184
186
  .vote-toggle-button {
185
187
  display: inline-flex;
186
188
  min-height: 2.5rem;
@@ -272,10 +274,10 @@ textarea:focus-visible {
272
274
 
273
275
  .feedback-submit-copy h2 {
274
276
  margin: 0;
275
- font-size: clamp(2rem, 4vw, 3.8rem);
276
- font-weight: 650;
277
- letter-spacing: -0.06em;
278
- line-height: 0.98;
277
+ font-size: var(--text-xl);
278
+ font-weight: 600;
279
+ letter-spacing: -0.025em;
280
+ line-height: 1.4;
279
281
  }
280
282
 
281
283
  .feedback-submit-copy > p:last-child {
@@ -466,8 +468,8 @@ textarea:focus-visible {
466
468
 
467
469
  .post-detail-dialog {
468
470
  display: block;
469
- width: min(70rem, calc(100vw - 2rem));
470
- max-width: 70rem;
471
+ width: min(64rem, calc(100vw - 2rem));
472
+ max-width: 64rem;
471
473
  max-height: calc(100svh - 2rem);
472
474
  overflow-y: auto;
473
475
  padding: 0;
@@ -483,32 +485,8 @@ textarea:focus-visible {
483
485
  min-height: 0;
484
486
  }
485
487
 
486
- .post-full-page-link {
487
- display: flex;
488
- min-height: 4.5rem;
489
- padding: 0 4.25rem 0 1.5rem;
490
- align-items: center;
491
- justify-content: flex-end;
492
- border-bottom: 1px solid var(--portal-rule);
493
- color: var(--muted-foreground);
494
- font-size: 0.8rem;
495
- font-weight: 600;
496
- text-decoration-color: transparent;
497
- text-underline-offset: 0.25rem;
498
- transition:
499
- color 160ms ease,
500
- text-decoration-color 160ms ease;
501
- }
502
-
503
- .post-full-page-link:hover {
504
- color: var(--portal-ink);
505
- text-decoration-color: currentColor;
506
- }
507
-
508
- .post-full-page-link svg {
509
- width: 0.9rem;
510
- height: 0.9rem;
511
- margin-left: 0.5rem;
488
+ .post-detail-dialog .post-detail-sidebar {
489
+ padding-top: 4rem;
512
490
  }
513
491
 
514
492
  .post-detail-drawer .overlay-post-detail {
@@ -534,9 +512,16 @@ textarea:focus-visible {
534
512
  }
535
513
 
536
514
  .portal-shell {
515
+ display: flex;
516
+ flex-direction: column;
537
517
  min-height: 100svh;
538
518
  }
539
519
 
520
+ #main-content {
521
+ flex: 1;
522
+ min-width: 0;
523
+ }
524
+
540
525
  .portal-header {
541
526
  display: flex;
542
527
  align-items: center;
@@ -624,7 +609,7 @@ textarea:focus-visible {
624
609
 
625
610
  .feedback-intro h1 {
626
611
  margin: 0;
627
- font-size: clamp(2rem, 4vw, 3.4rem);
612
+ font-size: var(--text-2xl);
628
613
  font-weight: 650;
629
614
  letter-spacing: -0.055em;
630
615
  line-height: 1;
@@ -638,331 +623,82 @@ textarea:focus-visible {
638
623
  line-height: 1.55;
639
624
  }
640
625
 
641
- .changelog-page {
642
- width: min(calc(100% - 2rem), 90rem);
643
- min-height: calc(100svh - 5rem);
644
- margin: 0 auto;
645
- padding: clamp(3rem, 7vw, 5rem) 0 6rem;
646
- animation: page-in 480ms ease-out both;
647
- }
648
-
649
- .changelog-heading {
650
- display: flex;
651
- align-items: flex-start;
652
- justify-content: space-between;
653
- gap: 2rem;
654
- }
655
-
656
- .changelog-heading h1 {
657
- margin: 0;
658
- font-size: clamp(1.75rem, 3vw, 2.25rem);
659
- font-weight: 650;
660
- letter-spacing: -0.04em;
661
- line-height: 1;
662
- }
663
-
664
- .changelog-heading p {
665
- margin: 0.75rem 0 0;
666
- color: var(--muted-foreground);
667
- font-size: 0.95rem;
668
- }
669
-
670
- .changelog-toolbar {
671
- display: flex;
672
- align-items: center;
673
- justify-content: space-between;
674
- gap: 1rem;
675
- margin: 2.5rem 0 1rem;
676
- }
677
-
678
- .changelog-filters {
679
- display: grid;
680
- grid-template-columns: repeat(4, minmax(0, 1fr));
681
- width: min(100%, 28rem);
682
- }
683
-
684
- .changelog-filters button {
685
- height: 2.5rem;
686
- padding-inline: 1rem;
687
- color: var(--muted-foreground);
688
- font-size: 0.8rem;
689
- }
690
-
691
- .changelog-filters button[aria-pressed="true"] {
692
- background: var(--muted);
693
- color: var(--foreground);
694
- }
695
-
696
626
  .changelog-timeline {
697
- position: relative;
698
627
  display: grid;
699
- gap: 0.75rem;
700
- margin: 0;
628
+ gap: 2.5rem;
629
+ max-width: 64rem;
630
+ margin: 2.5rem auto 0;
701
631
  padding: 0;
702
632
  list-style: none;
703
633
  }
704
634
 
705
- .changelog-timeline::before {
706
- position: absolute;
707
- top: 1.5rem;
708
- bottom: 4.5rem;
709
- left: 10.875rem;
710
- width: 1px;
711
- background: var(--border);
712
- content: "";
713
- }
714
-
715
635
  .changelog-timeline-entry {
716
636
  position: relative;
717
637
  display: grid;
718
- grid-template-columns: 9.75rem 1.5rem minmax(0, 1fr);
638
+ grid-template-columns: 8rem minmax(0, 1fr);
639
+ gap: 2rem;
719
640
  align-items: start;
720
641
  }
721
642
 
722
643
  .changelog-timeline-entry > time {
723
- padding-top: 1.1rem;
644
+ padding-top: 0.2rem;
724
645
  color: var(--muted-foreground);
725
- font-size: 0.8rem;
646
+ font-size: var(--text-xs);
726
647
  font-variant-numeric: tabular-nums;
727
648
  }
728
649
 
729
650
  .changelog-timeline-marker {
651
+ position: absolute;
730
652
  z-index: 1;
731
- width: 0.45rem;
732
- height: 0.45rem;
733
- margin: 1.35rem auto 0;
734
- border: 2px solid var(--background);
653
+ top: 0.45rem;
654
+ left: 10rem;
655
+ width: 0.4rem;
656
+ height: 0.4rem;
657
+ transform: translateX(-50%);
735
658
  border-radius: 50%;
736
- background: color-mix(
737
- in srgb,
738
- var(--muted-foreground) 55%,
739
- var(--background)
740
- );
741
- box-sizing: content-box;
659
+ background: var(--muted-foreground);
660
+ box-shadow: 0 0 0 4px var(--background);
742
661
  }
743
662
 
744
663
  .changelog-timeline-entry > article {
745
664
  min-width: 0;
665
+ padding: 0 0 2.5rem 2rem;
666
+ border-left: 1px solid var(--border);
667
+ border-bottom: 1px solid var(--border);
746
668
  scroll-margin-top: 6rem;
747
- border: 1px solid var(--border);
748
- background: color-mix(in srgb, var(--card) 36%, transparent);
749
- transition:
750
- border-color 180ms ease,
751
- background-color 180ms ease;
752
669
  }
753
670
 
754
- .changelog-timeline-entry > article:hover,
755
671
  .changelog-timeline-entry > article:target {
756
- border-color: color-mix(in srgb, var(--foreground) 28%, var(--border));
757
- background: color-mix(in srgb, var(--card) 72%, transparent);
758
- }
759
-
760
- .changelog-timeline-entry > article:target {
761
- outline: 1px solid color-mix(in srgb, var(--ring) 65%, transparent);
762
- outline-offset: 3px;
763
- }
764
-
765
- .changelog-entry-layout {
766
- padding: 1rem 1.5rem;
767
- }
768
-
769
- .changelog-entry-layout.has-image {
770
- display: grid;
771
- grid-template-columns: minmax(17rem, 1fr) minmax(20rem, 0.8fr);
772
- gap: clamp(1.5rem, 4vw, 4rem);
773
- align-items: center;
774
- min-height: 16rem;
775
- }
776
-
777
- .changelog-entry-copy {
778
- min-width: 0;
779
- }
780
-
781
- .changelog-labels {
782
- display: flex;
783
- flex-wrap: wrap;
784
- gap: 0.4rem;
785
- margin-bottom: 0.7rem;
786
- }
787
-
788
- .changelog-label {
789
- border-color: color-mix(in srgb, var(--foreground) 12%, transparent);
790
- background: color-mix(in srgb, var(--muted) 72%, transparent);
791
- color: var(--muted-foreground);
792
- }
793
-
794
- .changelog-label > span {
795
- width: 0.45rem;
796
- height: 0.45rem;
797
- border-radius: 50%;
798
- background: currentColor;
799
- }
800
-
801
- .changelog-label.is-new {
802
- background: color-mix(in srgb, var(--changelog-new) 12%, transparent);
803
- color: var(--changelog-new);
804
- }
805
-
806
- .changelog-label.is-improved {
807
- background: color-mix(in srgb, var(--changelog-improved) 12%, transparent);
808
- color: var(--changelog-improved);
809
- }
810
-
811
- .changelog-label.is-fixed {
812
- background: color-mix(in srgb, var(--destructive) 12%, transparent);
813
- color: var(--destructive);
814
- }
815
-
816
- .changelog-entry-title {
817
- display: flex;
818
- align-items: center;
819
- gap: 0.6rem;
820
- }
821
-
822
- .changelog-entry-title h2 {
823
- margin: 0;
824
- font-size: 1.1rem;
825
- font-weight: 650;
826
- letter-spacing: -0.025em;
827
- }
828
-
829
- .changelog-entry-title a {
830
- display: inline-grid;
831
- flex: none;
832
- width: 1.75rem;
833
- height: 1.75rem;
834
- place-items: center;
835
- color: var(--muted-foreground);
836
- opacity: 0.55;
837
- transition:
838
- color 160ms ease,
839
- opacity 160ms ease,
840
- transform 160ms ease;
841
- }
842
-
843
- .changelog-entry-title a:hover,
844
- .changelog-entry-title a:focus-visible {
845
- color: var(--foreground);
846
- opacity: 1;
847
- transform: translateY(-1px);
848
- }
849
-
850
- .changelog-entry-title svg {
851
- width: 0.9rem;
852
- height: 0.9rem;
853
- }
854
-
855
- .changelog-entry-summary {
856
- margin: 0.45rem 0 0;
857
- color: var(--muted-foreground);
858
- font-size: 0.9rem;
859
- line-height: 1.5;
672
+ outline: 1px solid var(--ring);
673
+ outline-offset: 0.75rem;
860
674
  }
861
675
 
862
676
  .changelog-entry-body {
863
- margin-top: 0.7rem;
677
+ display: grid;
678
+ gap: 1rem;
679
+ margin-top: 1rem;
864
680
  color: var(--muted-foreground);
865
- font-size: 0.86rem;
866
- line-height: 1.55;
681
+ font-size: var(--text-sm);
682
+ line-height: 1.75;
683
+ overflow-wrap: anywhere;
867
684
  }
868
685
 
869
- .changelog-entry-body p,
870
- .changelog-entry-body ul {
686
+ .changelog-entry-body p {
871
687
  margin: 0;
688
+ white-space: pre-line;
872
689
  }
873
690
 
874
- .changelog-entry-body ul {
875
- padding-left: 1.25rem;
876
- }
877
-
878
- .changelog-entry-layout img {
879
- display: block;
880
- width: 100%;
881
- border: 1px solid var(--border);
882
- background: var(--background);
883
- }
884
-
885
- .changelog-load-more {
886
- display: flex;
887
- justify-content: center;
888
- margin: 1rem 0 0 11.25rem;
889
- }
890
-
891
- @media (max-width: 800px) {
892
- .changelog-page {
893
- width: min(calc(100% - 2rem), 42rem);
894
- padding-top: 5rem;
895
- }
896
-
897
- .changelog-heading {
898
- align-items: stretch;
899
- flex-direction: column;
900
- }
901
-
902
- .changelog-heading button,
903
- .changelog-toolbar button {
904
- width: 100%;
905
- }
906
-
907
- .changelog-toolbar {
908
- display: grid;
909
- grid-template-columns: minmax(0, 1fr);
910
- margin-top: 1rem;
911
- }
912
-
913
- .changelog-filters {
914
- width: 100%;
915
- }
916
-
917
- .changelog-filters button {
918
- height: 2.75rem;
919
- min-width: 0;
920
- padding-inline: 0.45rem;
921
- font-size: 0.72rem;
922
- }
923
-
924
- .changelog-timeline::before {
925
- top: 3rem;
926
- bottom: 3rem;
927
- left: 0.35rem;
928
- }
929
-
691
+ @media (max-width: 640px) {
930
692
  .changelog-timeline-entry {
931
- grid-template-columns: 0.75rem minmax(0, 1fr);
932
- column-gap: 0.75rem;
933
- }
934
-
935
- .changelog-timeline-entry > time {
936
- grid-column: 2;
937
- padding: 0 0 0.55rem;
938
- }
939
-
940
- .changelog-timeline-marker {
941
- grid-column: 1;
942
- grid-row: 1 / span 2;
943
- margin-top: 0.25rem;
944
- }
945
-
946
- .changelog-timeline-entry > article {
947
- grid-column: 2;
948
- }
949
-
950
- .changelog-entry-layout,
951
- .changelog-entry-layout.has-image {
952
- display: grid;
953
693
  grid-template-columns: minmax(0, 1fr);
954
- gap: 1.25rem;
955
- min-height: 0;
956
- padding: 1.1rem;
694
+ gap: 0.75rem;
957
695
  }
958
-
959
- .changelog-load-more {
960
- margin-left: 1.5rem;
696
+ .changelog-timeline-entry > article {
697
+ padding-left: 0;
698
+ border-left: 0;
961
699
  }
962
-
963
- .changelog-load-more button {
964
- width: 100%;
965
- min-width: 0;
700
+ .changelog-timeline-marker {
701
+ display: none;
966
702
  }
967
703
  }
968
704
 
@@ -1041,76 +777,6 @@ textarea:focus-visible {
1041
777
  padding-top: 3rem;
1042
778
  }
1043
779
 
1044
- .feedback-feed-skeleton .animate-pulse,
1045
- .post-detail-skeleton .animate-pulse {
1046
- border-radius: 0;
1047
- }
1048
-
1049
- .feedback-skeleton-heading {
1050
- width: min(34rem, 80vw);
1051
- height: clamp(2.5rem, 7vw, 5.5rem);
1052
- }
1053
-
1054
- .feedback-skeleton-deck {
1055
- width: min(32rem, 70vw);
1056
- height: 1.25rem;
1057
- margin-top: 1.25rem;
1058
- }
1059
-
1060
- .feedback-skeleton-control {
1061
- width: 9rem;
1062
- height: 2.75rem;
1063
- }
1064
-
1065
- .feedback-skeleton-section-heading,
1066
- .feedback-skeleton-meta {
1067
- width: 8rem;
1068
- height: 0.75rem;
1069
- }
1070
-
1071
- .feedback-skeleton-row {
1072
- display: grid;
1073
- gap: 0.8rem;
1074
- padding: clamp(1.5rem, 3vw, 2.4rem) 0;
1075
- }
1076
-
1077
- .feedback-skeleton-title {
1078
- width: min(30rem, 70vw);
1079
- height: 2rem;
1080
- }
1081
-
1082
- .feedback-skeleton-copy {
1083
- width: min(42rem, 80vw);
1084
- height: 1rem;
1085
- }
1086
-
1087
- .post-detail-skeleton-back {
1088
- width: 8rem;
1089
- height: 1rem;
1090
- }
1091
-
1092
- .post-detail-skeleton-meta {
1093
- width: 12rem;
1094
- height: 0.8rem;
1095
- }
1096
-
1097
- .post-detail-skeleton-title {
1098
- width: min(44rem, 75vw);
1099
- height: clamp(3rem, 7vw, 6rem);
1100
- margin-top: 1.25rem;
1101
- }
1102
-
1103
- .post-detail-skeleton-copy {
1104
- width: min(52rem, 80vw);
1105
- height: 1rem;
1106
- margin-top: 2rem;
1107
- }
1108
-
1109
- .post-detail-skeleton-copy-short {
1110
- width: min(35rem, 60vw);
1111
- margin-top: 0.75rem;
1112
- }
1113
-
1114
780
  .creation-skeleton-eyebrow {
1115
781
  width: 7rem;
1116
782
  height: 0.75rem;
@@ -1275,7 +941,7 @@ textarea:focus-visible {
1275
941
  .roadmap-intro h1 {
1276
942
  max-width: 12ch;
1277
943
  margin: 0;
1278
- font-size: clamp(3rem, 7vw, 6.5rem);
944
+ font-size: var(--text-2xl);
1279
945
  font-weight: 650;
1280
946
  letter-spacing: -0.075em;
1281
947
  line-height: 0.94;
@@ -1468,7 +1134,7 @@ textarea:focus-visible {
1468
1134
  .feedback-detail h1 {
1469
1135
  max-width: 14ch;
1470
1136
  margin: 1.25rem 0 0;
1471
- font-size: clamp(3rem, 7vw, 6.5rem);
1137
+ font-size: var(--text-2xl);
1472
1138
  font-weight: 650;
1473
1139
  letter-spacing: -0.075em;
1474
1140
  line-height: 0.94;
@@ -1478,7 +1144,7 @@ textarea:focus-visible {
1478
1144
  max-width: 48rem;
1479
1145
  margin: clamp(2rem, 5vw, 4rem) 0 0;
1480
1146
  color: var(--muted-foreground);
1481
- font-size: clamp(1.15rem, 2vw, 1.5rem);
1147
+ font-size: var(--text-sm);
1482
1148
  line-height: 1.75;
1483
1149
  white-space: pre-wrap;
1484
1150
  }
@@ -1511,7 +1177,7 @@ textarea:focus-visible {
1511
1177
  }
1512
1178
 
1513
1179
  .public-post-detail {
1514
- width: min(90vw, 70rem);
1180
+ width: min(90vw, 64rem);
1515
1181
  padding: clamp(2rem, 5vw, 4rem) 0 5rem;
1516
1182
  }
1517
1183
 
@@ -1525,7 +1191,7 @@ textarea:focus-visible {
1525
1191
  .public-post-detail .post-detail-layout {
1526
1192
  display: grid;
1527
1193
  max-width: none;
1528
- grid-template-columns: minmax(0, 1fr) minmax(17rem, 0.42fr);
1194
+ grid-template-columns: minmax(0, 1fr) minmax(14rem, 0.38fr);
1529
1195
  margin-top: 1.5rem;
1530
1196
  border: 1px solid var(--portal-rule);
1531
1197
  background: color-mix(in srgb, var(--card) 55%, var(--background));
@@ -1539,7 +1205,7 @@ textarea:focus-visible {
1539
1205
  .post-detail-primary,
1540
1206
  .post-detail-sidebar {
1541
1207
  min-width: 0;
1542
- padding: clamp(1.5rem, 4vw, 2.5rem);
1208
+ padding: 1.5rem;
1543
1209
  }
1544
1210
 
1545
1211
  .post-detail-sidebar {
@@ -1578,19 +1244,24 @@ textarea:focus-visible {
1578
1244
  }
1579
1245
 
1580
1246
  .public-post-detail h1 {
1581
- max-width: 22ch;
1582
- margin: 1.5rem 0 0;
1583
- font-size: clamp(2rem, 4vw, 3rem);
1584
- font-weight: 650;
1585
- letter-spacing: -0.05em;
1586
- line-height: 1.05;
1247
+ max-width: none;
1248
+ margin: 1rem 0 0;
1249
+ font-size: var(--text-2xl);
1250
+ font-weight: 600;
1251
+ letter-spacing: -0.025em;
1252
+ line-height: 1.4;
1253
+ }
1254
+
1255
+ .public-post-detail[data-display="overlay"] h1 {
1256
+ font-size: var(--text-lg);
1257
+ line-height: 1.5;
1587
1258
  }
1588
1259
 
1589
1260
  .public-post-detail .feedback-detail-description {
1590
1261
  max-width: 45rem;
1591
1262
  margin: 0.75rem 0 0;
1592
1263
  color: var(--muted-foreground);
1593
- font-size: clamp(0.95rem, 1.4vw, 1.05rem);
1264
+ font-size: var(--text-sm);
1594
1265
  line-height: 1.65;
1595
1266
  }
1596
1267
 
@@ -1633,6 +1304,12 @@ textarea:focus-visible {
1633
1304
  border-top: 1px solid var(--portal-rule);
1634
1305
  }
1635
1306
 
1307
+ .post-detail-comments-tab {
1308
+ margin-top: 0;
1309
+ padding-top: 0;
1310
+ border-top: 0;
1311
+ }
1312
+
1636
1313
  .post-detail-comments > h2,
1637
1314
  .post-detail-sidebar > h2 {
1638
1315
  margin: 0;
@@ -1641,16 +1318,22 @@ textarea:focus-visible {
1641
1318
  letter-spacing: -0.02em;
1642
1319
  }
1643
1320
 
1644
- .post-detail-comments-empty {
1645
- min-height: 13rem;
1321
+ .post-detail-thread-list {
1322
+ max-height: 30rem;
1323
+ overflow-y: auto;
1324
+ overscroll-behavior: contain;
1325
+ scrollbar-gutter: stable;
1646
1326
  margin-top: 1.25rem;
1647
- border: 1px dashed var(--portal-rule);
1648
- background: color-mix(in srgb, var(--muted) 12%, transparent);
1327
+ border-top: 1px solid var(--portal-rule);
1649
1328
  }
1650
1329
 
1651
1330
  .comment-threads {
1652
- margin-top: 1.25rem;
1653
- border-block: 1px solid var(--portal-rule);
1331
+ padding-right: 0.5rem;
1332
+ }
1333
+
1334
+ .public-post-detail .comment-thread {
1335
+ max-width: none;
1336
+ margin-top: 0;
1654
1337
  }
1655
1338
 
1656
1339
  .comment-thread + .comment-thread {
@@ -1756,7 +1439,7 @@ textarea:focus-visible {
1756
1439
  }
1757
1440
 
1758
1441
  .comment-composer-input {
1759
- min-height: 7rem;
1442
+ min-height: 6rem;
1760
1443
  resize: vertical;
1761
1444
  border-color: color-mix(in srgb, var(--foreground) 28%, var(--portal-rule));
1762
1445
  background: var(--background);
@@ -1839,7 +1522,7 @@ textarea:focus-visible {
1839
1522
  .public-error h1 {
1840
1523
  max-width: 12ch;
1841
1524
  margin: 0;
1842
- font-size: clamp(3rem, 7vw, 6.5rem);
1525
+ font-size: var(--text-2xl);
1843
1526
  font-weight: 650;
1844
1527
  letter-spacing: -0.075em;
1845
1528
  line-height: 0.94;
@@ -1882,18 +1565,7 @@ textarea:focus-visible {
1882
1565
  }
1883
1566
 
1884
1567
  .portal-loading {
1885
- display: flex;
1886
- min-height: calc(100svh - 4.5rem);
1887
- align-items: center;
1888
- justify-content: center;
1889
- gap: 0.75rem;
1890
- color: var(--muted-foreground);
1891
- font-size: 0.85rem;
1892
- }
1893
-
1894
- .portal-loading svg {
1895
- width: 1.1rem;
1896
- animation: spin 900ms linear infinite;
1568
+ width: 100%;
1897
1569
  }
1898
1570
 
1899
1571
  @keyframes page-in {
@@ -2031,7 +1703,7 @@ textarea:focus-visible {
2031
1703
  }
2032
1704
 
2033
1705
  .feedback-detail h1 {
2034
- font-size: clamp(3rem, 15vw, 4.25rem);
1706
+ font-size: var(--text-2xl);
2035
1707
  }
2036
1708
 
2037
1709
  .feedback-detail-dates {
@@ -2040,7 +1712,7 @@ textarea:focus-visible {
2040
1712
  }
2041
1713
 
2042
1714
  .feedback-intro h1 {
2043
- font-size: clamp(2rem, 10vw, 3rem);
1715
+ font-size: var(--text-2xl);
2044
1716
  }
2045
1717
 
2046
1718
  .feedback-filters {
@@ -2085,7 +1757,7 @@ textarea:focus-visible {
2085
1757
  }
2086
1758
 
2087
1759
  .public-post-detail h1 {
2088
- font-size: clamp(1.85rem, 8vw, 2.5rem);
1760
+ font-size: var(--text-xl);
2089
1761
  }
2090
1762
 
2091
1763
  .post-detail-primary,
@@ -2101,10 +1773,6 @@ textarea:focus-visible {
2101
1773
  justify-content: flex-end;
2102
1774
  }
2103
1775
 
2104
- .post-detail-comments-empty {
2105
- min-height: 10rem;
2106
- }
2107
-
2108
1776
  .comment[data-reply="true"] {
2109
1777
  margin-left: 0.75rem;
2110
1778
  padding-left: 0.75rem;
@@ -2119,11 +1787,6 @@ textarea:focus-visible {
2119
1787
  .post-detail-details > div {
2120
1788
  grid-template-columns: minmax(5rem, 0.65fr) minmax(0, 1fr);
2121
1789
  }
2122
-
2123
- .post-full-page-link {
2124
- min-height: 3.75rem;
2125
- padding-right: 1.25rem;
2126
- }
2127
1790
  }
2128
1791
 
2129
1792
  @media (prefers-reduced-motion: reduce) {