@grove-dev/astro 0.1.5 → 0.2.5

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 (148) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +4 -25
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +56 -22
  5. package/dist/index.js.map +1 -1
  6. package/dist/layouts/index.d.ts +25 -0
  7. package/dist/layouts/index.d.ts.map +1 -0
  8. package/dist/layouts/index.js +25 -0
  9. package/dist/layouts/index.js.map +1 -0
  10. package/dist/lib/display.d.ts +33 -0
  11. package/dist/lib/display.d.ts.map +1 -0
  12. package/dist/lib/display.js +104 -0
  13. package/dist/lib/display.js.map +1 -0
  14. package/dist/lib/format.d.ts +30 -0
  15. package/dist/lib/format.d.ts.map +1 -0
  16. package/dist/lib/format.js +73 -0
  17. package/dist/lib/format.js.map +1 -0
  18. package/dist/lib/index.d.ts +26 -0
  19. package/dist/lib/index.d.ts.map +1 -0
  20. package/dist/lib/index.js +26 -0
  21. package/dist/lib/index.js.map +1 -0
  22. package/dist/lib/lenses.d.ts +96 -0
  23. package/dist/lib/lenses.d.ts.map +1 -0
  24. package/dist/lib/lenses.js +181 -0
  25. package/dist/lib/lenses.js.map +1 -0
  26. package/dist/lib/repo.d.ts +30 -0
  27. package/dist/lib/repo.d.ts.map +1 -0
  28. package/dist/lib/repo.js +44 -0
  29. package/dist/lib/repo.js.map +1 -0
  30. package/dist/lib/scores.d.ts +38 -0
  31. package/dist/lib/scores.d.ts.map +1 -0
  32. package/dist/lib/scores.js +83 -0
  33. package/dist/lib/scores.js.map +1 -0
  34. package/dist/lib/search.d.ts +199 -0
  35. package/dist/lib/search.d.ts.map +1 -0
  36. package/dist/lib/search.js +357 -0
  37. package/dist/lib/search.js.map +1 -0
  38. package/dist/lib/taxonomy-counts.d.ts +25 -0
  39. package/dist/lib/taxonomy-counts.d.ts.map +1 -0
  40. package/dist/lib/taxonomy-counts.js +41 -0
  41. package/dist/lib/taxonomy-counts.js.map +1 -0
  42. package/package.json +7 -7
  43. package/src/components/AppsIndexRow.astro +204 -0
  44. package/src/components/AppsPagination.astro +126 -0
  45. package/src/components/CategoryGrid.astro +86 -17
  46. package/src/components/ContributorsGrid.astro +149 -0
  47. package/src/components/DecisionRow.astro +89 -0
  48. package/src/components/ExploreByCategory.astro +67 -0
  49. package/src/components/ExploreByStack.astro +72 -0
  50. package/src/components/Hero.astro +246 -0
  51. package/src/components/Icon.astro +223 -0
  52. package/src/components/ItemCard.astro +306 -30
  53. package/src/components/MinimalAbout.astro +82 -0
  54. package/src/components/OriginalCollection.astro +116 -0
  55. package/src/components/RecordSection.astro +88 -0
  56. package/src/components/RefinePanel.astro +197 -0
  57. package/src/components/ScoreBars.astro +92 -22
  58. package/src/components/SmartLensTabs.astro +71 -0
  59. package/src/components/StackGrid.astro +132 -0
  60. package/src/components/WhyThisExists.astro +116 -0
  61. package/src/index.ts +61 -14
  62. package/src/layouts/BaseLayout.astro +227 -15
  63. package/src/layouts/Container.astro +57 -0
  64. package/src/layouts/Footer.astro +235 -0
  65. package/src/layouts/Header.astro +159 -0
  66. package/src/layouts/SectionHeader.astro +58 -0
  67. package/{templates/default/src/components/layout → src/layouts}/Seo.astro +62 -38
  68. package/src/layouts/ThemeToggle.astro +110 -0
  69. package/src/layouts/astro-shim.d.ts +29 -0
  70. package/src/layouts/index.ts +24 -0
  71. package/src/lib/display.ts +118 -0
  72. package/src/lib/format.ts +65 -0
  73. package/src/lib/index.ts +26 -0
  74. package/src/lib/lenses.ts +241 -0
  75. package/src/lib/repo.ts +44 -0
  76. package/src/lib/scores.ts +94 -0
  77. package/src/lib/search.ts +481 -0
  78. package/src/lib/taxonomy-counts.ts +60 -0
  79. package/src/styles.css +366 -638
  80. package/templates/default/astro.config.mjs +8 -6
  81. package/templates/default/content/pages/about.md +66 -0
  82. package/templates/default/content/pages/methodology.md +103 -0
  83. package/templates/default/data/generated/records.full.json +8 -0
  84. package/templates/default/data/generated/records.index.json +7 -0
  85. package/templates/default/data/generated/records.json +8 -0
  86. package/templates/default/data/generated/site-config.json +31 -0
  87. package/templates/default/data/records/.gitkeep +0 -0
  88. package/templates/default/grove.config.ts +36 -0
  89. package/templates/default/package.json +6 -5
  90. package/templates/default/public/llms-full.txt +14 -0
  91. package/templates/default/public/llms.txt +11 -0
  92. package/templates/default/src/components/layout/BaseLayout.astro +10 -57
  93. package/templates/default/src/components/layout/Footer.astro +16 -134
  94. package/templates/default/src/components/layout/Header.astro +25 -126
  95. package/templates/default/src/data/records.ts +193 -0
  96. package/templates/default/src/lib/markdown.ts +171 -0
  97. package/templates/default/src/pages/about.astro +95 -429
  98. package/templates/default/src/pages/index.astro +263 -61
  99. package/templates/default/src/pages/projects/[slug].astro +480 -0
  100. package/templates/default/src/pages/projects/index.astro +193 -0
  101. package/templates/default/src/pages/sitemap.xml.ts +73 -61
  102. package/templates/default/src/pages/submit.astro +122 -411
  103. package/templates/default/src/styles/global.css +42 -68
  104. package/src/components/ActiveFilterChips.astro +0 -20
  105. package/src/components/DirectoryFilters.astro +0 -100
  106. package/src/components/DirectoryHero.astro +0 -32
  107. package/src/components/HealthBadge.astro +0 -12
  108. package/src/components/LensTabs.astro +0 -26
  109. package/src/components/MethodologyPanel.astro +0 -20
  110. package/src/components/Pagination.astro +0 -24
  111. package/src/components/ProjectDetail.astro +0 -166
  112. package/src/components/SubmitDraft.astro +0 -137
  113. package/templates/default/src/components/AppCard.astro +0 -248
  114. package/templates/default/src/components/AppSection.astro +0 -58
  115. package/templates/default/src/components/AppsIndexRow.astro +0 -230
  116. package/templates/default/src/components/AppsPagination.astro +0 -147
  117. package/templates/default/src/components/CategoryGrid.astro +0 -80
  118. package/templates/default/src/components/ContributorsGrid.astro +0 -105
  119. package/templates/default/src/components/DecisionRow.astro +0 -219
  120. package/templates/default/src/components/ExploreByCategory.astro +0 -74
  121. package/templates/default/src/components/ExploreByStack.astro +0 -102
  122. package/templates/default/src/components/Hero.astro +0 -176
  123. package/templates/default/src/components/MinimalAbout.astro +0 -57
  124. package/templates/default/src/components/OriginalCollection.astro +0 -144
  125. package/templates/default/src/components/RefinePanel.astro +0 -272
  126. package/templates/default/src/components/ScoreBars.astro +0 -72
  127. package/templates/default/src/components/SmartLensTabs.astro +0 -65
  128. package/templates/default/src/components/StackGrid.astro +0 -95
  129. package/templates/default/src/components/WhyThisExists.astro +0 -81
  130. package/templates/default/src/components/icons/Icon.astro +0 -148
  131. package/templates/default/src/components/layout/SectionHeader.astro +0 -42
  132. package/templates/default/src/components/layout/ThemeToggle.astro +0 -97
  133. package/templates/default/src/data/apps.ts +0 -149
  134. package/templates/default/src/data/categories.ts +0 -27
  135. package/templates/default/src/data/config.ts +0 -28
  136. package/templates/default/src/data/contributors.ts +0 -96
  137. package/templates/default/src/data/stacks.ts +0 -47
  138. package/templates/default/src/data/stats.ts +0 -65
  139. package/templates/default/src/data/types.ts +0 -248
  140. package/templates/default/src/lib/apps-search.ts +0 -228
  141. package/templates/default/src/lib/format.ts +0 -36
  142. package/templates/default/src/lib/lenses.ts +0 -98
  143. package/templates/default/src/lib/repo.ts +0 -12
  144. package/templates/default/src/lib/scores.ts +0 -51
  145. package/templates/default/src/lib/taxonomy-counts.ts +0 -31
  146. package/templates/default/src/pages/apps/[slug].astro +0 -709
  147. package/templates/default/src/pages/apps/index.astro +0 -669
  148. package/templates/default/src/pages/contributors.astro +0 -142
package/src/styles.css CHANGED
@@ -1,675 +1,403 @@
1
- :root {
2
- color-scheme: light;
3
- --oc-bg: #f7f7f4;
4
- --oc-panel: #ffffff;
5
- --oc-text: #171717;
6
- --oc-muted: #666666;
7
- --oc-border: #dddddd;
8
- --oc-accent: #0f766e;
9
- --oc-warn: #a16207;
10
- --oc-danger: #b91c1c;
11
- }
12
-
13
- body {
14
- margin: 0;
15
- background: var(--oc-bg);
16
- color: var(--oc-text);
17
- font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
18
- }
19
-
20
- a {
21
- color: inherit;
22
- }
23
-
24
- .oc-topbar {
25
- position: sticky;
26
- top: 0;
27
- z-index: 20;
28
- display: flex;
29
- align-items: center;
30
- justify-content: space-between;
31
- gap: 16px;
32
- border-bottom: 1px solid var(--oc-border);
33
- background: color-mix(in srgb, var(--oc-panel), transparent 8%);
34
- padding: 12px max(16px, calc((100vw - 1120px) / 2));
35
- backdrop-filter: blur(14px);
36
- }
37
-
38
- .oc-brand {
39
- font-weight: 750;
40
- text-decoration: none;
41
- }
42
-
43
- .oc-topbar nav {
44
- display: flex;
45
- gap: 14px;
46
- color: var(--oc-muted);
47
- font-size: 0.875rem;
48
- }
49
-
50
- .oc-topbar nav a {
51
- text-decoration: none;
52
- }
53
-
54
- .oc-topbar nav a:hover {
55
- color: var(--oc-text);
56
- }
57
-
58
- .oc-shell {
59
- width: min(1120px, calc(100% - 32px));
60
- margin: 0 auto;
61
- padding: 32px 0 56px;
62
- }
63
-
64
- .oc-sr-only {
65
- position: absolute;
66
- width: 1px;
67
- height: 1px;
68
- padding: 0;
69
- overflow: hidden;
70
- clip: rect(0, 0, 0, 0);
71
- white-space: nowrap;
72
- border: 0;
73
- }
74
-
75
- .oc-eyebrow {
76
- margin: 0 0 8px;
77
- color: var(--oc-accent);
78
- font-size: 0.75rem;
79
- font-weight: 700;
80
- text-transform: uppercase;
81
- }
82
-
83
- .oc-lede {
84
- max-width: 68ch;
85
- color: var(--oc-muted);
86
- font-size: 1.0625rem;
87
- line-height: 1.6;
88
- }
89
-
90
- .oc-hero {
91
- display: grid;
92
- gap: 24px;
93
- padding: 28px 0 20px;
94
- }
95
-
96
- .oc-hero h1,
97
- .oc-detail h1 {
98
- margin: 0;
99
- font-size: clamp(2rem, 5vw, 3.5rem);
100
- line-height: 1;
101
- }
102
-
103
- .oc-hero-search,
104
- .oc-filters {
105
- border: 1px solid var(--oc-border);
106
- border-radius: 8px;
107
- background: var(--oc-panel);
108
- }
109
-
110
- .oc-hero-search {
111
- display: grid;
112
- grid-template-columns: 1fr auto;
113
- gap: 8px;
114
- padding: 8px;
115
- }
116
-
117
- input,
118
- select,
119
- button {
120
- font: inherit;
121
- }
122
-
123
- input,
124
- select {
125
- min-width: 0;
126
- width: 100%;
127
- box-sizing: border-box;
128
- border: 1px solid var(--oc-border);
129
- border-radius: 6px;
130
- background: #ffffff;
131
- color: var(--oc-text);
132
- padding: 10px 11px;
133
- }
134
-
135
- .oc-hero-search input {
136
- height: 44px;
137
- border: 0;
138
- padding-inline: 12px;
139
- }
140
-
141
- button,
142
- .oc-filter-actions a,
143
- .oc-card-actions a {
144
- display: inline-flex;
145
- align-items: center;
146
- justify-content: center;
147
- min-height: 36px;
148
- border: 1px solid var(--oc-text);
149
- border-radius: 6px;
150
- background: var(--oc-text);
151
- color: #ffffff;
152
- padding: 0 12px;
153
- font-weight: 650;
154
- text-decoration: none;
155
- }
156
-
157
- .oc-filter-actions a,
158
- .oc-card-actions a {
159
- border-color: var(--oc-border);
160
- background: var(--oc-panel);
161
- color: var(--oc-text);
162
- }
163
-
164
- .oc-stats {
165
- display: grid;
166
- grid-template-columns: repeat(4, minmax(0, 1fr));
167
- gap: 12px;
168
- margin: 0;
169
- }
170
-
171
- .oc-stats div,
172
- .oc-category-card,
173
- .oc-detail-grid section {
174
- border: 1px solid var(--oc-border);
175
- border-radius: 8px;
176
- background: var(--oc-panel);
177
- padding: 16px;
178
- }
179
-
180
- .oc-stats dt {
181
- color: var(--oc-muted);
182
- font-size: 0.75rem;
183
- }
184
-
185
- .oc-stats dd {
186
- margin: 4px 0 0;
187
- font-size: 1.6rem;
188
- font-weight: 800;
189
- }
190
-
191
- .oc-section {
192
- margin-top: 36px;
193
- }
194
-
195
- .oc-section-header,
196
- .oc-detail-header,
197
- .oc-results-header {
198
- display: flex;
199
- align-items: flex-start;
200
- justify-content: space-between;
201
- gap: 20px;
202
- }
203
-
204
- .oc-section-header h2,
205
- .oc-detail-grid h2 {
206
- margin: 0;
207
- }
208
-
209
- .oc-category-grid,
210
- .oc-grid {
211
- display: grid;
212
- grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
213
- gap: 14px;
214
- }
215
-
216
- .oc-category-card {
217
- display: flex;
218
- align-items: center;
219
- justify-content: space-between;
220
- text-decoration: none;
221
- }
222
-
223
- .oc-category-card strong {
224
- color: var(--oc-accent);
225
- }
226
-
227
- .oc-filters {
228
- display: grid;
229
- grid-template-columns: minmax(220px, 1.5fr) repeat(5, minmax(130px, 1fr));
230
- gap: 12px;
231
- margin: 24px 0;
232
- padding: 14px;
233
- }
234
-
235
- .oc-filters label span {
236
- display: block;
237
- margin-bottom: 5px;
238
- color: var(--oc-muted);
239
- font-size: 0.75rem;
240
- }
241
-
242
- .oc-filter-toggles,
243
- .oc-filter-actions {
244
- display: flex;
245
- flex-wrap: wrap;
246
- align-items: center;
247
- gap: 10px;
248
- grid-column: 1 / -1;
249
- }
250
-
251
- .oc-lenses,
252
- .oc-active-chips,
253
- .oc-pagination {
254
- display: flex;
255
- flex-wrap: wrap;
256
- align-items: center;
257
- gap: 8px;
258
- }
259
-
260
- .oc-lenses {
261
- margin-top: 18px;
262
- }
263
-
264
- .oc-lenses a,
265
- .oc-active-chips span,
266
- .oc-active-chips a,
267
- .oc-pagination a,
268
- .oc-pagination span {
269
- border: 1px solid var(--oc-border);
270
- border-radius: 6px;
271
- background: var(--oc-panel);
272
- padding: 7px 10px;
273
- color: var(--oc-muted);
274
- font-size: 0.8125rem;
275
- text-decoration: none;
276
- }
277
-
278
- .oc-lenses a[aria-current="page"] {
279
- border-color: var(--oc-text);
280
- background: var(--oc-text);
281
- color: #ffffff;
282
- }
283
-
284
- .oc-active-chips {
285
- margin: -8px 0 18px;
286
- }
287
-
288
- .oc-active-chips span {
289
- color: var(--oc-text);
290
- }
291
-
292
- .oc-pagination {
293
- justify-content: center;
294
- margin-top: 28px;
295
- }
296
-
297
- .oc-pagination a[aria-disabled="true"] {
298
- pointer-events: none;
299
- opacity: 0.45;
300
- }
301
-
302
- .oc-filter-toggles label {
303
- display: inline-flex;
304
- align-items: center;
305
- gap: 7px;
306
- color: var(--oc-text);
307
- font-size: 0.875rem;
308
- }
309
-
310
- .oc-filter-toggles input {
311
- width: auto;
312
- }
313
-
314
- .oc-card {
315
- border: 1px solid var(--oc-border);
316
- border-radius: 8px;
317
- background: var(--oc-panel);
318
- padding: 16px;
319
- }
320
-
321
- .oc-card-header {
322
- display: flex;
323
- align-items: flex-start;
324
- justify-content: space-between;
325
- gap: 16px;
326
- }
327
-
328
- .oc-card-title {
329
- margin: 0;
330
- font-size: 1rem;
331
- line-height: 1.25;
332
- }
333
-
334
- .oc-card-title a {
335
- color: inherit;
336
- text-decoration: none;
337
- }
338
-
339
- .oc-card-title a:hover {
340
- text-decoration: underline;
341
- }
342
-
343
- .oc-card-category,
344
- .oc-card-description,
345
- .oc-card-meta {
346
- color: var(--oc-muted);
347
- }
348
-
349
- .oc-card-actions {
350
- display: flex;
351
- flex-wrap: wrap;
352
- gap: 8px;
353
- margin-top: 14px;
354
- }
355
-
356
- .oc-card-actions a {
357
- min-height: 30px;
358
- font-size: 0.8125rem;
359
- }
360
-
361
- .oc-project-result[hidden] {
362
- display: none;
363
- }
364
-
365
- .oc-card-category {
366
- margin: 4px 0 0;
367
- font-size: 0.75rem;
368
- text-transform: uppercase;
369
- }
370
-
371
- .oc-card-description {
372
- margin: 12px 0 0;
373
- line-height: 1.55;
374
- }
375
-
376
- .oc-card-meta {
377
- display: flex;
378
- flex-wrap: wrap;
379
- gap: 8px 12px;
380
- margin-top: 12px;
381
- font-size: 0.8125rem;
382
- }
383
-
384
- .oc-tags {
385
- display: flex;
386
- flex-wrap: wrap;
387
- gap: 6px;
388
- padding: 0;
389
- margin: 12px 0 0;
390
- list-style: none;
391
- }
392
-
393
- .oc-tags li,
394
- .oc-health {
395
- border-radius: 999px;
396
- border: 1px solid var(--oc-border);
397
- padding: 3px 8px;
398
- font-size: 0.75rem;
399
- line-height: 1.2;
400
- }
401
-
402
- .oc-health {
403
- white-space: nowrap;
404
- text-transform: capitalize;
405
- }
406
-
407
- .oc-health-active,
408
- .oc-health-mature {
409
- border-color: color-mix(in srgb, var(--oc-accent), white 60%);
410
- color: var(--oc-accent);
411
- }
412
-
413
- .oc-health-stale,
414
- .oc-health-needs_review {
415
- border-color: color-mix(in srgb, var(--oc-warn), white 60%);
416
- color: var(--oc-warn);
417
- }
418
-
419
- .oc-health-inactive,
420
- .oc-health-archived {
421
- border-color: color-mix(in srgb, var(--oc-danger), white 60%);
422
- color: var(--oc-danger);
423
- }
424
-
425
- .oc-methodology,
426
- .oc-detail-grid {
427
- display: grid;
428
- grid-template-columns: 1fr 1fr;
429
- gap: 16px;
430
- }
431
-
432
- .oc-methodology {
433
- margin-top: 36px;
434
- border-top: 1px solid var(--oc-border);
435
- padding-top: 24px;
436
- }
437
-
438
- .oc-methodology p,
439
- .oc-methodology li,
440
- .oc-detail p,
441
- .oc-detail li {
442
- color: var(--oc-muted);
443
- line-height: 1.6;
444
- }
445
-
446
- .oc-detail-grid {
447
- margin-top: 24px;
448
- }
449
-
450
- .oc-detail-wide {
451
- grid-column: 1 / -1;
452
- }
453
-
454
- .oc-scores {
455
- display: flex;
456
- flex-wrap: wrap;
457
- gap: 12px 18px;
458
- margin: 14px 0 0;
459
- }
460
-
461
- .oc-scores div {
462
- display: inline-grid;
463
- grid-template-columns: auto auto auto;
464
- align-items: center;
465
- gap: 7px;
466
- }
467
-
468
- .oc-scores dt {
469
- color: var(--oc-muted);
470
- font-size: 0.8125rem;
471
- }
472
-
473
- .oc-score-value {
474
- margin: 0;
475
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
476
- }
477
-
478
- .oc-score-bar {
479
- display: flex;
480
- gap: 2px;
481
- width: 48px;
482
- margin: 0;
483
- }
484
-
485
- .oc-score-bar span {
486
- height: 7px;
487
- flex: 1;
488
- border-radius: 2px;
489
- background: var(--oc-border);
490
- }
491
-
492
- .oc-score-bar .is-filled {
493
- background: var(--oc-accent);
494
- }
495
-
496
- .oc-score-reasons,
497
- .oc-language-bars {
498
- display: grid;
499
- gap: 10px;
500
- margin: 18px 0 0;
1
+ /*
2
+ * Grove showcase design system.
3
+ *
4
+ * Public CSS API for `@grove-dev/astro`. Consumers (templates, examples)
5
+ * import this once at the top of their stack:
6
+ *
7
+ * import "@grove-dev/astro/styles.css";
8
+ *
9
+ * The `grove-` prefix below is the stable contract for the showcase
10
+ * component classes (`grove-section`, `grove-card`, `grove-btn`, etc.).
11
+ * Tailwind v4's `@theme` block declares the same tokens as CSS custom
12
+ * properties and Tailwind utility names — components can use either
13
+ * bare `grove-*` classes or Tailwind utilities like `text-ink-900`.
14
+ *
15
+ * Namespace history: earlier V0 drafts used a different (now
16
+ * removed) prefix. Only `grove-*` remains.
17
+ */
18
+
19
+ @theme {
20
+ /* ── Neutral ink scale (V1 default) ───────────────────────────── */
21
+ --color-ink-50: #fafafa;
22
+ --color-ink-100: #f4f4f5;
23
+ --color-ink-200: #e4e4e7;
24
+ --color-ink-300: #d4d4d8;
25
+ --color-ink-400: #a1a1aa;
26
+ --color-ink-500: #71717a;
27
+ --color-ink-600: #52525b;
28
+ --color-ink-700: #3f3f46;
29
+ --color-ink-800: #27272a;
30
+ --color-ink-900: #18181b;
31
+ --color-ink-950: #09090b;
32
+
33
+ /* ── Accent (interactive states) ─────────────────────────────── */
34
+ --color-accent: #1f6feb;
35
+ --color-accent-muted: #388bfd1a;
36
+
37
+ /* ── Status palettes (badges only) ───────────────────────────── */
38
+ --color-emerald-50: #ecfdf5;
39
+ --color-emerald-300: #6ee7b7;
40
+ --color-emerald-400: #34d399;
41
+ --color-emerald-700: #047857;
42
+ --color-emerald-800: #065f46;
43
+ --color-emerald-950: #022c22;
44
+
45
+ --color-orange-50: #fff7ed;
46
+ --color-orange-300: #fdba74;
47
+ --color-orange-400: #fb923c;
48
+ --color-orange-700: #c2410c;
49
+ --color-orange-800: #9a3412;
50
+ --color-orange-950: #431407;
51
+
52
+ --color-blue-50: #eff6ff;
53
+ --color-blue-300: #93c5fd;
54
+ --color-blue-400: #60a5fa;
55
+ --color-blue-700: #1d4ed8;
56
+ --color-blue-800: #1e40af;
57
+ --color-blue-950: #172554;
58
+
59
+ --color-amber-50: #fffbeb;
60
+ --color-amber-300: #fcd34d;
61
+ --color-amber-400: #fbbf24;
62
+ --color-amber-700: #b45309;
63
+ --color-amber-800: #92400e;
64
+ --color-amber-950: #451a03;
65
+
66
+ /* ── Font stacks ─────────────────────────────────────────────── */
67
+ --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
68
+ "Helvetica Neue", Arial, sans-serif;
69
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
70
+ "Liberation Mono", "Courier New", monospace;
71
+
72
+ /* ── Font size extensions (2xs) ──────────────────────────────── */
73
+ --text-2xs: 0.6875rem;
74
+ --text-2xs--line-height: 1rem;
75
+
76
+ /* ── Container widths (showcase rhythm) ──────────────────────── */
77
+ --container-container: 1140px;
78
+ --container-wide: 1400px;
79
+ --container-narrow: 720px;
80
+
81
+ /* ── Border radius scale ─────────────────────────────────────── */
82
+ --radius: 0.375rem;
83
+ --radius-lg: 0.5rem;
84
+ --radius-xl: 0.75rem;
85
+
86
+ /* ── Animations ──────────────────────────────────────────────── */
87
+ --animate-fade-in-up: fade-in-up 0.6s ease-out both;
88
+ --animate-fade-in: fade-in 0.8s ease-out both;
89
+ --animate-gradient-shift: gradient-shift 8s ease-in-out infinite;
90
+ --animate-subtle-bob: subtle-bob 3s ease-in-out infinite;
91
+ }
92
+
93
+ @keyframes fade-in-up {
94
+ 0% {
95
+ opacity: 0;
96
+ transform: translateY(8px);
97
+ }
98
+ 100% {
99
+ opacity: 1;
100
+ transform: translateY(0);
101
+ }
501
102
  }
502
103
 
503
- .oc-score-reasons div,
504
- .oc-language-bars div {
505
- display: grid;
506
- grid-template-columns: 140px 1fr;
507
- gap: 12px;
104
+ @keyframes fade-in {
105
+ 0% {
106
+ opacity: 0;
107
+ }
108
+ 100% {
109
+ opacity: 1;
110
+ }
508
111
  }
509
112
 
510
- .oc-score-reasons dt,
511
- .oc-language-bars dt {
512
- color: var(--oc-text);
513
- font-weight: 650;
113
+ @keyframes gradient-shift {
114
+ 0%,
115
+ 100% {
116
+ background-position: 0% 50%;
117
+ }
118
+ 50% {
119
+ background-position: 100% 50%;
120
+ }
514
121
  }
515
122
 
516
- .oc-score-reasons dd {
517
- margin: 0;
518
- color: var(--oc-muted);
123
+ @keyframes subtle-bob {
124
+ 0%,
125
+ 100% {
126
+ transform: translateY(0);
127
+ }
128
+ 50% {
129
+ transform: translateY(-2px);
130
+ }
519
131
  }
520
132
 
521
- .oc-curation-columns,
522
- .oc-repo-signals,
523
- .oc-submit-grid,
524
- .oc-two-col {
525
- display: grid;
526
- gap: 14px;
527
- }
133
+ /* ──────────────────────────────────────────────────────────────────
134
+ * Base
135
+ * ────────────────────────────────────────────────────────────────── */
528
136
 
529
- .oc-curation-columns,
530
- .oc-repo-signals {
531
- grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
532
- }
137
+ @layer base {
138
+ :root {
139
+ color-scheme: light dark;
140
+ }
533
141
 
534
- .oc-language-bars dd {
535
- height: 8px;
536
- margin: 7px 0 0;
537
- overflow: hidden;
538
- border-radius: 999px;
539
- background: var(--oc-border);
540
- }
142
+ html {
143
+ -webkit-text-size-adjust: 100%;
144
+ -webkit-font-smoothing: antialiased;
145
+ -moz-osx-font-smoothing: grayscale;
146
+ }
541
147
 
542
- .oc-language-bars span {
543
- display: block;
544
- height: 100%;
545
- border-radius: inherit;
546
- background: var(--oc-accent);
547
- }
148
+ body {
149
+ margin: 0;
150
+ background: #ffffff;
151
+ color: var(--color-ink-900);
152
+ font-family: var(--font-sans);
153
+ font-size: 15px;
154
+ line-height: 1.55;
155
+ }
548
156
 
549
- .oc-activity-bars {
550
- display: flex;
551
- align-items: end;
552
- gap: 5px;
553
- height: 56px;
554
- }
157
+ body.dark {
158
+ background: var(--color-ink-950);
159
+ color: var(--color-ink-100);
160
+ }
555
161
 
556
- .oc-activity-bars span {
557
- width: 12px;
558
- border-radius: 3px 3px 0 0;
559
- background: var(--oc-accent);
560
- }
162
+ a {
163
+ color: inherit;
164
+ text-decoration: none;
165
+ }
561
166
 
562
- .oc-submit-grid {
563
- grid-template-columns: minmax(0, 1fr) minmax(320px, 0.8fr);
564
- margin-top: 24px;
565
- }
167
+ /* Subtle selection */
168
+ ::selection {
169
+ background: var(--color-ink-200);
170
+ color: var(--color-ink-900);
171
+ }
172
+ .dark ::selection {
173
+ background: var(--color-ink-800);
174
+ color: var(--color-ink-100);
175
+ }
566
176
 
567
- .oc-submit-form,
568
- .oc-submit-preview {
569
- border: 1px solid var(--oc-border);
570
- border-radius: 8px;
571
- background: var(--oc-panel);
572
- padding: 16px;
573
- }
177
+ /* Slim, neutral scrollbar */
178
+ * {
179
+ scrollbar-width: thin;
180
+ scrollbar-color: var(--color-ink-300) transparent;
181
+ }
182
+ *::-webkit-scrollbar {
183
+ width: 8px;
184
+ height: 8px;
185
+ }
186
+ *::-webkit-scrollbar-thumb {
187
+ background: var(--color-ink-200);
188
+ border-radius: 4px;
189
+ }
190
+ .dark *::-webkit-scrollbar-thumb {
191
+ background: var(--color-ink-800);
192
+ }
574
193
 
575
- .oc-submit-form {
576
- display: grid;
577
- gap: 14px;
194
+ input,
195
+ select,
196
+ textarea,
197
+ button {
198
+ font: inherit;
199
+ }
578
200
  }
579
201
 
580
- .oc-two-col {
581
- grid-template-columns: 1fr 1fr;
582
- }
202
+ /* ──────────────────────────────────────────────────────────────────
203
+ * Component classes — shared by the showcase component library.
204
+ * Use these directly; you can also use the equivalent Tailwind
205
+ * utilities (text-ink-900, bg-white, …) and mix freely.
206
+ * ────────────────────────────────────────────────────────────────── */
583
207
 
584
- .oc-submit-form label span {
585
- display: block;
586
- margin-bottom: 5px;
587
- color: var(--oc-muted);
588
- font-size: 0.75rem;
589
- }
208
+ @layer components {
209
+ /* Section spacing — consistent vertical rhythm */
210
+ .grove-section {
211
+ padding-top: 3rem;
212
+ padding-bottom: 3rem;
213
+ }
214
+ @media (min-width: 640px) {
215
+ .grove-section {
216
+ padding-top: 4rem;
217
+ padding-bottom: 4rem;
218
+ }
219
+ }
590
220
 
591
- textarea {
592
- box-sizing: border-box;
593
- width: 100%;
594
- min-width: 0;
595
- border: 1px solid var(--oc-border);
596
- border-radius: 6px;
597
- padding: 10px 11px;
598
- color: var(--oc-text);
599
- font: inherit;
600
- }
221
+ .grove-section-tight {
222
+ padding-top: 2.5rem;
223
+ padding-bottom: 2.5rem;
224
+ }
225
+ @media (min-width: 640px) {
226
+ .grove-section-tight {
227
+ padding-top: 3rem;
228
+ padding-bottom: 3rem;
229
+ }
230
+ }
601
231
 
602
- .oc-submit-preview pre {
603
- min-height: 420px;
604
- overflow: auto;
605
- border: 1px solid var(--oc-border);
606
- border-radius: 8px;
607
- background: #f3f3ef;
608
- padding: 12px;
609
- font-size: 0.8125rem;
610
- }
232
+ /* Subtle card border + hover lift, used everywhere */
233
+ .grove-card {
234
+ border: 1px solid var(--color-ink-200);
235
+ background: #ffffff;
236
+ border-radius: var(--radius-lg);
237
+ transition:
238
+ border-color 150ms ease,
239
+ box-shadow 150ms ease,
240
+ background-color 150ms ease;
241
+ }
242
+ .dark .grove-card {
243
+ border-color: var(--color-ink-800);
244
+ background: var(--color-ink-950);
245
+ }
611
246
 
612
- .oc-muted {
613
- color: var(--oc-muted);
614
- }
247
+ .grove-card-hover:hover {
248
+ border-color: var(--color-ink-300);
249
+ background: rgba(244, 244, 245, 0.6);
250
+ box-shadow:
251
+ 0 1px 2px rgba(0, 0, 0, 0.04),
252
+ 0 4px 12px -2px rgba(0, 0, 0, 0.06);
253
+ }
254
+ .dark .grove-card-hover:hover {
255
+ border-color: var(--color-ink-700);
256
+ background: rgba(24, 24, 27, 0.4);
257
+ box-shadow:
258
+ 0 1px 2px rgba(0, 0, 0, 0.4),
259
+ 0 4px 12px -2px rgba(0, 0, 0, 0.3);
260
+ }
615
261
 
616
- .oc-link-list,
617
- .oc-signal-list {
618
- margin: 12px 0 0;
619
- padding-left: 18px;
620
- }
262
+ /* Pill badge — small, neutral */
263
+ .grove-badge {
264
+ display: inline-flex;
265
+ align-items: center;
266
+ gap: 0.25rem;
267
+ border-radius: 0.25rem;
268
+ border: 1px solid var(--color-ink-200);
269
+ background: var(--color-ink-50);
270
+ padding: 0.125rem 0.375rem;
271
+ font-size: var(--text-2xs);
272
+ line-height: var(--text-2xs--line-height);
273
+ font-weight: 500;
274
+ color: var(--color-ink-700);
275
+ }
276
+ .dark .grove-badge {
277
+ border-color: var(--color-ink-800);
278
+ background: rgba(24, 24, 27, 0.6);
279
+ color: var(--color-ink-300);
280
+ }
621
281
 
622
- .oc-fact-list {
623
- display: grid;
624
- gap: 10px;
625
- margin: 12px 0 0;
626
- }
282
+ .grove-badge-accent {
283
+ border-color: var(--color-ink-900);
284
+ background: var(--color-ink-900);
285
+ color: #ffffff;
286
+ }
287
+ .dark .grove-badge-accent {
288
+ border-color: var(--color-ink-100);
289
+ background: var(--color-ink-100);
290
+ color: var(--color-ink-900);
291
+ }
627
292
 
628
- .oc-fact-list div {
629
- display: flex;
630
- justify-content: space-between;
631
- gap: 16px;
632
- border-bottom: 1px solid var(--oc-border);
633
- padding-bottom: 8px;
634
- }
293
+ .grove-badge-new {
294
+ border-color: rgba(110, 231, 183, 0.6);
295
+ background: var(--color-emerald-50);
296
+ color: var(--color-emerald-800);
297
+ }
298
+ .dark .grove-badge-new {
299
+ border-color: rgba(6, 95, 70, 0.6);
300
+ background: rgba(2, 44, 34, 0.4);
301
+ color: var(--color-emerald-300);
302
+ }
635
303
 
636
- .oc-fact-list dt {
637
- color: var(--oc-muted);
638
- }
304
+ .grove-badge-hot {
305
+ border-color: rgba(253, 186, 116, 0.6);
306
+ background: var(--color-orange-50);
307
+ color: var(--color-orange-800);
308
+ }
309
+ .dark .grove-badge-hot {
310
+ border-color: rgba(154, 52, 18, 0.6);
311
+ background: rgba(67, 20, 7, 0.4);
312
+ color: var(--color-orange-300);
313
+ }
639
314
 
640
- .oc-fact-list dd {
641
- margin: 0;
642
- text-align: right;
643
- }
315
+ .grove-badge-mature {
316
+ border-color: rgba(147, 197, 253, 0.6);
317
+ background: var(--color-blue-50);
318
+ color: var(--color-blue-800);
319
+ }
320
+ .dark .grove-badge-mature {
321
+ border-color: rgba(30, 64, 175, 0.6);
322
+ background: rgba(23, 37, 84, 0.4);
323
+ color: var(--color-blue-300);
324
+ }
644
325
 
645
- .oc-source {
646
- font-size: 0.8125rem;
647
- }
326
+ .grove-badge-stale {
327
+ border-color: rgba(252, 211, 77, 0.6);
328
+ background: var(--color-amber-50);
329
+ color: var(--color-amber-800);
330
+ }
331
+ .dark .grove-badge-stale {
332
+ border-color: rgba(146, 64, 14, 0.6);
333
+ background: rgba(69, 26, 3, 0.4);
334
+ color: var(--color-amber-300);
335
+ }
648
336
 
649
- @media (max-width: 860px) {
650
- .oc-stats,
651
- .oc-filters,
652
- .oc-methodology,
653
- .oc-detail-grid,
654
- .oc-submit-grid,
655
- .oc-two-col {
656
- grid-template-columns: 1fr;
337
+ /* Buttons outline / ghost / primary */
338
+ .grove-btn {
339
+ display: inline-flex;
340
+ align-items: center;
341
+ justify-content: center;
342
+ gap: 0.375rem;
343
+ border-radius: var(--radius);
344
+ border: 1px solid transparent;
345
+ padding: 0.375rem 0.75rem;
346
+ font-size: 0.875rem;
347
+ line-height: 1.25rem;
348
+ font-weight: 500;
349
+ transition: color 150ms ease, background-color 150ms ease,
350
+ border-color 150ms ease;
351
+ text-decoration: none;
352
+ cursor: pointer;
657
353
  }
658
354
 
659
- .oc-section-header,
660
- .oc-detail-header,
661
- .oc-results-header {
662
- flex-direction: column;
355
+ .grove-btn-ghost {
356
+ color: var(--color-ink-700);
357
+ }
358
+ .grove-btn-ghost:hover {
359
+ background: var(--color-ink-100);
360
+ }
361
+ .dark .grove-btn-ghost {
362
+ color: var(--color-ink-300);
363
+ }
364
+ .dark .grove-btn-ghost:hover {
365
+ background: var(--color-ink-900);
663
366
  }
664
- }
665
367
 
666
- @media (max-width: 560px) {
667
- .oc-topbar {
668
- align-items: flex-start;
669
- flex-direction: column;
368
+ .grove-btn-outline {
369
+ border-color: var(--color-ink-200);
370
+ background: #ffffff;
371
+ color: var(--color-ink-900);
372
+ }
373
+ .grove-btn-outline:hover {
374
+ border-color: var(--color-ink-300);
375
+ background: var(--color-ink-50);
376
+ }
377
+ .dark .grove-btn-outline {
378
+ border-color: var(--color-ink-800);
379
+ background: var(--color-ink-950);
380
+ color: var(--color-ink-100);
381
+ }
382
+ .dark .grove-btn-outline:hover {
383
+ border-color: var(--color-ink-700);
384
+ background: rgba(24, 24, 27, 0.4);
670
385
  }
671
386
 
672
- .oc-hero-search {
673
- grid-template-columns: 1fr;
387
+ .grove-btn-primary {
388
+ border-color: var(--color-ink-900);
389
+ background: var(--color-ink-900);
390
+ color: #ffffff;
391
+ }
392
+ .grove-btn-primary:hover {
393
+ background: var(--color-ink-800);
394
+ }
395
+ .dark .grove-btn-primary {
396
+ border-color: var(--color-ink-100);
397
+ background: var(--color-ink-100);
398
+ color: var(--color-ink-900);
399
+ }
400
+ .dark .grove-btn-primary:hover {
401
+ background: #ffffff;
674
402
  }
675
403
  }