@cavebatsofware/riposte-pickers 0.1.0

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 (57) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +214 -0
  3. package/dist/chunk-6FAEMGAR.js +93 -0
  4. package/dist/chunk-6FAEMGAR.js.map +1 -0
  5. package/dist/chunk-6OZDKKEP.cjs +95 -0
  6. package/dist/chunk-6OZDKKEP.cjs.map +1 -0
  7. package/dist/chunk-7JL223UJ.cjs +84 -0
  8. package/dist/chunk-7JL223UJ.cjs.map +1 -0
  9. package/dist/chunk-A4OVAXLP.js +261 -0
  10. package/dist/chunk-A4OVAXLP.js.map +1 -0
  11. package/dist/chunk-ATS6MI5Q.js +3 -0
  12. package/dist/chunk-ATS6MI5Q.js.map +1 -0
  13. package/dist/chunk-GDYHLOSQ.cjs +268 -0
  14. package/dist/chunk-GDYHLOSQ.cjs.map +1 -0
  15. package/dist/chunk-IWUGV7HL.js +113 -0
  16. package/dist/chunk-IWUGV7HL.js.map +1 -0
  17. package/dist/chunk-LIGL56YJ.cjs +116 -0
  18. package/dist/chunk-LIGL56YJ.cjs.map +1 -0
  19. package/dist/chunk-U73YJG4C.cjs +4 -0
  20. package/dist/chunk-U73YJG4C.cjs.map +1 -0
  21. package/dist/chunk-XWM3AYYR.js +82 -0
  22. package/dist/chunk-XWM3AYYR.js.map +1 -0
  23. package/dist/i18n/index.cjs +192 -0
  24. package/dist/i18n/index.cjs.map +1 -0
  25. package/dist/i18n/index.d.cts +156 -0
  26. package/dist/i18n/index.d.ts +156 -0
  27. package/dist/i18n/index.js +189 -0
  28. package/dist/i18n/index.js.map +1 -0
  29. package/dist/index.cjs +52 -0
  30. package/dist/index.cjs.map +1 -0
  31. package/dist/index.d.cts +4 -0
  32. package/dist/index.d.ts +4 -0
  33. package/dist/index.js +7 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/language.cjs +18 -0
  36. package/dist/language.cjs.map +1 -0
  37. package/dist/language.d.cts +39 -0
  38. package/dist/language.d.ts +39 -0
  39. package/dist/language.js +5 -0
  40. package/dist/language.js.map +1 -0
  41. package/dist/shared.cjs +18 -0
  42. package/dist/shared.cjs.map +1 -0
  43. package/dist/shared.d.cts +29 -0
  44. package/dist/shared.d.ts +29 -0
  45. package/dist/shared.js +5 -0
  46. package/dist/shared.js.map +1 -0
  47. package/dist/theme.cjs +33 -0
  48. package/dist/theme.cjs.map +1 -0
  49. package/dist/theme.d.cts +54 -0
  50. package/dist/theme.d.ts +54 -0
  51. package/dist/theme.js +4 -0
  52. package/dist/theme.js.map +1 -0
  53. package/package.json +97 -0
  54. package/styles/index.css +3 -0
  55. package/styles/language.css +89 -0
  56. package/styles/palette.css +614 -0
  57. package/styles/picker.css +139 -0
@@ -0,0 +1,614 @@
1
+ /* Default riposte palette: colorway [data-theme] blocks plus the shared
2
+ * design tokens (typography, spacing, radius, shadow) the picker consumes.
3
+ * Override by shipping your own [data-theme="<id>"] blocks for your catalog.
4
+ */
5
+
6
+ /* ==========================================================================
7
+ Riposte Social design tokens.
8
+
9
+ Theme-driven colors are defined per `[data-theme="..."]` block. The
10
+ default block (`:root, [data-theme="forest"]`) is "Forest & Cream"; two
11
+ alternates (warm editorial, plum & apricot) override only the color
12
+ tokens. Typography, spacing, and radius are common across all themes.
13
+
14
+ The active theme is set as `<html data-theme="forest">` by ThemeContext
15
+ on mount; localStorage carries the choice across sessions.
16
+ ========================================================================== */
17
+
18
+ :root,
19
+ [data-theme="forest"] {
20
+ /* Forest & cream: deep green primary, sand background, copper accent. */
21
+ --color-bg: #f5efe4;
22
+ --color-surface: #fbf7ee;
23
+ --color-surface-2: #ede4d0;
24
+ --color-border: #e6d8b8;
25
+ --color-divider: #ede1cb;
26
+ --color-text: #2b2a26;
27
+ --color-muted: #6c6453;
28
+ --color-primary: #2d4a37;
29
+ --color-primary-hover: #1f3526;
30
+ --color-on-primary: #fbf7ee;
31
+ --color-link-underline: #a89867;
32
+ --color-avatar-bg: #2d4a37;
33
+ --color-avatar-fg: #fbf7ee;
34
+ --color-media-bg: #e5dabd;
35
+ --color-overlay: rgba(45, 74, 55, 0.55);
36
+
37
+ --color-badge-public-bg: #d6e2cd;
38
+ --color-badge-public-fg: #2d4a37;
39
+ --color-badge-commenters-bg: #e8dcc1;
40
+ --color-badge-commenters-fg: #6b4f1c;
41
+ --color-badge-posters-bg: #f0d6c3;
42
+ --color-badge-posters-fg: #8a3d11;
43
+
44
+ --color-danger: #b91c1c;
45
+ --color-danger-bg: #fef2f2;
46
+ --color-danger-border: #fecaca;
47
+ }
48
+
49
+ [data-theme="warm"] {
50
+ /* Warm editorial: deep navy primary, ivory base, terracotta accent. */
51
+ --color-bg: #f7f1e8;
52
+ --color-surface: #ffffff;
53
+ --color-surface-2: #f0e8da;
54
+ --color-border: #ebe0c9;
55
+ --color-divider: #ede1cb;
56
+ --color-text: #1f2937;
57
+ --color-muted: #6e6452;
58
+ --color-primary: #1d3557;
59
+ --color-primary-hover: #14253f;
60
+ --color-on-primary: #ffffff;
61
+ --color-link-underline: #b8a578;
62
+ --color-avatar-bg: #1d3557;
63
+ --color-avatar-fg: #ffffff;
64
+ --color-media-bg: #ede1cb;
65
+ --color-overlay: rgba(29, 53, 87, 0.55);
66
+
67
+ --color-badge-public-bg: #e6dccb;
68
+ --color-badge-public-fg: #1d3557;
69
+ --color-badge-commenters-bg: #ddd2bd;
70
+ --color-badge-commenters-fg: #4b3a1f;
71
+ --color-badge-posters-bg: rgba(194, 65, 12, 0.12);
72
+ --color-badge-posters-fg: #9a3412;
73
+
74
+ --color-danger: #b91c1c;
75
+ --color-danger-bg: #fef2f2;
76
+ --color-danger-border: #fecaca;
77
+ }
78
+
79
+ [data-theme="plum"] {
80
+ /* Plum & apricot: aubergine primary, cream surface, peach accents. */
81
+ --color-bg: #fbf6f0;
82
+ --color-surface: #ffffff;
83
+ --color-surface-2: #f5e9dc;
84
+ --color-border: #f0e2d0;
85
+ --color-divider: #f0e2d0;
86
+ --color-text: #2a1a2e;
87
+ --color-muted: #7a6c75;
88
+ --color-primary: #5b1f4d;
89
+ --color-primary-hover: #44153a;
90
+ --color-on-primary: #fbf6f0;
91
+ --color-link-underline: #c89070;
92
+ --color-avatar-bg: #5b1f4d;
93
+ --color-avatar-fg: #fbf6f0;
94
+ --color-media-bg: #f3e3d2;
95
+ --color-overlay: rgba(91, 31, 77, 0.55);
96
+
97
+ --color-badge-public-bg: #fbe2cf;
98
+ --color-badge-public-fg: #9c3f0a;
99
+ --color-badge-commenters-bg: #ead4e2;
100
+ --color-badge-commenters-fg: #5b1f4d;
101
+ --color-badge-posters-bg: #fae8b8;
102
+ --color-badge-posters-fg: #7a5106;
103
+
104
+ --color-danger: #b91c1c;
105
+ --color-danger-bg: #fef2f2;
106
+ --color-danger-border: #fecaca;
107
+ }
108
+
109
+ /* ==========================================================================
110
+ Dark companions for each colorway.
111
+
112
+ Each variant is hand-tuned (not a mechanical inversion) so the colorway
113
+ keeps its personality after dark. WCAG AA contrast (4.5:1 body / 3:1
114
+ large text) verified against `--color-bg`/`--color-surface` for every
115
+ text color and against `--color-primary` for `--color-on-primary`.
116
+ ========================================================================== */
117
+
118
+ [data-theme="forest-dark"] {
119
+ /* Deep forest at night: near-black green base, cream foreground, the
120
+ same primary hue but brighter so it reads on dark surfaces. */
121
+ --color-bg: #14201a;
122
+ --color-surface: #1a2922;
123
+ --color-surface-2: #22372d;
124
+ --color-border: #2c4135;
125
+ --color-divider: #25372d;
126
+ --color-text: #f1ead8;
127
+ --color-muted: #a89e85;
128
+ --color-primary: #7ec79a;
129
+ --color-primary-hover: #95d6ad;
130
+ --color-on-primary: #14201a;
131
+ --color-link-underline: #6b9b80;
132
+ --color-avatar-bg: #7ec79a;
133
+ --color-avatar-fg: #14201a;
134
+ --color-media-bg: #1f3328;
135
+ --color-overlay: rgba(126, 199, 154, 0.18);
136
+
137
+ --color-badge-public-bg: #1f3328;
138
+ --color-badge-public-fg: #b9e3c8;
139
+ --color-badge-commenters-bg: #3a2f1c;
140
+ --color-badge-commenters-fg: #e8c889;
141
+ --color-badge-posters-bg: #3a2419;
142
+ --color-badge-posters-fg: #e9b58f;
143
+
144
+ --color-danger: #f87171;
145
+ --color-danger-bg: #3a1818;
146
+ --color-danger-border: #6b2828;
147
+ }
148
+
149
+ [data-theme="warm-dark"] {
150
+ /* Warm editorial after dark: deep ink-navy base, ivory text, the navy
151
+ primary lifted toward a powdered blue. */
152
+ --color-bg: #131826;
153
+ --color-surface: #1a2236;
154
+ --color-surface-2: #232c44;
155
+ --color-border: #2e3a55;
156
+ --color-divider: #2a3349;
157
+ --color-text: #ece4d4;
158
+ --color-muted: #a59c87;
159
+ --color-primary: #8ab2dd;
160
+ --color-primary-hover: #a3c2e6;
161
+ --color-on-primary: #131826;
162
+ --color-link-underline: #7a8db3;
163
+ --color-avatar-bg: #8ab2dd;
164
+ --color-avatar-fg: #131826;
165
+ --color-media-bg: #1f293f;
166
+ --color-overlay: rgba(138, 178, 221, 0.18);
167
+
168
+ --color-badge-public-bg: #1f293f;
169
+ --color-badge-public-fg: #b9d2f0;
170
+ --color-badge-commenters-bg: #38301c;
171
+ --color-badge-commenters-fg: #e7c785;
172
+ --color-badge-posters-bg: #3a241a;
173
+ --color-badge-posters-fg: #ecb38e;
174
+
175
+ --color-danger: #f87171;
176
+ --color-danger-bg: #341919;
177
+ --color-danger-border: #5e2727;
178
+ }
179
+
180
+ [data-theme="plum-dark"] {
181
+ /* Plum & apricot after dark: deep aubergine base, peach text, primary
182
+ stays plum but pushed lighter for contrast. */
183
+ --color-bg: #1c1220;
184
+ --color-surface: #271a2c;
185
+ --color-surface-2: #34253a;
186
+ --color-border: #3f2d46;
187
+ --color-divider: #382740;
188
+ --color-text: #f3e1d3;
189
+ --color-muted: #ad9a9f;
190
+ --color-primary: #c884b6;
191
+ --color-primary-hover: #d99dc7;
192
+ --color-on-primary: #1c1220;
193
+ --color-link-underline: #b3829e;
194
+ --color-avatar-bg: #c884b6;
195
+ --color-avatar-fg: #1c1220;
196
+ --color-media-bg: #2c1f33;
197
+ --color-overlay: rgba(200, 132, 182, 0.18);
198
+
199
+ --color-badge-public-bg: #3a221d;
200
+ --color-badge-public-fg: #f0c6a8;
201
+ --color-badge-commenters-bg: #2e1f33;
202
+ --color-badge-commenters-fg: #e3b9d6;
203
+ --color-badge-posters-bg: #3a2e16;
204
+ --color-badge-posters-fg: #e6cf8b;
205
+
206
+ --color-danger: #f87171;
207
+ --color-danger-bg: #3a1717;
208
+ --color-danger-border: #5e2222;
209
+ }
210
+
211
+ /* ==========================================================================
212
+ Avernus & Clouds celestial dichotomy. Light "clouds" reads soft and
213
+ ethereal; dark "avernus" is volcanic, with ember-red primary and ash-
214
+ gold highlights. The two halves are intentionally opposite poles of
215
+ the same metaphor rather than light/dark inversions of each other.
216
+ ========================================================================== */
217
+
218
+ [data-theme="avernus"] {
219
+ /* Clouds: cloud-white base, midnight-blue text, sky-blue primary,
220
+ dawn-pink badge accents. */
221
+ --color-bg: #f5f7fb;
222
+ --color-surface: #ffffff;
223
+ --color-surface-2: #e9eef7;
224
+ --color-border: #d8e2f0;
225
+ --color-divider: #e2eaf3;
226
+ --color-text: #1a2438;
227
+ --color-muted: #5e6878;
228
+ --color-primary: #4f6dab;
229
+ --color-primary-hover: #3d588f;
230
+ --color-on-primary: #ffffff;
231
+ --color-link-underline: #a3b6d2;
232
+ --color-avatar-bg: #4f6dab;
233
+ --color-avatar-fg: #ffffff;
234
+ --color-media-bg: #e1e9f5;
235
+ --color-overlay: rgba(79, 109, 171, 0.15);
236
+
237
+ --color-badge-public-bg: #d6e0f2;
238
+ --color-badge-public-fg: #2c3e6d;
239
+ --color-badge-commenters-bg: #efd9e2;
240
+ --color-badge-commenters-fg: #8b3e58;
241
+ --color-badge-posters-bg: #efe2c9;
242
+ --color-badge-posters-fg: #7a591b;
243
+
244
+ --color-danger: #b91c1c;
245
+ --color-danger-bg: #fef2f2;
246
+ --color-danger-border: #fecaca;
247
+ }
248
+
249
+ [data-theme="avernus-dark"] {
250
+ /* Avernus: volcanic warm-black base lifted off pure black so ember
251
+ primary clears AA on it. Sky-rose haze for muted, lava-glow ember
252
+ for primary, copper underline. Tuned against BG3 Avernus reference. */
253
+ --color-bg: #18120f;
254
+ --color-surface: #221512;
255
+ --color-surface-2: #2f1a16;
256
+ --color-border: #9c563d;
257
+ --color-divider: #3a201a;
258
+ --color-text: #f3e2cf;
259
+ --color-muted: #b89381;
260
+ --color-primary: #ed5e3a;
261
+ --color-primary-hover: #f47049;
262
+ --color-on-primary: #170a06;
263
+ --color-link-underline: #c47a5a;
264
+ --color-avatar-bg: #ed5e3a;
265
+ --color-avatar-fg: #170a06;
266
+ --color-media-bg: #1f120e;
267
+ --color-overlay: rgba(237, 94, 58, 0.18);
268
+
269
+ --color-badge-public-bg: #2a1714;
270
+ --color-badge-public-fg: #f4b89c;
271
+ --color-badge-commenters-bg: #3a2618;
272
+ --color-badge-commenters-fg: #f0c98a;
273
+ --color-badge-posters-bg: #2e1a0e;
274
+ --color-badge-posters-fg: #e9a47a;
275
+
276
+ --color-danger: #f87171;
277
+ --color-danger-bg: #3a1717;
278
+ --color-danger-border: #6b2222;
279
+ }
280
+
281
+ /* ==========================================================================
282
+ Rocks & Minerals geological palette, earthy without being green.
283
+ Light "sandstone" is warm limestone with slate text and copper primary;
284
+ dark "granite" is cool charcoal with amber primary and faint mineral-
285
+ teal accents. Both halves draw from the same rock face, just lit
286
+ differently.
287
+ ========================================================================== */
288
+
289
+ [data-theme="mineral"] {
290
+ /* Sandstone: warm limestone bg, basalt text, copper primary. */
291
+ --color-bg: #f0ebe1;
292
+ --color-surface: #f8f5ed;
293
+ --color-surface-2: #e6dfd0;
294
+ --color-border: #d6cdba;
295
+ --color-divider: #ddd3be;
296
+ --color-text: #2d2925;
297
+ --color-muted: #6c6453;
298
+ --color-primary: #8e4a1f;
299
+ --color-primary-hover: #7a3f1a;
300
+ --color-on-primary: #f8f5ed;
301
+ --color-link-underline: #ad8d63;
302
+ --color-avatar-bg: #5e4b3a;
303
+ --color-avatar-fg: #f8f5ed;
304
+ --color-media-bg: #d8cdb6;
305
+ --color-overlay: rgba(160, 90, 44, 0.15);
306
+
307
+ --color-badge-public-bg: #d8cdb6;
308
+ --color-badge-public-fg: #4a3f2c;
309
+ --color-badge-commenters-bg: #e6d4ba;
310
+ --color-badge-commenters-fg: #6e5026;
311
+ --color-badge-posters-bg: #e8c8a8;
312
+ --color-badge-posters-fg: #7d3f17;
313
+
314
+ --color-danger: #b91c1c;
315
+ --color-danger-bg: #fef2f2;
316
+ --color-danger-border: #fecaca;
317
+ }
318
+
319
+ [data-theme="mineral-dark"] {
320
+ /* Granite: cool charcoal bg, sandstone text, amber-copper primary,
321
+ faint mineral-teal hint in the badge accents. */
322
+ --color-bg: #1c1c1f;
323
+ --color-surface: #25252a;
324
+ --color-surface-2: #2f2f35;
325
+ --color-border: #3a3a42;
326
+ --color-divider: #333339;
327
+ --color-text: #ebe2cf;
328
+ --color-muted: #9b9281;
329
+ --color-primary: #d6884a;
330
+ --color-primary-hover: #e3995d;
331
+ --color-on-primary: #1c1c1f;
332
+ --color-link-underline: #8a6f4d;
333
+ --color-avatar-bg: #d6884a;
334
+ --color-avatar-fg: #1c1c1f;
335
+ --color-media-bg: #28282d;
336
+ --color-overlay: rgba(214, 136, 74, 0.18);
337
+
338
+ --color-badge-public-bg: #28282d;
339
+ --color-badge-public-fg: #d6c9a8;
340
+ --color-badge-commenters-bg: #2c2820;
341
+ --color-badge-commenters-fg: #e7c382;
342
+ --color-badge-posters-bg: #1f2a2c;
343
+ --color-badge-posters-fg: #8fc4c4;
344
+
345
+ --color-danger: #f87171;
346
+ --color-danger-bg: #34191a;
347
+ --color-danger-border: #5e2424;
348
+ }
349
+
350
+ /* ==========================================================================
351
+ Accessibility colorways. Engineered against simulated color-vision so
352
+ every text and link surface clears WCAG 2.1 AA under the targeted
353
+ deficiency. Daltonia is anchored on the Okabe-Ito CVD-safe palette
354
+ (deep blue primary, vermillion danger); Tritan uses Paul Tol's
355
+ high-contrast palette (deep navy primary, red danger that retains
356
+ distinct chroma under blue-yellow shift); Achroma is luminance-only
357
+ for monovision and low-vision users.
358
+ ========================================================================== */
359
+
360
+ [data-theme="daltonia"] {
361
+ /* Red-green accessible (light): designed FOR users with R-G CVD,
362
+ not just compatible with them. Their working S cones perceive
363
+ the blue-yellow axis richly, so the palette lives there: warm
364
+ parchment bg, prussian blue primary, golden amber accents.
365
+ Aesthetic reference: vintage cartography, golden-hour lighting,
366
+ blue-and-gold heraldry. R-G axis is unused. */
367
+ --color-bg: #f5ecd5;
368
+ --color-surface: #fbf6e6;
369
+ --color-surface-2: #e8dbb8;
370
+ --color-border: #c9b890;
371
+ --color-divider: #d8c9a0;
372
+ --color-text: #0e1a30;
373
+ --color-muted: #4d5670;
374
+ --color-primary: #1c4a8c;
375
+ --color-primary-hover: #144078;
376
+ --color-on-primary: #fbf6e6;
377
+ --color-link-underline: #a06f1a;
378
+ --color-avatar-bg: #1c4a8c;
379
+ --color-avatar-fg: #fbf6e6;
380
+ --color-media-bg: #ebe1c5;
381
+ --color-overlay: rgba(28, 74, 140, 0.55);
382
+
383
+ --color-badge-public-bg: #d4dde8;
384
+ --color-badge-public-fg: #142a52;
385
+ --color-badge-commenters-bg: #f0deb0;
386
+ --color-badge-commenters-fg: #6e4c10;
387
+ --color-badge-posters-bg: #ead8a8;
388
+ --color-badge-posters-fg: #2a3d6c;
389
+
390
+ --color-danger: #8e3c00;
391
+ --color-danger-bg: #fde6c8;
392
+ --color-danger-border: #e8c790;
393
+ }
394
+
395
+ [data-theme="daltonia-dark"] {
396
+ /* Red-green accessible (dark): deep midnight blue with golden
397
+ lamplight. Bright amber primary glows on a near-black blue base;
398
+ warm cream text. The "blue night, gold lamp" identity reads
399
+ vivid to deuteranopes/protanopes via the blue-yellow axis their
400
+ working S cones still resolve at full saturation. */
401
+ --color-bg: #0a1428;
402
+ --color-surface: #142440;
403
+ --color-surface-2: #1d2f50;
404
+ --color-border: #3a4d70;
405
+ --color-divider: #1f2a44;
406
+ --color-text: #f0e8d0;
407
+ --color-muted: #a89a7a;
408
+ --color-primary: #e8b03a;
409
+ --color-primary-hover: #f0c45a;
410
+ --color-on-primary: #0a1428;
411
+ --color-link-underline: #c4942a;
412
+ --color-avatar-bg: #e8b03a;
413
+ --color-avatar-fg: #0a1428;
414
+ --color-media-bg: #142440;
415
+ --color-overlay: rgba(232, 176, 58, 0.18);
416
+
417
+ --color-badge-public-bg: #1d2f50;
418
+ --color-badge-public-fg: #e8c870;
419
+ --color-badge-commenters-bg: #3a2e14;
420
+ --color-badge-commenters-fg: #f0c870;
421
+ --color-badge-posters-bg: #1a3050;
422
+ --color-badge-posters-fg: #d8e0f0;
423
+
424
+ --color-danger: #ff9a4a;
425
+ --color-danger-bg: #2e1808;
426
+ --color-danger-border: #6e3520;
427
+ }
428
+
429
+ [data-theme="tritan"] {
430
+ /* Blue-yellow accessible (light): forest-floor aesthetic of moss,
431
+ berry, and bark. Tritans have working L+M cones so they perceive
432
+ the red-green axis richly; they LACK S cones so warm yellows
433
+ shift toward pink in their perception. Earlier draft used warm
434
+ cream + amber + coral accents which all collapsed into a single
435
+ "warm pink" zone for the target user, killing perceptual
436
+ variety. This palette pivots to neutral warm-stone bg + deep
437
+ forest primary + red/green/bark badges so the user gets four
438
+ distinct perceptual zones (green, red, brown, neutral) rather
439
+ than one warm zone repeated. Bg uses R = G to avoid any residual
440
+ pink shift under tritanopia: with no S channel to balance, even
441
+ a slight R-over-G bias collapses into a warm-pink wash. Sits as
442
+ a defensible neutral pending validation with actual tritan
443
+ users; cooler-sage and warmer-paper alternatives are equally
444
+ plausible aesthetic directions but require user feedback to
445
+ pick between. */
446
+ --color-bg: #e6e8df;
447
+ --color-surface: #f0f2e8;
448
+ --color-surface-2: #d6d9ce;
449
+ --color-border: #c0c4ae;
450
+ --color-divider: #ccd0be;
451
+ --color-text: #1a2818;
452
+ --color-muted: #525c44;
453
+ --color-primary: #2c5538;
454
+ --color-primary-hover: #234628;
455
+ --color-on-primary: #f0f2e8;
456
+ --color-link-underline: #8a2818;
457
+ --color-avatar-bg: #2c5538;
458
+ --color-avatar-fg: #f0f2e8;
459
+ --color-media-bg: #d6d9ce;
460
+ --color-overlay: rgba(44, 85, 56, 0.55);
461
+
462
+ --color-badge-public-bg: #d0e0c8;
463
+ --color-badge-public-fg: #1f3a26;
464
+ --color-badge-commenters-bg: #f0d2d2;
465
+ --color-badge-commenters-fg: #6e1818;
466
+ --color-badge-posters-bg: #d8d8c8;
467
+ --color-badge-posters-fg: #4a3520;
468
+
469
+ --color-danger: #8e1818;
470
+ --color-danger-bg: #fde0e0;
471
+ --color-danger-border: #e8b5b5;
472
+ }
473
+
474
+ [data-theme="tritan-dark"] {
475
+ /* Blue-yellow accessible (dark): deep forest at night with autumn
476
+ fire. Coral-red primary glows on a near-black green base; warm
477
+ cream text. Reads vivid to tritans via the red-green axis their
478
+ working L+M cones still resolve at full saturation. */
479
+ --color-bg: #0d1a12;
480
+ --color-surface: #152a1c;
481
+ --color-surface-2: #1f3e28;
482
+ --color-border: #3a5240;
483
+ --color-divider: #234028;
484
+ --color-text: #f0e8d0;
485
+ --color-muted: #8c9c70;
486
+ --color-primary: #dd7866;
487
+ --color-primary-hover: #e88876;
488
+ --color-on-primary: #0d1a12;
489
+ --color-link-underline: #d68c7a;
490
+ --color-avatar-bg: #dd7866;
491
+ --color-avatar-fg: #0d1a12;
492
+ --color-media-bg: #152a1c;
493
+ --color-overlay: rgba(221, 120, 102, 0.18);
494
+
495
+ --color-badge-public-bg: #2a4a30;
496
+ --color-badge-public-fg: #c8e0c0;
497
+ --color-badge-commenters-bg: #4a1e1e;
498
+ --color-badge-commenters-fg: #f0c0a0;
499
+ --color-badge-posters-bg: #3a2a14;
500
+ --color-badge-posters-fg: #e8c79a;
501
+
502
+ --color-danger: #ff6655;
503
+ --color-danger-bg: #3d1818;
504
+ --color-danger-border: #6a2a2a;
505
+ }
506
+
507
+ [data-theme="achroma"] {
508
+ /* High contrast (light): pure black-on-white core for monovision
509
+ and low-vision users. Borders are load-bearing here (full black)
510
+ rather than the soft decorative aesthetic of the other themes.
511
+ Deep blue primary keeps a single saturated accent that also
512
+ reads as a distinct dark luminance under monochromacy. Badges
513
+ differ in luminance step rather than hue so they remain
514
+ distinguishable when all hue is collapsed. */
515
+ --color-bg: #ffffff;
516
+ --color-surface: #ffffff;
517
+ --color-surface-2: #f0f0f0;
518
+ --color-border: #000000;
519
+ --color-divider: #cccccc;
520
+ --color-text: #000000;
521
+ --color-muted: #404040;
522
+ --color-primary: #0000aa;
523
+ --color-primary-hover: #000077;
524
+ --color-on-primary: #ffffff;
525
+ --color-link-underline: #000000;
526
+ --color-avatar-bg: #000000;
527
+ --color-avatar-fg: #ffffff;
528
+ --color-media-bg: #f0f0f0;
529
+ --color-overlay: rgba(0, 0, 0, 0.5);
530
+
531
+ --color-badge-public-bg: #000000;
532
+ --color-badge-public-fg: #ffffff;
533
+ --color-badge-commenters-bg: #404040;
534
+ --color-badge-commenters-fg: #ffffff;
535
+ --color-badge-posters-bg: #666666;
536
+ --color-badge-posters-fg: #ffffff;
537
+
538
+ --color-danger: #cc0000;
539
+ --color-danger-bg: #ffe6e6;
540
+ --color-danger-border: #cc0000;
541
+ }
542
+
543
+ [data-theme="achroma-dark"] {
544
+ /* High contrast (dark): pure white-on-black inverse. Sky-blue
545
+ primary lifted for dark mode. Badges step through three light
546
+ luminances (white, light grey, mid grey) so monochromat vision
547
+ can still rank them. */
548
+ --color-bg: #000000;
549
+ --color-surface: #0a0a0a;
550
+ --color-surface-2: #1a1a1a;
551
+ --color-border: #ffffff;
552
+ --color-divider: #404040;
553
+ --color-text: #ffffff;
554
+ --color-muted: #cccccc;
555
+ --color-primary: #66aaff;
556
+ --color-primary-hover: #99c4ff;
557
+ --color-on-primary: #000000;
558
+ --color-link-underline: #ffffff;
559
+ --color-avatar-bg: #ffffff;
560
+ --color-avatar-fg: #000000;
561
+ --color-media-bg: #1a1a1a;
562
+ --color-overlay: rgba(255, 255, 255, 0.3);
563
+
564
+ --color-badge-public-bg: #ffffff;
565
+ --color-badge-public-fg: #000000;
566
+ --color-badge-commenters-bg: #cccccc;
567
+ --color-badge-commenters-fg: #000000;
568
+ --color-badge-posters-bg: #999999;
569
+ --color-badge-posters-fg: #000000;
570
+
571
+ --color-danger: #ff6666;
572
+ --color-danger-bg: #4d0000;
573
+ --color-danger-border: #ff6666;
574
+ }
575
+
576
+ /* Static tokens, identical across themes. Both stacks anchor on
577
+ webfonts loaded from index.html so the page renders predictably
578
+ regardless of what's installed locally:
579
+ Inter -> Latin
580
+ JetBrains Mono -> monospace
581
+ Noto Sans SC -> Simplified Chinese
582
+ Noto Color Emoji -> emoji glyphs
583
+ Each Google `@font-face` carries its own `unicode-range`, so the
584
+ browser picks the right family per code point. The generic family
585
+ at the tail is the offline / CDN-blocked catch. */
586
+ :root {
587
+ --font-body: 'Inter', 'Noto Sans SC', 'Noto Color Emoji', sans-serif;
588
+ --font-mono: 'JetBrains Mono', 'Noto Sans SC', 'Noto Color Emoji',
589
+ monospace;
590
+
591
+ --font-size-xs: 0.75rem;
592
+ --font-size-sm: 0.875rem;
593
+ --font-size-base: 1rem;
594
+ --font-size-lg: 1.125rem;
595
+ --font-size-xl: 1.25rem;
596
+ --font-size-2xl: 1.5rem;
597
+ --font-size-3xl: 2rem;
598
+
599
+ --spacing-1: 0.25rem;
600
+ --spacing-2: 0.5rem;
601
+ --spacing-3: 0.75rem;
602
+ --spacing-4: 1rem;
603
+ --spacing-6: 1.5rem;
604
+ --spacing-8: 2rem;
605
+ --spacing-12: 3rem;
606
+
607
+ --radius-sm: 0.25rem;
608
+ --radius-md: 0.375rem;
609
+ --radius-lg: 0.625rem;
610
+ --radius-full: 999px;
611
+
612
+ --shadow-card: 0 1px 0 rgba(0, 0, 0, 0.04);
613
+ --shadow-popover: 0 8px 24px -8px rgba(0, 0, 0, 0.18);
614
+ }