create-feedbax 0.1.0 → 0.2.1

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 (251) hide show
  1. package/LICENSE +201 -21
  2. package/README.md +11 -1
  3. package/dist/cli.js +3283 -22
  4. package/dist/index.js +3394 -160
  5. package/package.json +40 -14
  6. package/template/.feedbax-template.sha256 +1 -0
  7. package/template/.gitignore.template +6 -0
  8. package/template/.npmignore.template +5 -0
  9. package/template/.prettierignore.template +4 -0
  10. package/template/AGENTS.md +13 -0
  11. package/template/CONNECTED.md +404 -0
  12. package/template/LICENSE +201 -0
  13. package/template/README.md +56 -5
  14. package/template/components.json +25 -0
  15. package/template/eslint.config.mjs +48 -0
  16. package/template/migrations/0001_connected.sql +6 -0
  17. package/template/migrations/0002_participation.sql +8 -0
  18. package/template/migrations/0003_images.sql +3 -0
  19. package/template/migrations/0004_followed_status.sql +9 -0
  20. package/template/package.json +74 -14
  21. package/template/public/feedbax-mark.svg +4 -0
  22. package/template/public/robots.txt +3 -0
  23. package/template/src/authorized-draft-post.test.tsx +212 -0
  24. package/template/src/authorized-draft-post.tsx +205 -0
  25. package/template/src/authorized-draft-query.ts +74 -0
  26. package/template/src/browser-post-state.test.ts +120 -0
  27. package/template/src/browser-post-state.ts +134 -0
  28. package/template/src/browser-vote-state.test.ts +14 -0
  29. package/template/src/browser-vote-state.ts +27 -0
  30. package/template/src/capability-authorization-error.ts +3 -0
  31. package/template/src/changelog-page.test.tsx +139 -0
  32. package/template/src/changelog-page.tsx +228 -0
  33. package/template/src/changelog-query.ts +13 -0
  34. package/template/src/changelog-runtime.ts +27 -0
  35. package/template/src/cloudflare-turnstile.ts +31 -0
  36. package/template/src/cloudflare-workers-test.ts +3 -0
  37. package/template/src/cloudflare-workers.d.ts +24 -0
  38. package/template/src/comment-creation.test.tsx +311 -0
  39. package/template/src/comment-profile.ts +5 -0
  40. package/template/src/comment-thread-page.ts +28 -0
  41. package/template/src/components/command-palette-context.tsx +71 -0
  42. package/template/src/components/command-palette.tsx +275 -0
  43. package/template/src/components/connected-identity-provider.tsx +108 -0
  44. package/template/src/components/create-post-trigger.tsx +44 -0
  45. package/template/src/components/device-profile-provider.tsx +324 -0
  46. package/template/src/components/follow-post-button.tsx +89 -0
  47. package/template/src/components/header.tsx +97 -0
  48. package/template/src/components/image-attachments.tsx +187 -0
  49. package/template/src/components/loader.tsx +53 -0
  50. package/template/src/components/notification-inbox.tsx +232 -0
  51. package/template/src/components/portal-footer.tsx +14 -0
  52. package/template/src/components/profile-menu.tsx +119 -0
  53. package/template/src/components/ui/components/alert-dialog.tsx +185 -0
  54. package/template/src/components/ui/components/attachment.tsx +207 -0
  55. package/template/src/components/ui/components/avatar.tsx +107 -0
  56. package/template/src/components/ui/components/badge.tsx +52 -0
  57. package/template/src/components/ui/components/bubble.tsx +128 -0
  58. package/template/src/components/ui/components/button-group.tsx +87 -0
  59. package/template/src/components/ui/components/button.tsx +56 -0
  60. package/template/src/components/ui/components/card.tsx +103 -0
  61. package/template/src/components/ui/components/checkbox.tsx +26 -0
  62. package/template/src/components/ui/components/command.tsx +195 -0
  63. package/template/src/components/ui/components/dialog.tsx +154 -0
  64. package/template/src/components/ui/components/drawer.tsx +229 -0
  65. package/template/src/components/ui/components/dropdown-menu.tsx +270 -0
  66. package/template/src/components/ui/components/empty.tsx +101 -0
  67. package/template/src/components/ui/components/field.tsx +236 -0
  68. package/template/src/components/ui/components/input-group.tsx +155 -0
  69. package/template/src/components/ui/components/input.tsx +20 -0
  70. package/template/src/components/ui/components/item.tsx +201 -0
  71. package/template/src/components/ui/components/kbd.tsx +26 -0
  72. package/template/src/components/ui/components/label.tsx +18 -0
  73. package/template/src/components/ui/components/marker.tsx +71 -0
  74. package/template/src/components/ui/components/message-scroller.tsx +128 -0
  75. package/template/src/components/ui/components/message.tsx +92 -0
  76. package/template/src/components/ui/components/native-select.tsx +65 -0
  77. package/template/src/components/ui/components/popover.tsx +88 -0
  78. package/template/src/components/ui/components/portal-primitives.test.tsx +85 -0
  79. package/template/src/components/ui/components/radio-group.tsx +36 -0
  80. package/template/src/components/ui/components/scroll-area.tsx +51 -0
  81. package/template/src/components/ui/components/secondary-form-actions.test.tsx +23 -0
  82. package/template/src/components/ui/components/select.tsx +199 -0
  83. package/template/src/components/ui/components/separator.tsx +23 -0
  84. package/template/src/components/ui/components/sheet.tsx +135 -0
  85. package/template/src/components/ui/components/skeleton.tsx +13 -0
  86. package/template/src/components/ui/components/sonner.tsx +43 -0
  87. package/template/src/components/ui/components/spinner.tsx +16 -0
  88. package/template/src/components/ui/components/switch.tsx +29 -0
  89. package/template/src/components/ui/components/tabs.tsx +80 -0
  90. package/template/src/components/ui/components/textarea.tsx +18 -0
  91. package/template/src/components/ui/components/tooltip.tsx +64 -0
  92. package/template/src/components/ui/hooks/.gitkeep +0 -0
  93. package/template/src/components/ui/lib/utils.ts +6 -0
  94. package/template/src/components/ui/styles/globals.css +151 -0
  95. package/template/src/connected-identity.test.ts +144 -0
  96. package/template/src/connected-identity.ts +122 -0
  97. package/template/src/connected-participation.test.tsx +67 -0
  98. package/template/src/connected-runtime.test.ts +241 -0
  99. package/template/src/connected-runtime.ts +176 -0
  100. package/template/src/connected-social.test.tsx +158 -0
  101. package/template/src/create-post-overlay.tsx +82 -0
  102. package/template/src/draft-post-list.tsx +39 -0
  103. package/template/src/feedback-cache-invalidation.test.ts +185 -0
  104. package/template/src/feedback-cache-invalidation.ts +98 -0
  105. package/template/src/feedback-runtime.ts +105 -0
  106. package/template/src/feedbax/changelog/index.test.ts +156 -0
  107. package/template/src/feedbax/changelog/index.ts +206 -0
  108. package/template/src/feedbax/changelog/notion-changelog.test.ts +395 -0
  109. package/template/src/feedbax/changelog/notion-changelog.ts +400 -0
  110. package/template/src/feedbax/config/index.test.ts +139 -0
  111. package/template/src/feedbax/config/index.ts +364 -0
  112. package/template/src/feedbax/feedback/connected-feedback.ts +206 -0
  113. package/template/src/feedbax/feedback/connected.test.ts +272 -0
  114. package/template/src/feedbax/feedback/connected.ts +215 -0
  115. package/template/src/feedbax/feedback/email-delivery.test.ts +65 -0
  116. package/template/src/feedbax/feedback/email-delivery.ts +66 -0
  117. package/template/src/feedbax/feedback/feedback-storage.ts +43 -0
  118. package/template/src/feedbax/feedback/identity-handoff.test.ts +81 -0
  119. package/template/src/feedbax/feedback/identity-handoff.ts +119 -0
  120. package/template/src/feedbax/feedback/image-feedback.ts +101 -0
  121. package/template/src/feedbax/feedback/images.test.ts +223 -0
  122. package/template/src/feedbax/feedback/images.ts +324 -0
  123. package/template/src/feedbax/feedback/index.test.ts +900 -0
  124. package/template/src/feedbax/feedback/index.ts +996 -0
  125. package/template/src/feedbax/feedback/notion-comments.test.ts +171 -0
  126. package/template/src/feedbax/feedback/notion-comments.ts +231 -0
  127. package/template/src/feedbax/feedback/notion-data-source.test.ts +364 -0
  128. package/template/src/feedbax/feedback/notion-data-source.ts +458 -0
  129. package/template/src/feedbax/feedback/notion-feedback.test.ts +998 -0
  130. package/template/src/feedbax/feedback/notion-feedback.ts +651 -0
  131. package/template/src/feedbax/feedback/notion-image-review.ts +55 -0
  132. package/template/src/feedbax/feedback/notion-request.ts +74 -0
  133. package/template/src/feedbax/feedback/participation.test.ts +653 -0
  134. package/template/src/feedbax/feedback/participation.ts +502 -0
  135. package/template/src/feedbax.test-fixture.ts +64 -0
  136. package/template/src/feedbax.ts +69 -0
  137. package/template/src/images-runtime.test.ts +133 -0
  138. package/template/src/images-runtime.ts +125 -0
  139. package/template/src/index.css +1795 -0
  140. package/template/src/lazy-create-post-overlay.tsx +6 -0
  141. package/template/src/lazy-post-detail-overlay.tsx +21 -0
  142. package/template/src/masked-post-link.tsx +27 -0
  143. package/template/src/overlay-post-detail.test.tsx +181 -0
  144. package/template/src/overlay-post-detail.tsx +43 -0
  145. package/template/src/participation-client.ts +63 -0
  146. package/template/src/participation-runtime.test.ts +35 -0
  147. package/template/src/participation-runtime.ts +255 -0
  148. package/template/src/portal-comments.test.ts +375 -0
  149. package/template/src/portal-comments.ts +403 -0
  150. package/template/src/portal-features.test.tsx +150 -0
  151. package/template/src/portal-feedback-form.tsx +530 -0
  152. package/template/src/portal-feedback-runtime.test.ts +32 -0
  153. package/template/src/portal-feedback-runtime.ts +58 -0
  154. package/template/src/portal-feedback-server-function.ts +96 -0
  155. package/template/src/portal-feedback-submission.test.ts +307 -0
  156. package/template/src/portal-feedback-submission.ts +224 -0
  157. package/template/src/portal-head.ts +58 -0
  158. package/template/src/portal-server-entry.ts +68 -0
  159. package/template/src/portal-voting.test.ts +106 -0
  160. package/template/src/portal-voting.ts +149 -0
  161. package/template/src/post-badges.tsx +27 -0
  162. package/template/src/post-creation-flow.test.tsx +230 -0
  163. package/template/src/post-creation-flow.tsx +88 -0
  164. package/template/src/post-detail-content.test.tsx +233 -0
  165. package/template/src/post-detail-content.tsx +162 -0
  166. package/template/src/post-detail-overlay.test.tsx +114 -0
  167. package/template/src/post-detail-overlay.tsx +67 -0
  168. package/template/src/post-detail-query.ts +34 -0
  169. package/template/src/post-feed-controls.test.tsx +239 -0
  170. package/template/src/post-feed-controls.tsx +298 -0
  171. package/template/src/post-presentation.ts +37 -0
  172. package/template/src/post-queries.test.ts +158 -0
  173. package/template/src/post-queries.ts +26 -0
  174. package/template/src/post-results.tsx +165 -0
  175. package/template/src/public-cache-policy.test.ts +148 -0
  176. package/template/src/public-cache-policy.ts +119 -0
  177. package/template/src/public-cache-tags.ts +7 -0
  178. package/template/src/public-changelog-page.ts +15 -0
  179. package/template/src/public-changelog-server-function.ts +27 -0
  180. package/template/src/public-date.ts +11 -0
  181. package/template/src/public-failure-state.test.tsx +69 -0
  182. package/template/src/public-feedback-index.tsx +94 -0
  183. package/template/src/public-feedback-page.test.tsx +355 -0
  184. package/template/src/public-feedback-page.ts +86 -0
  185. package/template/src/public-feedback-server-function.ts +22 -0
  186. package/template/src/public-portal-error.tsx +27 -0
  187. package/template/src/public-post-detail-skeleton.tsx +54 -0
  188. package/template/src/public-post-detail.tsx +772 -0
  189. package/template/src/public-post-page.test.tsx +173 -0
  190. package/template/src/public-post-page.ts +15 -0
  191. package/template/src/public-post-route.test.tsx +250 -0
  192. package/template/src/public-post-route.tsx +158 -0
  193. package/template/src/public-post-server-function.ts +48 -0
  194. package/template/src/public-post-unavailable.tsx +10 -0
  195. package/template/src/public-roadmap-page.test.tsx +139 -0
  196. package/template/src/public-roadmap-page.ts +24 -0
  197. package/template/src/public-roadmap-route.test.tsx +254 -0
  198. package/template/src/public-roadmap-route.tsx +50 -0
  199. package/template/src/public-roadmap-server-function.ts +44 -0
  200. package/template/src/public-roadmap-view.tsx +411 -0
  201. package/template/src/public-shell.test.tsx +544 -0
  202. package/template/src/roadmap-query.ts +21 -0
  203. package/template/src/root-branding.test.ts +53 -0
  204. package/template/src/routeTree.gen.ts +177 -0
  205. package/template/src/routed-post-creation-form.tsx +28 -0
  206. package/template/src/router.tsx +27 -0
  207. package/template/src/routes/__root.tsx +114 -0
  208. package/template/src/routes/changelog.tsx +39 -0
  209. package/template/src/routes/email-preferences.tsx +77 -0
  210. package/template/src/routes/index.tsx +61 -0
  211. package/template/src/routes/p.$slug.tsx +16 -0
  212. package/template/src/routes/roadmap.tsx +11 -0
  213. package/template/src/routes/submit.tsx +28 -0
  214. package/template/src/safe-public-failure.ts +47 -0
  215. package/template/src/server.ts +151 -0
  216. package/template/src/similar-posts.tsx +45 -0
  217. package/template/src/submit-route.test.tsx +134 -0
  218. package/template/src/trusted-feedback-handler.test.ts +425 -0
  219. package/template/src/trusted-feedback-handler.ts +181 -0
  220. package/template/src/trusted-feedback-runtime.ts +17 -0
  221. package/template/src/turnstile-configuration.test.ts +37 -0
  222. package/template/src/turnstile-configuration.ts +19 -0
  223. package/template/src/use-media-query.ts +17 -0
  224. package/template/src/vote-toggle.test.tsx +171 -0
  225. package/template/src/vote-toggle.tsx +244 -0
  226. package/template/tsconfig.json +45 -0
  227. package/template/vite.config.ts +20 -0
  228. package/template/vitest.config.ts +4 -0
  229. package/template/vitest.setup.ts +3 -0
  230. package/template/wrangler.jsonc +35 -0
  231. package/dist/cli.d.ts +0 -3
  232. package/dist/cli.d.ts.map +0 -1
  233. package/dist/cli.js.map +0 -1
  234. package/dist/index.d.ts +0 -21
  235. package/dist/index.d.ts.map +0 -1
  236. package/dist/index.js.map +0 -1
  237. package/template/.env.example +0 -4
  238. package/template/apps/portal/components.json +0 -20
  239. package/template/apps/portal/package.json +0 -31
  240. package/template/apps/portal/src/lib/utils.ts +0 -6
  241. package/template/apps/portal/src/routeTree.gen.ts +0 -59
  242. package/template/apps/portal/src/router.tsx +0 -10
  243. package/template/apps/portal/src/routes/__root.tsx +0 -31
  244. package/template/apps/portal/src/routes/index.tsx +0 -35
  245. package/template/apps/portal/src/styles.css +0 -91
  246. package/template/apps/portal/tsconfig.json +0 -15
  247. package/template/apps/portal/vite.config.ts +0 -13
  248. package/template/feedbax.config.ts +0 -13
  249. package/template/feedbax.jsonc +0 -11
  250. package/template/pnpm-workspace.yaml +0 -3
  251. package/template/turbo.json +0 -8
@@ -0,0 +1,1795 @@
1
+ @import "./components/ui/styles/globals.css";
2
+
3
+ :root {
4
+ --portal-ink: var(--foreground);
5
+ --portal-paper: var(--background);
6
+ --portal-accent: var(--primary);
7
+ --portal-rule: var(--border);
8
+ }
9
+ .sr-only {
10
+ position: absolute;
11
+ width: 1px;
12
+ height: 1px;
13
+ padding: 0;
14
+ margin: -1px;
15
+ overflow: hidden;
16
+ clip: rect(0, 0, 0, 0);
17
+ white-space: nowrap;
18
+ border: 0;
19
+ }
20
+ .post-controls {
21
+ display: flex;
22
+ align-items: end;
23
+ gap: 0.75rem;
24
+ margin: 2.5rem 0 0;
25
+ padding-block: 1rem;
26
+ border-block: 1px solid var(--portal-rule);
27
+ }
28
+ .post-controls label {
29
+ display: grid;
30
+ gap: 0.35rem;
31
+ font-size: 0.75rem;
32
+ }
33
+ .post-search {
34
+ position: relative;
35
+ flex: 1;
36
+ }
37
+ .post-search svg {
38
+ position: absolute;
39
+ left: 0.75rem;
40
+ bottom: 0.75rem;
41
+ width: 1rem;
42
+ }
43
+ .post-search input {
44
+ width: 100%;
45
+ min-height: 2.75rem;
46
+ padding-left: 2.25rem;
47
+ }
48
+ .post-controls select,
49
+ .post-controls button,
50
+ .post-filters summary {
51
+ min-height: 2.75rem;
52
+ padding: 0.65rem 0.85rem;
53
+ border: 1px solid var(--portal-rule);
54
+ background: var(--portal-paper);
55
+ color: var(--portal-ink);
56
+ }
57
+ .post-filters {
58
+ position: relative;
59
+ }
60
+ .post-filters > div,
61
+ .post-filters fieldset {
62
+ display: flex;
63
+ gap: 0.65rem;
64
+ }
65
+ .post-filters[open] {
66
+ padding: 1rem;
67
+ border: 1px solid var(--portal-rule);
68
+ }
69
+ .profile-control {
70
+ position: relative;
71
+ }
72
+ .profile-control summary {
73
+ cursor: pointer;
74
+ }
75
+ .profile-panel {
76
+ position: absolute;
77
+ z-index: 20;
78
+ right: 0;
79
+ width: min(22rem, 85vw);
80
+ padding: 1rem;
81
+ border: 1px solid var(--portal-rule);
82
+ background: var(--portal-paper);
83
+ }
84
+ .profile-panel form,
85
+ .profile-panel label {
86
+ display: grid;
87
+ gap: 0.5rem;
88
+ }
89
+ .roadmap-groups {
90
+ overflow-x: auto;
91
+ scroll-snap-type: x mandatory;
92
+ }
93
+ .roadmap-group {
94
+ scroll-snap-align: start;
95
+ }
96
+ .draft-post-link {
97
+ border-style: dashed;
98
+ background: color-mix(in srgb, var(--portal-ink) 5%, var(--portal-paper));
99
+ }
100
+ .draft-post-link strong {
101
+ border: 1px solid currentColor;
102
+ padding: 0.15rem 0.4rem;
103
+ font-size: 0.68rem;
104
+ text-transform: uppercase;
105
+ }
106
+ @media (max-width: 720px) {
107
+ .portal-header nav {
108
+ gap: 0.65rem;
109
+ overflow-x: auto;
110
+ }
111
+ .portal-header nav a {
112
+ font-size: 0.65rem;
113
+ }
114
+ .post-controls {
115
+ align-items: stretch;
116
+ flex-direction: column;
117
+ }
118
+ .post-filters fieldset {
119
+ flex-direction: column;
120
+ }
121
+ }
122
+ @media (prefers-reduced-motion: reduce) {
123
+ *,
124
+ *::before,
125
+ *::after {
126
+ scroll-behavior: auto !important;
127
+ animation-duration: 0.01ms !important;
128
+ animation-iteration-count: 1 !important;
129
+ transition-duration: 0.01ms !important;
130
+ }
131
+ }
132
+ .mobile-menu {
133
+ display: none;
134
+ border: 0;
135
+ background: transparent;
136
+ color: inherit;
137
+ }
138
+ .portal-header .mobile-nav {
139
+ display: grid;
140
+ align-items: stretch;
141
+ gap: 1rem;
142
+ overflow: visible;
143
+ padding: 1.5rem;
144
+ }
145
+ @media (max-width: 720px) {
146
+ .portal-header .desktop-nav {
147
+ display: none;
148
+ }
149
+ .mobile-menu {
150
+ display: inline-grid;
151
+ place-items: center;
152
+ }
153
+ }
154
+
155
+ body {
156
+ margin: 0;
157
+ background: var(--portal-paper);
158
+ color: var(--portal-ink);
159
+ }
160
+
161
+ a,
162
+ button,
163
+ select,
164
+ input,
165
+ textarea {
166
+ -webkit-tap-highlight-color: transparent;
167
+ }
168
+
169
+ a:focus-visible,
170
+ button:focus-visible,
171
+ select:focus-visible,
172
+ input:focus-visible,
173
+ textarea:focus-visible {
174
+ outline: 3px solid color-mix(in srgb, var(--portal-accent) 65%, transparent);
175
+ outline-offset: 3px;
176
+ }
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
+
186
+ .vote-toggle-button {
187
+ display: inline-flex;
188
+ min-height: 2.5rem;
189
+ align-items: center;
190
+ justify-content: center;
191
+ gap: 0.35rem;
192
+ padding: 0.5rem 0.75rem;
193
+ border: 1px solid var(--portal-rule);
194
+ background: var(--card);
195
+ color: var(--portal-ink);
196
+ font: inherit;
197
+ font-weight: 650;
198
+ cursor: pointer;
199
+ transition:
200
+ border-color 160ms ease,
201
+ background-color 160ms ease,
202
+ color 160ms ease,
203
+ transform 160ms ease;
204
+ }
205
+
206
+ .vote-toggle-button:hover:not(:disabled),
207
+ .vote-toggle-button:focus-visible {
208
+ border-color: color-mix(
209
+ in srgb,
210
+ var(--portal-accent) 55%,
211
+ var(--portal-rule)
212
+ );
213
+ background: color-mix(in srgb, var(--portal-accent) 10%, var(--card));
214
+ color: var(--portal-accent);
215
+ transform: translateY(-1px);
216
+ }
217
+
218
+ .vote-toggle-button[aria-pressed="true"] {
219
+ border-color: color-mix(
220
+ in srgb,
221
+ var(--portal-accent) 50%,
222
+ var(--portal-rule)
223
+ );
224
+ background: color-mix(in srgb, var(--portal-accent) 14%, var(--card));
225
+ color: var(--portal-accent);
226
+ }
227
+
228
+ .vote-toggle-button:disabled {
229
+ cursor: wait;
230
+ opacity: 0.65;
231
+ }
232
+
233
+ .vote-toggle-button svg {
234
+ width: 1rem;
235
+ height: 1rem;
236
+ stroke-width: 2.5;
237
+ }
238
+
239
+ .feedback-submit {
240
+ display: grid;
241
+ grid-template-columns: minmax(0, 0.8fr) minmax(20rem, 1.2fr);
242
+ gap: clamp(2rem, 7vw, 7rem);
243
+ margin-top: clamp(3.5rem, 8vw, 7rem);
244
+ padding: clamp(2rem, 5vw, 4rem);
245
+ border: 1px solid var(--portal-rule);
246
+ background: var(--card);
247
+ }
248
+
249
+ .create-post-dialog {
250
+ max-height: min(90dvh, 52rem);
251
+ width: min(62rem, calc(100vw - 2rem));
252
+ max-width: min(62rem, calc(100vw - 2rem));
253
+ overflow-y: auto;
254
+ padding: 0;
255
+ }
256
+
257
+ .create-post-drawer {
258
+ max-height: calc(100svh - 1rem);
259
+ }
260
+
261
+ .create-post-drawer .feedback-submit {
262
+ overflow-y: auto;
263
+ overscroll-behavior: contain;
264
+ }
265
+
266
+ .feedback-submit[data-display="overlay"] {
267
+ grid-template-columns: minmax(0, 0.7fr) minmax(20rem, 1.3fr);
268
+ gap: 2rem;
269
+ margin: 0;
270
+ padding: clamp(1.5rem, 4vw, 3rem);
271
+ border: 0;
272
+ background: transparent;
273
+ }
274
+
275
+ .feedback-submit-copy h2 {
276
+ margin: 0;
277
+ font-size: var(--text-xl);
278
+ font-weight: 600;
279
+ letter-spacing: -0.025em;
280
+ line-height: 1.4;
281
+ }
282
+
283
+ .feedback-submit-copy > p:last-child {
284
+ margin: 1.5rem 0 0;
285
+ color: var(--muted-foreground);
286
+ font-size: 0.88rem;
287
+ line-height: 1.65;
288
+ }
289
+
290
+ .feedback-submit-form,
291
+ .feedback-submit-field {
292
+ display: grid;
293
+ }
294
+
295
+ .feedback-submit-form {
296
+ gap: 1rem;
297
+ }
298
+
299
+ .feedback-submit-field {
300
+ gap: 0.5rem;
301
+ }
302
+
303
+ .feedback-submit-field > label {
304
+ color: var(--muted-foreground);
305
+ font-size: 0.68rem;
306
+ font-weight: 750;
307
+ letter-spacing: 0.08em;
308
+ text-transform: uppercase;
309
+ }
310
+
311
+ .feedback-character-count,
312
+ .feedback-field-error {
313
+ font-size: 0.72rem;
314
+ }
315
+
316
+ .feedback-character-count {
317
+ color: var(--muted-foreground);
318
+ text-align: right;
319
+ }
320
+
321
+ .feedback-field-error {
322
+ color: var(--destructive);
323
+ }
324
+
325
+ .feedback-submit-form input,
326
+ .feedback-submit-form textarea,
327
+ .feedback-submit-form select {
328
+ box-sizing: border-box;
329
+ width: 100%;
330
+ border: 1px solid var(--input);
331
+ border-radius: 0;
332
+ background: var(--portal-paper);
333
+ color: var(--portal-ink);
334
+ font: inherit;
335
+ }
336
+
337
+ .feedback-submit-form input,
338
+ .feedback-submit-form select {
339
+ min-height: 3rem;
340
+ padding: 0 0.85rem;
341
+ }
342
+
343
+ .feedback-submit-form textarea {
344
+ min-height: 9rem;
345
+ padding: 0.85rem;
346
+ resize: vertical;
347
+ }
348
+
349
+ .feedback-post-type-picker {
350
+ grid-template-columns: repeat(3, minmax(0, 1fr));
351
+ gap: 0.625rem;
352
+ }
353
+
354
+ .feedback-post-type-card {
355
+ position: relative;
356
+ display: grid;
357
+ box-sizing: border-box;
358
+ width: 100%;
359
+ min-height: 8rem;
360
+ grid-template-columns: 1fr auto;
361
+ grid-template-rows: auto 1fr;
362
+ gap: 1.25rem 0.75rem;
363
+ align-content: space-between;
364
+ padding: 1rem;
365
+ border: 1px solid var(--portal-rule);
366
+ background: var(--background);
367
+ color: var(--foreground);
368
+ cursor: pointer;
369
+ text-transform: none;
370
+ transition:
371
+ border-color 160ms ease,
372
+ background-color 160ms ease,
373
+ transform 160ms ease;
374
+ }
375
+
376
+ .feedback-post-type-card:hover {
377
+ border-color: color-mix(
378
+ in srgb,
379
+ var(--portal-accent) 55%,
380
+ var(--portal-rule)
381
+ );
382
+ background: color-mix(in srgb, var(--portal-accent) 5%, var(--background));
383
+ transform: translateY(-2px);
384
+ }
385
+
386
+ .feedback-post-type-card:has([data-checked]) {
387
+ border-color: var(--portal-accent);
388
+ background: color-mix(in srgb, var(--portal-accent) 10%, var(--background));
389
+ }
390
+
391
+ .feedback-post-type-card:has(:focus-visible) {
392
+ border-color: var(--ring);
393
+ outline: 2px solid color-mix(in srgb, var(--ring) 55%, transparent);
394
+ outline-offset: 2px;
395
+ }
396
+
397
+ .feedback-post-type-card > [data-slot="radio-group-item"] {
398
+ grid-column: 2;
399
+ grid-row: 1;
400
+ }
401
+
402
+ .feedback-post-type-card > svg {
403
+ width: 1.35rem;
404
+ height: 1.35rem;
405
+ grid-column: 1;
406
+ grid-row: 1;
407
+ color: var(--portal-accent);
408
+ stroke-width: 1.75;
409
+ }
410
+
411
+ .feedback-post-type-copy {
412
+ display: grid;
413
+ grid-column: 1 / -1;
414
+ grid-row: 2;
415
+ gap: 0.3rem;
416
+ align-self: end;
417
+ }
418
+
419
+ .feedback-post-type-copy strong {
420
+ font-size: 0.78rem;
421
+ line-height: 1.25;
422
+ }
423
+
424
+ .feedback-post-type-copy small {
425
+ color: var(--muted-foreground);
426
+ font-size: 0.68rem;
427
+ font-weight: 500;
428
+ line-height: 1.4;
429
+ }
430
+
431
+ .feedback-submit-actions {
432
+ display: flex;
433
+ flex-wrap: wrap;
434
+ gap: 0.75rem;
435
+ }
436
+
437
+ .feedback-submit-actions button {
438
+ min-height: 3rem;
439
+ padding: 0 1.25rem;
440
+ border-radius: 0;
441
+ cursor: pointer;
442
+ font: inherit;
443
+ font-size: 0.82rem;
444
+ font-weight: 750;
445
+ }
446
+
447
+ .feedback-submit-actions button:disabled {
448
+ cursor: wait;
449
+ opacity: 0.6;
450
+ }
451
+
452
+ .feedback-submit-actions .feedback-withdraw {
453
+ background: transparent;
454
+ color: var(--destructive);
455
+ }
456
+
457
+ .feedback-submit-actions .feedback-cancel {
458
+ background: transparent;
459
+ color: var(--portal-ink);
460
+ }
461
+
462
+ .feedback-submit-message {
463
+ margin: 0;
464
+ color: var(--portal-accent);
465
+ font-size: 0.85rem;
466
+ font-weight: 650;
467
+ }
468
+
469
+ .post-detail-dialog {
470
+ display: block;
471
+ width: min(64rem, calc(100vw - 2rem));
472
+ max-width: 64rem;
473
+ max-height: calc(100svh - 2rem);
474
+ overflow-y: auto;
475
+ padding: 0;
476
+ }
477
+
478
+ .post-detail-drawer {
479
+ max-height: calc(100svh - 0.5rem);
480
+ overflow: hidden;
481
+ }
482
+
483
+ .overlay-post-detail {
484
+ display: grid;
485
+ min-height: 0;
486
+ }
487
+
488
+ .post-detail-dialog .post-detail-sidebar {
489
+ padding-top: 4rem;
490
+ }
491
+
492
+ .post-detail-drawer .overlay-post-detail {
493
+ overflow-y: auto;
494
+ }
495
+
496
+ .draft-detail-actions {
497
+ display: flex;
498
+ justify-content: flex-end;
499
+ gap: 0.5rem;
500
+ }
501
+
502
+ .draft-detail-actions button {
503
+ min-height: 2.5rem;
504
+ padding: 0 0.85rem;
505
+ border: 1px solid var(--portal-rule);
506
+ background: transparent;
507
+ color: var(--portal-ink);
508
+ cursor: pointer;
509
+ font: inherit;
510
+ font-size: 0.8rem;
511
+ font-weight: 700;
512
+ }
513
+
514
+ .portal-shell {
515
+ display: flex;
516
+ flex-direction: column;
517
+ min-height: 100svh;
518
+ }
519
+
520
+ #main-content {
521
+ flex: 1;
522
+ min-width: 0;
523
+ }
524
+
525
+ .portal-header {
526
+ display: flex;
527
+ align-items: center;
528
+ justify-content: space-between;
529
+ min-height: 4.5rem;
530
+ padding: 0 5vw;
531
+ border-bottom: 1px solid var(--portal-rule);
532
+ background: color-mix(in srgb, var(--portal-paper) 92%, transparent);
533
+ backdrop-filter: blur(16px);
534
+ }
535
+
536
+ .portal-brand {
537
+ display: inline-flex;
538
+ align-items: center;
539
+ gap: 0.7rem;
540
+ color: inherit;
541
+ font-size: 1rem;
542
+ font-weight: 750;
543
+ letter-spacing: -0.03em;
544
+ text-decoration: none;
545
+ }
546
+
547
+ .portal-brand span {
548
+ display: grid;
549
+ width: 2rem;
550
+ height: 2rem;
551
+ place-items: center;
552
+ background: var(--portal-accent);
553
+ color: var(--primary-foreground);
554
+ font-size: 0.85rem;
555
+ }
556
+
557
+ .portal-header nav {
558
+ display: flex;
559
+ align-items: center;
560
+ gap: 1.25rem;
561
+ }
562
+
563
+ .portal-header nav a {
564
+ padding-block: 0.35rem;
565
+ border-bottom: 2px solid transparent;
566
+ color: var(--muted-foreground);
567
+ font-size: 0.75rem;
568
+ font-weight: 700;
569
+ letter-spacing: 0.08em;
570
+ text-decoration: none;
571
+ text-transform: uppercase;
572
+ }
573
+
574
+ .portal-header nav a:hover {
575
+ color: var(--portal-ink);
576
+ }
577
+
578
+ .portal-header nav a[aria-current="page"] {
579
+ border-bottom-color: currentColor;
580
+ color: var(--portal-ink);
581
+ }
582
+
583
+ .portal-header nav a.create-post-link {
584
+ padding: 0.65rem 0.8rem;
585
+ border: 1px solid var(--portal-ink);
586
+ background: var(--portal-ink);
587
+ color: var(--portal-paper);
588
+ }
589
+
590
+ .feedback-index {
591
+ width: min(90vw, 76rem);
592
+ margin: 0 auto;
593
+ padding: clamp(2.5rem, 6vw, 5rem) 0 6rem;
594
+ animation: page-in 480ms ease-out both;
595
+ }
596
+
597
+ .feedback-intro {
598
+ max-width: 42rem;
599
+ }
600
+
601
+ .feedback-eyebrow {
602
+ margin: 0 0 1rem;
603
+ color: var(--portal-accent);
604
+ font-size: 0.75rem;
605
+ font-weight: 750;
606
+ letter-spacing: 0.13em;
607
+ text-transform: uppercase;
608
+ }
609
+
610
+ .feedback-intro h1 {
611
+ margin: 0;
612
+ font-size: var(--text-2xl);
613
+ font-weight: 650;
614
+ letter-spacing: -0.055em;
615
+ line-height: 1;
616
+ }
617
+
618
+ .feedback-deck {
619
+ max-width: 37rem;
620
+ margin: 0.85rem 0 0;
621
+ color: var(--muted-foreground);
622
+ font-size: 0.95rem;
623
+ line-height: 1.55;
624
+ }
625
+
626
+ .changelog-timeline {
627
+ display: grid;
628
+ gap: 2.5rem;
629
+ max-width: 64rem;
630
+ margin: 2.5rem auto 0;
631
+ padding: 0;
632
+ list-style: none;
633
+ }
634
+
635
+ .changelog-timeline-entry {
636
+ position: relative;
637
+ display: grid;
638
+ grid-template-columns: 8rem minmax(0, 1fr);
639
+ gap: 2rem;
640
+ align-items: start;
641
+ }
642
+
643
+ .changelog-timeline-entry > time {
644
+ padding-top: 0.2rem;
645
+ color: var(--muted-foreground);
646
+ font-size: var(--text-xs);
647
+ font-variant-numeric: tabular-nums;
648
+ }
649
+
650
+ .changelog-timeline-marker {
651
+ position: absolute;
652
+ z-index: 1;
653
+ top: 0.45rem;
654
+ left: 10rem;
655
+ width: 0.4rem;
656
+ height: 0.4rem;
657
+ transform: translateX(-50%);
658
+ border-radius: 50%;
659
+ background: var(--muted-foreground);
660
+ box-shadow: 0 0 0 4px var(--background);
661
+ }
662
+
663
+ .changelog-timeline-entry > article {
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);
668
+ scroll-margin-top: 6rem;
669
+ }
670
+
671
+ .changelog-timeline-entry > article:target {
672
+ outline: 1px solid var(--ring);
673
+ outline-offset: 0.75rem;
674
+ }
675
+
676
+ .changelog-entry-body {
677
+ display: grid;
678
+ gap: 1rem;
679
+ margin-top: 1rem;
680
+ color: var(--muted-foreground);
681
+ font-size: var(--text-sm);
682
+ line-height: 1.75;
683
+ overflow-wrap: anywhere;
684
+ }
685
+
686
+ .changelog-entry-body p {
687
+ margin: 0;
688
+ white-space: pre-line;
689
+ }
690
+
691
+ @media (max-width: 640px) {
692
+ .changelog-timeline-entry {
693
+ grid-template-columns: minmax(0, 1fr);
694
+ gap: 0.75rem;
695
+ }
696
+ .changelog-timeline-entry > article {
697
+ padding-left: 0;
698
+ border-left: 0;
699
+ }
700
+ .changelog-timeline-marker {
701
+ display: none;
702
+ }
703
+ }
704
+
705
+ .theme-control {
706
+ display: grid;
707
+ gap: 0.4rem;
708
+ color: var(--muted-foreground);
709
+ font-size: 0.75rem;
710
+ font-weight: 700;
711
+ }
712
+
713
+ .theme-control select {
714
+ min-height: 2.5rem;
715
+ border: 1px solid var(--portal-rule);
716
+ background: var(--portal-paper);
717
+ color: var(--portal-ink);
718
+ }
719
+
720
+ .feedback-filters {
721
+ display: grid;
722
+ grid-template-columns: repeat(2, minmax(0, 1fr)) auto;
723
+ gap: 1rem;
724
+ align-items: end;
725
+ margin: clamp(3rem, 7vw, 6rem) 0 0;
726
+ padding: 1.35rem 0;
727
+ border-block: 1px solid var(--portal-rule);
728
+ }
729
+
730
+ .feedback-filters label {
731
+ display: grid;
732
+ gap: 0.55rem;
733
+ }
734
+
735
+ .feedback-filters label > span {
736
+ color: var(--muted-foreground);
737
+ font-size: 0.68rem;
738
+ font-weight: 700;
739
+ letter-spacing: 0.08em;
740
+ text-transform: uppercase;
741
+ }
742
+
743
+ .feedback-filters select,
744
+ .feedback-filters button {
745
+ min-height: 2.8rem;
746
+ border: 1px solid var(--input);
747
+ border-radius: 0;
748
+ background: transparent;
749
+ color: var(--portal-ink);
750
+ font: inherit;
751
+ }
752
+
753
+ .feedback-filters select {
754
+ width: 100%;
755
+ padding: 0 2.5rem 0 0.8rem;
756
+ }
757
+
758
+ .feedback-filters button {
759
+ padding: 0 1.35rem;
760
+ border-color: var(--portal-ink);
761
+ background: var(--portal-ink);
762
+ color: var(--primary-foreground);
763
+ cursor: pointer;
764
+ font-size: 0.82rem;
765
+ font-weight: 700;
766
+ transition:
767
+ background-color 160ms ease,
768
+ transform 160ms ease;
769
+ }
770
+
771
+ .feedback-filters button:hover {
772
+ background: var(--portal-accent);
773
+ transform: translateY(-2px);
774
+ }
775
+
776
+ .feedback-results {
777
+ padding-top: 3rem;
778
+ }
779
+
780
+ .creation-skeleton-eyebrow {
781
+ width: 7rem;
782
+ height: 0.75rem;
783
+ }
784
+
785
+ .creation-skeleton-heading {
786
+ width: min(22rem, 70vw);
787
+ height: clamp(3rem, 6vw, 5rem);
788
+ margin-top: 1rem;
789
+ }
790
+
791
+ .creation-skeleton-copy {
792
+ width: min(26rem, 75vw);
793
+ height: 3rem;
794
+ margin-top: 1.5rem;
795
+ }
796
+
797
+ .creation-skeleton-field,
798
+ .creation-skeleton-textarea,
799
+ .creation-skeleton-action {
800
+ width: 100%;
801
+ height: 3rem;
802
+ }
803
+
804
+ .creation-skeleton-textarea {
805
+ height: 9rem;
806
+ }
807
+
808
+ .creation-skeleton-action {
809
+ width: 8rem;
810
+ }
811
+
812
+ .feedback-results-heading {
813
+ display: flex;
814
+ align-items: baseline;
815
+ justify-content: space-between;
816
+ gap: 1rem;
817
+ padding-bottom: 1rem;
818
+ }
819
+
820
+ .feedback-results-heading h2 {
821
+ margin: 0;
822
+ font-size: 1.25rem;
823
+ letter-spacing: -0.035em;
824
+ }
825
+
826
+ .feedback-results-heading span {
827
+ color: var(--muted-foreground);
828
+ font-size: 0.75rem;
829
+ }
830
+
831
+ .feedback-list {
832
+ margin: 0;
833
+ padding: 0;
834
+ border-top: 1px solid var(--portal-ink);
835
+ list-style: none;
836
+ }
837
+
838
+ .feedback-list li {
839
+ border-bottom: 1px solid var(--portal-rule);
840
+ }
841
+
842
+ .post-link {
843
+ display: block;
844
+ color: inherit;
845
+ text-decoration: none;
846
+ }
847
+
848
+ .feedback-list article {
849
+ padding: clamp(1.5rem, 3vw, 2.4rem) 0;
850
+ transition: transform 180ms ease;
851
+ }
852
+
853
+ .feedback-list li:hover article {
854
+ transform: translateX(0.45rem);
855
+ }
856
+
857
+ .feedback-meta {
858
+ display: flex;
859
+ flex-wrap: wrap;
860
+ gap: 0.5rem 1rem;
861
+ color: var(--muted-foreground);
862
+ font-size: 0.7rem;
863
+ font-weight: 650;
864
+ letter-spacing: 0.045em;
865
+ text-transform: uppercase;
866
+ }
867
+
868
+ .feedback-meta span:nth-child(2) {
869
+ color: var(--portal-accent);
870
+ }
871
+
872
+ .feedback-list h3 {
873
+ margin: 0.8rem 0 0;
874
+ font-size: clamp(1.35rem, 2.5vw, 2.15rem);
875
+ font-weight: 620;
876
+ letter-spacing: -0.045em;
877
+ }
878
+
879
+ .feedback-list article > p {
880
+ max-width: 47rem;
881
+ margin: 0.75rem 0 0;
882
+ color: var(--muted-foreground);
883
+ line-height: 1.65;
884
+ }
885
+
886
+ .feedback-empty {
887
+ padding: 5rem 0;
888
+ border-block: 1px solid var(--portal-rule);
889
+ text-align: center;
890
+ }
891
+
892
+ .feedback-empty p {
893
+ margin: 0 0 1rem;
894
+ font-size: clamp(1.4rem, 3vw, 2rem);
895
+ letter-spacing: -0.04em;
896
+ }
897
+
898
+ .feedback-empty a,
899
+ .feedback-next {
900
+ color: var(--portal-accent);
901
+ font-weight: 700;
902
+ text-underline-offset: 0.25em;
903
+ }
904
+
905
+ .feedback-next {
906
+ display: inline-flex;
907
+ align-items: center;
908
+ gap: 0.6rem;
909
+ margin-top: 2rem;
910
+ text-decoration: none;
911
+ }
912
+
913
+ .feedback-next svg {
914
+ width: 1rem;
915
+ transition: transform 160ms ease;
916
+ }
917
+
918
+ .feedback-next:hover svg {
919
+ transform: translateX(0.35rem);
920
+ }
921
+
922
+ .roadmap-page {
923
+ width: min(90vw, 90rem);
924
+ margin: 0 auto;
925
+ padding: clamp(3.5rem, 8vw, 8rem) 0 6rem;
926
+ animation: page-in 480ms ease-out both;
927
+ }
928
+
929
+ .roadmap-intro {
930
+ display: grid;
931
+ grid-template-columns: minmax(0, 1fr) minmax(18rem, 0.55fr);
932
+ gap: 2rem;
933
+ align-items: end;
934
+ }
935
+
936
+ .roadmap-intro .feedback-eyebrow {
937
+ grid-column: 1 / -1;
938
+ margin-bottom: -1rem;
939
+ }
940
+
941
+ .roadmap-intro h1 {
942
+ max-width: 12ch;
943
+ margin: 0;
944
+ font-size: var(--text-2xl);
945
+ font-weight: 650;
946
+ letter-spacing: -0.075em;
947
+ line-height: 0.94;
948
+ }
949
+
950
+ .roadmap-intro > p:last-child {
951
+ margin: 0;
952
+ color: var(--muted-foreground);
953
+ font-size: clamp(1rem, 1.5vw, 1.2rem);
954
+ line-height: 1.65;
955
+ }
956
+
957
+ .roadmap-groups {
958
+ display: grid;
959
+ grid-template-columns: repeat(3, minmax(0, 1fr));
960
+ gap: 1px;
961
+ margin-top: clamp(4rem, 9vw, 8rem);
962
+ border: 1px solid var(--portal-ink);
963
+ background: var(--portal-ink);
964
+ }
965
+
966
+ .roadmap-group {
967
+ min-width: 0;
968
+ background: var(--portal-paper);
969
+ }
970
+
971
+ .roadmap-group > header {
972
+ display: flex;
973
+ align-items: baseline;
974
+ justify-content: space-between;
975
+ gap: 1rem;
976
+ padding: 1.15rem 1.25rem;
977
+ border-bottom: 1px solid var(--portal-ink);
978
+ }
979
+
980
+ .roadmap-group h2 {
981
+ margin: 0;
982
+ font-size: 0.82rem;
983
+ letter-spacing: 0.08em;
984
+ text-transform: uppercase;
985
+ }
986
+
987
+ .roadmap-group > header span {
988
+ color: var(--portal-accent);
989
+ font-size: 0.75rem;
990
+ font-weight: 750;
991
+ }
992
+
993
+ .roadmap-list {
994
+ margin: 0;
995
+ padding: 0;
996
+ list-style: none;
997
+ }
998
+
999
+ .roadmap-list li + li {
1000
+ border-top: 1px solid var(--portal-rule);
1001
+ }
1002
+
1003
+ .roadmap-list a {
1004
+ display: block;
1005
+ color: inherit;
1006
+ text-decoration: none;
1007
+ }
1008
+
1009
+ .roadmap-list article {
1010
+ padding: 1.5rem 1.25rem;
1011
+ transition: background-color 160ms ease;
1012
+ }
1013
+
1014
+ .roadmap-list a:hover article {
1015
+ background: color-mix(in srgb, var(--portal-accent) 6%, transparent);
1016
+ }
1017
+
1018
+ .roadmap-item-meta {
1019
+ display: flex;
1020
+ flex-wrap: wrap;
1021
+ gap: 0.45rem 0.8rem;
1022
+ color: var(--muted-foreground);
1023
+ font-size: 0.65rem;
1024
+ font-weight: 700;
1025
+ letter-spacing: 0.045em;
1026
+ text-transform: uppercase;
1027
+ }
1028
+
1029
+ .roadmap-item-meta span {
1030
+ color: var(--portal-accent);
1031
+ }
1032
+
1033
+ .roadmap-list h3 {
1034
+ margin: 0.8rem 0 0;
1035
+ font-size: clamp(1.2rem, 2vw, 1.65rem);
1036
+ font-weight: 640;
1037
+ letter-spacing: -0.04em;
1038
+ }
1039
+
1040
+ .roadmap-list article > p {
1041
+ display: -webkit-box;
1042
+ overflow: hidden;
1043
+ margin: 0.65rem 0 0;
1044
+ -webkit-box-orient: vertical;
1045
+ color: var(--muted-foreground);
1046
+ line-height: 1.55;
1047
+ -webkit-line-clamp: 3;
1048
+ }
1049
+
1050
+ .roadmap-empty {
1051
+ margin: 0;
1052
+ padding: 3.5rem 1.25rem;
1053
+ color: var(--muted-foreground);
1054
+ font-size: 0.86rem;
1055
+ line-height: 1.5;
1056
+ }
1057
+
1058
+ .roadmap-skeleton-count {
1059
+ width: 1.5rem;
1060
+ height: 0.75rem;
1061
+ }
1062
+
1063
+ .roadmap-skeleton-card {
1064
+ display: grid;
1065
+ gap: 0.75rem;
1066
+ padding: 1.5rem 1.25rem;
1067
+ }
1068
+
1069
+ .roadmap-skeleton-meta {
1070
+ width: 55%;
1071
+ height: 0.65rem;
1072
+ }
1073
+
1074
+ .roadmap-skeleton-title {
1075
+ width: 80%;
1076
+ height: 1.65rem;
1077
+ }
1078
+
1079
+ .roadmap-skeleton-copy {
1080
+ width: 100%;
1081
+ height: 0.85rem;
1082
+ }
1083
+
1084
+ .roadmap-skeleton-copy-short {
1085
+ width: 70%;
1086
+ }
1087
+
1088
+ .feedback-detail {
1089
+ width: min(90vw, 76rem);
1090
+ margin: 0 auto;
1091
+ padding: clamp(2.5rem, 6vw, 5rem) 0 6rem;
1092
+ animation: page-in 480ms ease-out both;
1093
+ }
1094
+
1095
+ .feedback-detail-back {
1096
+ display: inline-flex;
1097
+ align-items: center;
1098
+ gap: 0.55rem;
1099
+ color: var(--portal-ink);
1100
+ font-size: 0.78rem;
1101
+ font-weight: 700;
1102
+ text-decoration: none;
1103
+ }
1104
+
1105
+ .feedback-detail-back svg {
1106
+ width: 1rem;
1107
+ transition: transform 160ms ease;
1108
+ }
1109
+
1110
+ .feedback-detail-back:hover svg {
1111
+ transform: translateX(-0.3rem);
1112
+ }
1113
+
1114
+ .feedback-detail article {
1115
+ max-width: 62rem;
1116
+ margin-top: clamp(4rem, 9vw, 8rem);
1117
+ }
1118
+
1119
+ .feedback-detail-meta {
1120
+ display: flex;
1121
+ flex-wrap: wrap;
1122
+ gap: 0.75rem 1.25rem;
1123
+ color: var(--portal-accent);
1124
+ font-size: 0.72rem;
1125
+ font-weight: 750;
1126
+ letter-spacing: 0.08em;
1127
+ text-transform: uppercase;
1128
+ }
1129
+
1130
+ .feedback-detail-meta span + span {
1131
+ color: var(--muted-foreground);
1132
+ }
1133
+
1134
+ .feedback-detail h1 {
1135
+ max-width: 14ch;
1136
+ margin: 1.25rem 0 0;
1137
+ font-size: var(--text-2xl);
1138
+ font-weight: 650;
1139
+ letter-spacing: -0.075em;
1140
+ line-height: 0.94;
1141
+ }
1142
+
1143
+ .feedback-detail-description {
1144
+ max-width: 48rem;
1145
+ margin: clamp(2rem, 5vw, 4rem) 0 0;
1146
+ color: var(--muted-foreground);
1147
+ font-size: var(--text-sm);
1148
+ line-height: 1.75;
1149
+ white-space: pre-wrap;
1150
+ }
1151
+
1152
+ .feedback-detail-dates {
1153
+ display: flex;
1154
+ gap: clamp(2rem, 7vw, 6rem);
1155
+ margin: clamp(3rem, 6vw, 5rem) 0 0;
1156
+ padding-top: 1.25rem;
1157
+ border-top: 1px solid var(--portal-rule);
1158
+ }
1159
+
1160
+ .feedback-detail-dates div {
1161
+ display: grid;
1162
+ gap: 0.35rem;
1163
+ }
1164
+
1165
+ .feedback-detail-dates dt {
1166
+ color: var(--muted-foreground);
1167
+ font-size: 0.68rem;
1168
+ font-weight: 700;
1169
+ letter-spacing: 0.08em;
1170
+ text-transform: uppercase;
1171
+ }
1172
+
1173
+ .feedback-detail-dates dd {
1174
+ margin: 0;
1175
+ font-size: 0.85rem;
1176
+ font-weight: 650;
1177
+ }
1178
+
1179
+ .public-post-detail {
1180
+ width: min(90vw, 64rem);
1181
+ padding: clamp(2rem, 5vw, 4rem) 0 5rem;
1182
+ }
1183
+
1184
+ .public-post-detail[data-display="overlay"] {
1185
+ width: 100%;
1186
+ margin: 0;
1187
+ padding: 0;
1188
+ animation: none;
1189
+ }
1190
+
1191
+ .public-post-detail .post-detail-layout {
1192
+ display: grid;
1193
+ max-width: none;
1194
+ grid-template-columns: minmax(0, 1fr) minmax(14rem, 0.38fr);
1195
+ margin-top: 1.5rem;
1196
+ border: 1px solid var(--portal-rule);
1197
+ background: color-mix(in srgb, var(--card) 55%, var(--background));
1198
+ }
1199
+
1200
+ .public-post-detail[data-display="overlay"] .post-detail-layout {
1201
+ margin-top: 0;
1202
+ border: 0;
1203
+ }
1204
+
1205
+ .post-detail-primary,
1206
+ .post-detail-sidebar {
1207
+ min-width: 0;
1208
+ padding: 1.5rem;
1209
+ }
1210
+
1211
+ .post-detail-sidebar {
1212
+ border-left: 1px solid var(--portal-rule);
1213
+ background: color-mix(in srgb, var(--muted) 16%, transparent);
1214
+ }
1215
+
1216
+ .public-post-detail .feedback-detail-meta {
1217
+ display: flex;
1218
+ gap: 0.5rem;
1219
+ color: inherit;
1220
+ font-size: inherit;
1221
+ letter-spacing: normal;
1222
+ text-transform: none;
1223
+ }
1224
+
1225
+ .public-post-detail .feedback-detail-meta [data-status="Planned"],
1226
+ .public-post-detail .post-detail-details [data-status="Planned"] {
1227
+ border-color: color-mix(in srgb, var(--status-planned) 40%, transparent);
1228
+ background: color-mix(in srgb, var(--status-planned) 14%, transparent);
1229
+ color: var(--status-planned);
1230
+ }
1231
+
1232
+ .public-post-detail .feedback-detail-meta [data-status="In Progress"],
1233
+ .public-post-detail .post-detail-details [data-status="In Progress"] {
1234
+ border-color: color-mix(in srgb, var(--status-in-progress) 40%, transparent);
1235
+ background: color-mix(in srgb, var(--status-in-progress) 14%, transparent);
1236
+ color: var(--status-in-progress);
1237
+ }
1238
+
1239
+ .public-post-detail .feedback-detail-meta [data-status="Shipped"],
1240
+ .public-post-detail .post-detail-details [data-status="Shipped"] {
1241
+ border-color: color-mix(in srgb, var(--status-shipped) 40%, transparent);
1242
+ background: color-mix(in srgb, var(--status-shipped) 14%, transparent);
1243
+ color: var(--status-shipped);
1244
+ }
1245
+
1246
+ .public-post-detail h1 {
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;
1258
+ }
1259
+
1260
+ .public-post-detail .feedback-detail-description {
1261
+ max-width: 45rem;
1262
+ margin: 0.75rem 0 0;
1263
+ color: var(--muted-foreground);
1264
+ font-size: var(--text-sm);
1265
+ line-height: 1.65;
1266
+ }
1267
+
1268
+ .post-detail-engagement {
1269
+ display: flex;
1270
+ align-items: center;
1271
+ justify-content: space-between;
1272
+ gap: 1rem;
1273
+ margin-top: 1.75rem;
1274
+ }
1275
+
1276
+ .post-detail-summary-actions {
1277
+ margin-top: 1.25rem;
1278
+ }
1279
+
1280
+ .post-detail-engagement > span {
1281
+ display: inline-flex;
1282
+ min-height: 2.75rem;
1283
+ align-items: center;
1284
+ gap: 0.6rem;
1285
+ color: var(--muted-foreground);
1286
+ font-size: 0.85rem;
1287
+ }
1288
+
1289
+ .post-detail-engagement > span:first-child {
1290
+ min-width: 5rem;
1291
+ justify-content: center;
1292
+ border: 1px solid var(--portal-rule);
1293
+ color: var(--portal-ink);
1294
+ }
1295
+
1296
+ .post-detail-engagement svg {
1297
+ width: 1rem;
1298
+ height: 1rem;
1299
+ }
1300
+
1301
+ .post-detail-comments {
1302
+ margin-top: 1.75rem;
1303
+ padding-top: 1.75rem;
1304
+ border-top: 1px solid var(--portal-rule);
1305
+ }
1306
+
1307
+ .post-detail-comments > h2,
1308
+ .post-detail-sidebar > h2 {
1309
+ margin: 0;
1310
+ font-size: 1rem;
1311
+ font-weight: 650;
1312
+ letter-spacing: -0.02em;
1313
+ }
1314
+
1315
+ .post-detail-thread-list {
1316
+ max-height: 30rem;
1317
+ overflow-y: auto;
1318
+ overscroll-behavior: contain;
1319
+ scrollbar-gutter: stable;
1320
+ margin-top: 1.25rem;
1321
+ border-top: 1px solid var(--portal-rule);
1322
+ }
1323
+
1324
+ .comment-threads {
1325
+ padding-right: 0.5rem;
1326
+ }
1327
+
1328
+ .public-post-detail .comment-thread {
1329
+ max-width: none;
1330
+ margin-top: 0;
1331
+ }
1332
+
1333
+ .comment-thread + .comment-thread {
1334
+ border-top: 1px solid var(--portal-rule);
1335
+ }
1336
+
1337
+ .comment {
1338
+ padding: 1.15rem 0;
1339
+ }
1340
+
1341
+ .comment + .comment {
1342
+ border-top: 1px solid color-mix(in srgb, var(--portal-rule) 70%, transparent);
1343
+ }
1344
+
1345
+ .comment[data-reply="true"] {
1346
+ margin-left: 2rem;
1347
+ padding-left: 1rem;
1348
+ border-left: 2px solid var(--portal-rule);
1349
+ }
1350
+
1351
+ .comment-header {
1352
+ display: flex;
1353
+ align-items: center;
1354
+ justify-content: space-between;
1355
+ gap: 0.75rem;
1356
+ }
1357
+
1358
+ .comment-author {
1359
+ display: flex;
1360
+ min-width: 0;
1361
+ flex-wrap: wrap;
1362
+ align-items: center;
1363
+ gap: 0.45rem;
1364
+ }
1365
+
1366
+ .comment-author strong {
1367
+ overflow: hidden;
1368
+ font-size: 0.85rem;
1369
+ font-weight: 650;
1370
+ text-overflow: ellipsis;
1371
+ white-space: nowrap;
1372
+ }
1373
+
1374
+ .comment-author span {
1375
+ padding: 0.1rem 0.35rem;
1376
+ border: 1px solid var(--portal-rule);
1377
+ color: var(--muted-foreground);
1378
+ font-size: 0.65rem;
1379
+ line-height: 1.25;
1380
+ }
1381
+
1382
+ .comment-header time {
1383
+ flex: none;
1384
+ color: var(--muted-foreground);
1385
+ font-size: 0.72rem;
1386
+ font-variant-numeric: tabular-nums;
1387
+ }
1388
+
1389
+ .comment-body {
1390
+ margin: 0.6rem 0 0;
1391
+ color: var(--foreground);
1392
+ font-size: 0.9rem;
1393
+ line-height: 1.6;
1394
+ overflow-wrap: anywhere;
1395
+ }
1396
+
1397
+ .comment-actions {
1398
+ display: flex;
1399
+ flex-wrap: wrap;
1400
+ justify-content: flex-end;
1401
+ gap: 0.25rem;
1402
+ margin-top: 0.65rem;
1403
+ }
1404
+
1405
+ .profile-gate {
1406
+ min-height: 13rem;
1407
+ margin-top: 1.25rem;
1408
+ border: 1px dashed var(--portal-rule);
1409
+ background: color-mix(in srgb, var(--muted) 14%, transparent);
1410
+ }
1411
+
1412
+ .comment-composer {
1413
+ display: grid;
1414
+ gap: 0.75rem;
1415
+ margin-top: 1.25rem;
1416
+ padding: 1rem;
1417
+ border: 1px solid
1418
+ color-mix(in srgb, var(--foreground) 24%, var(--portal-rule));
1419
+ background: var(--card);
1420
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--background) 70%, transparent);
1421
+ }
1422
+
1423
+ .comment-composer-label {
1424
+ font-size: 0.9rem;
1425
+ font-weight: 650;
1426
+ }
1427
+
1428
+ .comment-composer-hint {
1429
+ margin: -0.35rem 0 0;
1430
+ color: var(--muted-foreground);
1431
+ font-size: 0.75rem;
1432
+ line-height: 1.45;
1433
+ }
1434
+
1435
+ .comment-composer-input {
1436
+ min-height: 6rem;
1437
+ resize: vertical;
1438
+ border-color: color-mix(in srgb, var(--foreground) 28%, var(--portal-rule));
1439
+ background: var(--background);
1440
+ font-size: 0.9rem;
1441
+ line-height: 1.5;
1442
+ }
1443
+
1444
+ .comment-composer-input:focus-visible {
1445
+ border-color: var(--portal-accent);
1446
+ background: var(--card);
1447
+ }
1448
+
1449
+ .comment-composer-actions {
1450
+ display: flex;
1451
+ flex-wrap: wrap;
1452
+ gap: 0.5rem;
1453
+ justify-content: flex-end;
1454
+ }
1455
+
1456
+ .post-detail-details {
1457
+ display: grid;
1458
+ gap: 1.25rem;
1459
+ margin: 1.5rem 0 0;
1460
+ }
1461
+
1462
+ .post-detail-details > div {
1463
+ display: grid;
1464
+ grid-template-columns: minmax(5rem, 0.75fr) minmax(0, 1fr);
1465
+ gap: 1rem;
1466
+ align-items: center;
1467
+ }
1468
+
1469
+ .post-detail-details dt {
1470
+ color: var(--muted-foreground);
1471
+ font-size: 0.8rem;
1472
+ }
1473
+
1474
+ .post-detail-details dd {
1475
+ min-width: 0;
1476
+ margin: 0;
1477
+ font-size: 0.8rem;
1478
+ font-weight: 550;
1479
+ }
1480
+
1481
+ .post-detail-details time {
1482
+ white-space: nowrap;
1483
+ }
1484
+
1485
+ .feedback-detail-missing {
1486
+ display: flex;
1487
+ min-height: calc(100svh - 4.5rem);
1488
+ flex-direction: column;
1489
+ align-items: flex-start;
1490
+ justify-content: center;
1491
+ padding-block: 3rem;
1492
+ }
1493
+
1494
+ .feedback-detail-missing h1 {
1495
+ max-width: 11ch;
1496
+ }
1497
+
1498
+ .feedback-detail-missing > p:not(.feedback-eyebrow) {
1499
+ max-width: 34rem;
1500
+ margin: 1.5rem 0 2rem;
1501
+ color: var(--muted-foreground);
1502
+ font-size: 1.05rem;
1503
+ }
1504
+
1505
+ .public-error {
1506
+ display: flex;
1507
+ width: min(90vw, 76rem);
1508
+ min-height: calc(100svh - 4.5rem);
1509
+ margin: 0 auto;
1510
+ padding-block: 3rem;
1511
+ flex-direction: column;
1512
+ align-items: flex-start;
1513
+ justify-content: center;
1514
+ }
1515
+
1516
+ .public-error h1 {
1517
+ max-width: 12ch;
1518
+ margin: 0;
1519
+ font-size: var(--text-2xl);
1520
+ font-weight: 650;
1521
+ letter-spacing: -0.075em;
1522
+ line-height: 0.94;
1523
+ }
1524
+
1525
+ .public-error > p:not(.feedback-eyebrow) {
1526
+ max-width: 38rem;
1527
+ margin: 1.5rem 0 2rem;
1528
+ color: var(--muted-foreground);
1529
+ font-size: 1.05rem;
1530
+ line-height: 1.65;
1531
+ }
1532
+
1533
+ .public-error-actions {
1534
+ display: flex;
1535
+ flex-wrap: wrap;
1536
+ gap: 0.75rem;
1537
+ }
1538
+
1539
+ .public-error-actions button,
1540
+ .public-error-actions a {
1541
+ display: inline-flex;
1542
+ min-height: 3rem;
1543
+ padding: 0 1.25rem;
1544
+ align-items: center;
1545
+ border: 1px solid var(--portal-ink);
1546
+ border-radius: 0;
1547
+ background: var(--portal-ink);
1548
+ color: var(--primary-foreground);
1549
+ cursor: pointer;
1550
+ font: inherit;
1551
+ font-size: 0.82rem;
1552
+ font-weight: 750;
1553
+ text-decoration: none;
1554
+ }
1555
+
1556
+ .public-error-actions a {
1557
+ background: transparent;
1558
+ color: var(--portal-ink);
1559
+ }
1560
+
1561
+ .portal-loading {
1562
+ width: 100%;
1563
+ }
1564
+
1565
+ @keyframes page-in {
1566
+ from {
1567
+ opacity: 0;
1568
+ transform: translateY(12px);
1569
+ }
1570
+ }
1571
+
1572
+ @keyframes spin {
1573
+ to {
1574
+ transform: rotate(360deg);
1575
+ }
1576
+ }
1577
+
1578
+ @media (max-width: 720px) {
1579
+ .feedback-submit {
1580
+ grid-template-columns: 1fr;
1581
+ gap: 1.5rem;
1582
+ padding: 1.25rem;
1583
+ }
1584
+
1585
+ .feedback-submit[data-display="overlay"] {
1586
+ grid-template-columns: minmax(0, 1fr);
1587
+ }
1588
+
1589
+ .feedback-submit-form input,
1590
+ .feedback-submit-form textarea,
1591
+ .feedback-submit-form select {
1592
+ font-size: 1rem;
1593
+ }
1594
+
1595
+ .feedback-post-type-picker {
1596
+ grid-template-columns: 1fr;
1597
+ }
1598
+
1599
+ .feedback-post-type-card {
1600
+ min-height: auto;
1601
+ grid-template-columns: auto 1fr auto;
1602
+ grid-template-rows: 1fr;
1603
+ gap: 0.875rem;
1604
+ align-items: center;
1605
+ }
1606
+
1607
+ .feedback-post-type-card > svg {
1608
+ grid-column: 1;
1609
+ grid-row: 1;
1610
+ }
1611
+
1612
+ .feedback-post-type-copy {
1613
+ grid-column: 2;
1614
+ grid-row: 1;
1615
+ }
1616
+
1617
+ .feedback-post-type-card > [data-slot="radio-group-item"] {
1618
+ grid-column: 3;
1619
+ grid-row: 1;
1620
+ }
1621
+
1622
+ .feedback-submit-actions {
1623
+ display: grid;
1624
+ }
1625
+ }
1626
+
1627
+ @media (max-width: 640px) {
1628
+ .portal-header {
1629
+ padding-inline: 1rem;
1630
+ }
1631
+
1632
+ .portal-header nav {
1633
+ gap: 0.75rem;
1634
+ }
1635
+
1636
+ .portal-header nav a {
1637
+ font-size: 0.66rem;
1638
+ }
1639
+
1640
+ .feedback-index {
1641
+ width: auto;
1642
+ padding: 3.5rem 1rem 4rem;
1643
+ }
1644
+
1645
+ .feedback-detail {
1646
+ width: auto;
1647
+ padding: 2.5rem 1rem 4rem;
1648
+ }
1649
+
1650
+ .public-error {
1651
+ width: auto;
1652
+ padding: 3rem 1rem;
1653
+ }
1654
+
1655
+ .public-error-actions {
1656
+ display: grid;
1657
+ width: 100%;
1658
+ }
1659
+
1660
+ .public-error-actions button,
1661
+ .public-error-actions a {
1662
+ justify-content: center;
1663
+ }
1664
+
1665
+ .roadmap-page {
1666
+ width: auto;
1667
+ padding: 3.5rem 1rem 4rem;
1668
+ }
1669
+
1670
+ .roadmap-intro,
1671
+ .roadmap-intro {
1672
+ grid-template-columns: 1fr;
1673
+ }
1674
+
1675
+ .roadmap-intro .feedback-eyebrow {
1676
+ grid-column: auto;
1677
+ margin-bottom: -0.5rem;
1678
+ }
1679
+
1680
+ .roadmap-groups {
1681
+ grid-template-columns: repeat(3, minmax(82vw, 1fr));
1682
+ gap: 1px;
1683
+ margin-top: 4rem;
1684
+ overflow-x: auto;
1685
+ scroll-snap-type: x mandatory;
1686
+ overscroll-behavior-inline: contain;
1687
+ scrollbar-width: thin;
1688
+ }
1689
+
1690
+ .roadmap-group {
1691
+ scroll-snap-align: start;
1692
+ scroll-snap-stop: always;
1693
+ }
1694
+
1695
+ .feedback-detail article {
1696
+ margin-top: 4rem;
1697
+ }
1698
+
1699
+ .feedback-detail h1 {
1700
+ font-size: var(--text-2xl);
1701
+ }
1702
+
1703
+ .feedback-detail-dates {
1704
+ flex-direction: column;
1705
+ gap: 1.25rem;
1706
+ }
1707
+
1708
+ .feedback-intro h1 {
1709
+ font-size: var(--text-2xl);
1710
+ }
1711
+
1712
+ .feedback-filters {
1713
+ grid-template-columns: 1fr;
1714
+ }
1715
+
1716
+ .feedback-filters select,
1717
+ .feedback-filters button {
1718
+ min-height: 3rem;
1719
+ }
1720
+
1721
+ .feedback-list article > p {
1722
+ display: -webkit-box;
1723
+ overflow: hidden;
1724
+ -webkit-box-orient: vertical;
1725
+ -webkit-line-clamp: 3;
1726
+ }
1727
+ }
1728
+
1729
+ @media (max-width: 880px) {
1730
+ .public-post-detail .post-detail-layout {
1731
+ grid-template-columns: 1fr;
1732
+ }
1733
+
1734
+ .post-detail-sidebar {
1735
+ border-top: 1px solid var(--portal-rule);
1736
+ border-left: 0;
1737
+ }
1738
+ }
1739
+
1740
+ @media (max-width: 640px) {
1741
+ .public-post-detail {
1742
+ width: auto;
1743
+ }
1744
+
1745
+ .public-post-detail .post-detail-layout {
1746
+ margin-top: 1rem;
1747
+ }
1748
+
1749
+ .public-post-detail[data-display="overlay"] .post-detail-layout {
1750
+ margin-top: 0;
1751
+ }
1752
+
1753
+ .public-post-detail h1 {
1754
+ font-size: var(--text-xl);
1755
+ }
1756
+
1757
+ .post-detail-primary,
1758
+ .post-detail-sidebar {
1759
+ padding: 1.25rem;
1760
+ }
1761
+
1762
+ .post-detail-engagement {
1763
+ align-items: stretch;
1764
+ }
1765
+
1766
+ .post-detail-engagement > span:last-child {
1767
+ justify-content: flex-end;
1768
+ }
1769
+
1770
+ .comment[data-reply="true"] {
1771
+ margin-left: 0.75rem;
1772
+ padding-left: 0.75rem;
1773
+ }
1774
+
1775
+ .comment-header {
1776
+ align-items: flex-start;
1777
+ flex-direction: column;
1778
+ gap: 0.35rem;
1779
+ }
1780
+
1781
+ .post-detail-details > div {
1782
+ grid-template-columns: minmax(5rem, 0.65fr) minmax(0, 1fr);
1783
+ }
1784
+ }
1785
+
1786
+ @media (prefers-reduced-motion: reduce) {
1787
+ *,
1788
+ *::before,
1789
+ *::after {
1790
+ scroll-behavior: auto !important;
1791
+ animation-duration: 0.01ms !important;
1792
+ animation-iteration-count: 1 !important;
1793
+ transition-duration: 0.01ms !important;
1794
+ }
1795
+ }