minecodex 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 (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -0
  3. package/apps/dashboard/app.js +387 -0
  4. package/apps/dashboard/favicon.svg +18 -0
  5. package/apps/dashboard/index.html +70 -0
  6. package/apps/dashboard/styles.css +297 -0
  7. package/features/images/README.md +106 -0
  8. package/features/images/codex-feature.json +24 -0
  9. package/features/images/src/http-server.mjs +302 -0
  10. package/features/images/src/image-library.mjs +582 -0
  11. package/features/images/src/main.mjs +52 -0
  12. package/features/images/src/prompt-index.mjs +182 -0
  13. package/features/images/src/save-as.mjs +40 -0
  14. package/features/images/src/thread-metadata.mjs +93 -0
  15. package/features/images/web/app.js +1045 -0
  16. package/features/images/web/index.html +162 -0
  17. package/features/images/web/styles.css +994 -0
  18. package/features/model-slider/README.md +30 -0
  19. package/features/model-slider/THIRD_PARTY_NOTICES.md +24 -0
  20. package/features/model-slider/assets/providers/anthropic.svg +1 -0
  21. package/features/model-slider/assets/providers/deepseek.svg +1 -0
  22. package/features/model-slider/assets/providers/gemini.svg +1 -0
  23. package/features/model-slider/assets/providers/grok.svg +1 -0
  24. package/features/model-slider/assets/providers/hunyuan.svg +1 -0
  25. package/features/model-slider/assets/providers/kimi.svg +1 -0
  26. package/features/model-slider/assets/providers/minimax.svg +1 -0
  27. package/features/model-slider/assets/providers/openai.svg +1 -0
  28. package/features/model-slider/assets/providers/qwen.svg +1 -0
  29. package/features/model-slider/assets/providers/xiaomimimo.svg +1 -0
  30. package/features/model-slider/assets/providers/zhipu.svg +1 -0
  31. package/features/model-slider/assets/ui/sparkles.svg +18 -0
  32. package/features/model-slider/assets/ui/star-off.svg +17 -0
  33. package/features/model-slider/assets/ui/star.svg +15 -0
  34. package/features/model-slider/codex-feature.json +56 -0
  35. package/features/model-slider/vendor/cc-switch-LICENSE +21 -0
  36. package/features/model-slider/vendor/lucide-LICENSE +35 -0
  37. package/features/notes/README.md +106 -0
  38. package/features/notes/assets/icons/circle.svg +15 -0
  39. package/features/notes/assets/icons/ellipsis.svg +17 -0
  40. package/features/notes/assets/icons/external-link.svg +17 -0
  41. package/features/notes/assets/icons/list-todo.svg +19 -0
  42. package/features/notes/assets/icons/message-square-quote.svg +17 -0
  43. package/features/notes/assets/icons/paperclip.svg +15 -0
  44. package/features/notes/assets/icons/star-off.svg +17 -0
  45. package/features/notes/assets/icons/star.svg +15 -0
  46. package/features/notes/assets/icons/sticky-note.svg +16 -0
  47. package/features/notes/assets/icons/trash-2.svg +19 -0
  48. package/features/notes/codex-feature.json +90 -0
  49. package/features/notes/src/http-server.mjs +541 -0
  50. package/features/notes/src/main.mjs +54 -0
  51. package/features/notes/src/product.mjs +771 -0
  52. package/features/notes/web/app.js +1495 -0
  53. package/features/notes/web/codex-artifact-document.svg +1 -0
  54. package/features/notes/web/codex-attachment.svg +1 -0
  55. package/features/notes/web/codex-build.svg +1 -0
  56. package/features/notes/web/codex-code.svg +1 -0
  57. package/features/notes/web/codex-cplusplus.svg +1 -0
  58. package/features/notes/web/codex-css.svg +1 -0
  59. package/features/notes/web/codex-document.svg +1 -0
  60. package/features/notes/web/codex-file.svg +1 -0
  61. package/features/notes/web/codex-folder.svg +1 -0
  62. package/features/notes/web/codex-hashes.svg +1 -0
  63. package/features/notes/web/codex-html.svg +1 -0
  64. package/features/notes/web/codex-image.svg +1 -0
  65. package/features/notes/web/codex-java.svg +1 -0
  66. package/features/notes/web/codex-javascript.svg +1 -0
  67. package/features/notes/web/codex-json.svg +1 -0
  68. package/features/notes/web/codex-notebook.svg +1 -0
  69. package/features/notes/web/codex-pdf.svg +1 -0
  70. package/features/notes/web/codex-pencil.svg +3 -0
  71. package/features/notes/web/codex-php.svg +1 -0
  72. package/features/notes/web/codex-plus.svg +3 -0
  73. package/features/notes/web/codex-presentation.svg +1 -0
  74. package/features/notes/web/codex-python.svg +1 -0
  75. package/features/notes/web/codex-react.svg +1 -0
  76. package/features/notes/web/codex-rust.svg +1 -0
  77. package/features/notes/web/codex-shell.svg +1 -0
  78. package/features/notes/web/codex-skill.svg +1 -0
  79. package/features/notes/web/codex-spreadsheet.svg +1 -0
  80. package/features/notes/web/codex-task.svg +3 -0
  81. package/features/notes/web/codex-terminal.svg +1 -0
  82. package/features/notes/web/codex-toml.svg +1 -0
  83. package/features/notes/web/codex-typescript.svg +1 -0
  84. package/features/notes/web/codex-view-all.svg +3 -0
  85. package/features/notes/web/index.html +15 -0
  86. package/features/notes/web/styles.css +1155 -0
  87. package/package.json +67 -0
  88. package/packages/cli/bin/mcx.mjs +7 -0
  89. package/packages/cli/src/browser-exchange.mjs +31 -0
  90. package/packages/cli/src/commands.mjs +389 -0
  91. package/packages/cli/src/config.mjs +101 -0
  92. package/packages/cli/src/control-server.mjs +371 -0
  93. package/packages/cli/src/npm-adapter.mjs +40 -0
  94. package/packages/cli/src/paths.mjs +33 -0
  95. package/packages/cli/src/platform.mjs +368 -0
  96. package/packages/cli/src/runtime-manager.mjs +338 -0
  97. package/packages/runtime-host/README.md +171 -0
  98. package/packages/runtime-host/src/codex-runtime.mjs +4311 -0
  99. package/packages/runtime-host/src/feature-registry.mjs +827 -0
  100. package/packages/runtime-host/src/main.mjs +98 -0
  101. package/packages/runtime-host/src/pid-file.mjs +23 -0
@@ -0,0 +1,994 @@
1
+ :root {
2
+ color-scheme: light;
3
+ --codex-base-accent: #339cff;
4
+ --color-token-main-surface-primary: #fff;
5
+ --color-token-bg-primary: #f9f9f9;
6
+ --color-token-bg-secondary: color-mix(in srgb, #f9f9f9 92%, transparent);
7
+ --color-background-elevated-primary-opaque: #fff;
8
+ --color-background-panel: #f5f5f5;
9
+ --color-background-primary-solid: #1a1c1f;
10
+ --color-text-primary-solid: #fff;
11
+ --color-background-button-secondary: color-mix(in oklab, #1a1c1f 5%, transparent);
12
+ --color-background-button-secondary-hover: color-mix(in oklab, #1a1c1f 8%, transparent);
13
+ --color-background-button-tertiary-hover: color-mix(in oklab, #1a1c1f 7%, transparent);
14
+ --color-text-foreground: #1a1c1f;
15
+ --color-text-foreground-secondary: color-mix(in oklab, #1a1c1f 70%, transparent);
16
+ --color-text-foreground-tertiary: color-mix(in oklab, #1a1c1f 50%, transparent);
17
+ --color-icon-tertiary: rgb(13 13 13 / 48.4%);
18
+ --color-text-accent: #087ccf;
19
+ --color-border: color-mix(in oklab, #1a1c1f 8%, transparent);
20
+ --color-border-heavy: color-mix(in oklab, #1a1c1f 14%, transparent);
21
+ --color-border-focus: #339cff;
22
+ --color-token-scrollbar-slider-background: var(--color-border);
23
+ --color-token-scrollbar-slider-hover-background: var(--color-border-heavy);
24
+ --color-token-scrollbar-slider-active-background: var(--color-border-heavy);
25
+ --color-token-list-hover-background: color-mix(in oklab, #1a1c1f 5%, transparent);
26
+ --color-token-input-background: #f3f3f3;
27
+ --color-token-input-border: color-mix(in oklab, #1a1c1f 14%, transparent);
28
+ --color-token-input-foreground: #1a1c1f;
29
+ --color-token-input-placeholder-foreground: color-mix(in oklab, #1a1c1f 50%, transparent);
30
+ --font-sans-default: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
31
+ --default-mono-font-family: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, monospace;
32
+ --text-heading-md: 20px;
33
+ --text-heading-sm: 18px;
34
+ --text-base: 14px;
35
+ --text-sm: 13px;
36
+ --text-xs: 12px;
37
+ --radius-md: 10px;
38
+ --radius-lg: 12.5px;
39
+ --radius-xl: 15px;
40
+ --shadow-xl: 0 8px 30px rgb(0 0 0 / 14%);
41
+ font-family: var(--font-sans-default);
42
+ background: var(--color-token-main-surface-primary);
43
+ color: var(--color-text-foreground);
44
+ }
45
+
46
+ :root[data-theme="dark"] {
47
+ color-scheme: dark;
48
+ --color-token-main-surface-primary: #181818;
49
+ --color-token-bg-primary: #141414;
50
+ --color-token-bg-secondary: color-mix(in srgb, #141414 92%, transparent);
51
+ --color-background-elevated-primary-opaque: #363636;
52
+ --color-background-panel: #232323;
53
+ --color-background-primary-solid: #fff;
54
+ --color-text-primary-solid: #2d2d2d;
55
+ --color-background-button-secondary: rgb(255 255 255 / 5.2%);
56
+ --color-background-button-secondary-hover: rgb(255 255 255 / 7.8%);
57
+ --color-background-button-tertiary-hover: rgb(255 255 255 / 6.8%);
58
+ --color-text-foreground: #fff;
59
+ --color-text-foreground-secondary: rgb(255 255 255 / 71%);
60
+ --color-text-foreground-tertiary: rgb(255 255 255 / 49.8%);
61
+ --color-icon-tertiary: color-mix(in oklab, #fff 50%, transparent);
62
+ --color-text-accent: #83c3ff;
63
+ --color-border: rgb(255 255 255 / 8.4%);
64
+ --color-border-heavy: rgb(255 255 255 / 15.6%);
65
+ --color-border-focus: rgb(131 195 255 / 76%);
66
+ --color-token-list-hover-background: rgb(255 255 255 / 7.8%);
67
+ --color-token-input-background: rgb(45 45 45 / 96%);
68
+ --color-token-input-border: rgb(255 255 255 / 15.6%);
69
+ --color-token-input-foreground: #fff;
70
+ --color-token-input-placeholder-foreground: rgb(255 255 255 / 49.8%);
71
+ }
72
+
73
+ @media (prefers-color-scheme: dark) {
74
+ :root:not([data-theme]) {
75
+ color-scheme: dark;
76
+ --color-token-main-surface-primary: #181818;
77
+ --color-token-bg-primary: #141414;
78
+ --color-token-bg-secondary: color-mix(in srgb, #141414 92%, transparent);
79
+ --color-background-elevated-primary-opaque: #363636;
80
+ --color-background-panel: #232323;
81
+ --color-background-primary-solid: #fff;
82
+ --color-text-primary-solid: #2d2d2d;
83
+ --color-background-button-secondary: rgb(255 255 255 / 5.2%);
84
+ --color-background-button-secondary-hover: rgb(255 255 255 / 7.8%);
85
+ --color-background-button-tertiary-hover: rgb(255 255 255 / 6.8%);
86
+ --color-text-foreground: #fff;
87
+ --color-text-foreground-secondary: rgb(255 255 255 / 71%);
88
+ --color-text-foreground-tertiary: rgb(255 255 255 / 49.8%);
89
+ --color-icon-tertiary: color-mix(in oklab, #fff 50%, transparent);
90
+ --color-text-accent: #83c3ff;
91
+ --color-border: rgb(255 255 255 / 8.4%);
92
+ --color-border-heavy: rgb(255 255 255 / 15.6%);
93
+ --color-border-focus: rgb(131 195 255 / 76%);
94
+ --color-token-list-hover-background: rgb(255 255 255 / 7.8%);
95
+ --color-token-input-background: rgb(45 45 45 / 96%);
96
+ --color-token-input-border: rgb(255 255 255 / 15.6%);
97
+ --color-token-input-foreground: #fff;
98
+ --color-token-input-placeholder-foreground: rgb(255 255 255 / 49.8%);
99
+ }
100
+ }
101
+
102
+ * { box-sizing: border-box; }
103
+
104
+ html,
105
+ body {
106
+ min-height: 100%;
107
+ margin: 0;
108
+ background: var(--color-token-main-surface-primary);
109
+ }
110
+
111
+ body {
112
+ min-width: 320px;
113
+ color: var(--color-text-foreground);
114
+ font: 400 var(--text-base)/1.5 var(--font-sans-default);
115
+ -webkit-font-smoothing: antialiased;
116
+ }
117
+
118
+ button,
119
+ input { font: inherit; }
120
+
121
+ button,
122
+ a { -webkit-tap-highlight-color: transparent; }
123
+
124
+ button { color: inherit; }
125
+
126
+ .sr-only {
127
+ position: absolute;
128
+ width: 1px;
129
+ height: 1px;
130
+ padding: 0;
131
+ margin: -1px;
132
+ overflow: hidden;
133
+ clip: rect(0, 0, 0, 0);
134
+ white-space: nowrap;
135
+ border: 0;
136
+ }
137
+
138
+ .library-shell {
139
+ position: relative;
140
+ width: 100vw;
141
+ height: 100vh;
142
+ display: flex;
143
+ overflow: hidden;
144
+ background: var(--color-token-main-surface-primary);
145
+ }
146
+
147
+ .library-pane {
148
+ width: 100%;
149
+ min-width: 0;
150
+ flex: 0 0 auto;
151
+ display: flex;
152
+ flex-direction: column;
153
+ overflow: hidden;
154
+ container-type: inline-size;
155
+ background: var(--color-token-main-surface-primary);
156
+ transform: translateX(0);
157
+ transition: transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
158
+ }
159
+
160
+ .library-scroll {
161
+ min-height: 0;
162
+ flex: 1 1 auto;
163
+ overflow-y: auto;
164
+ overscroll-behavior: contain;
165
+ scrollbar-gutter: stable;
166
+ }
167
+
168
+ .library-scroll,
169
+ .drawer-scroll,
170
+ .source-menu {
171
+ scrollbar-color: var(--color-token-scrollbar-slider-background) transparent;
172
+ }
173
+
174
+ .library-scroll::-webkit-scrollbar { width: 12px; }
175
+ .library-scroll::-webkit-scrollbar-track { background: transparent; }
176
+
177
+ .library-scroll::-webkit-scrollbar-thumb {
178
+ min-height: 48px;
179
+ border: 3px solid transparent;
180
+ border-radius: 999px;
181
+ background-clip: padding-box;
182
+ }
183
+
184
+ .library-scroll::-webkit-scrollbar-thumb,
185
+ .drawer-scroll::-webkit-scrollbar-thumb,
186
+ .source-menu::-webkit-scrollbar-thumb {
187
+ background-color: var(--color-token-scrollbar-slider-background);
188
+ }
189
+
190
+ .library-scroll::-webkit-scrollbar-thumb:hover,
191
+ .drawer-scroll::-webkit-scrollbar-thumb:hover,
192
+ .source-menu::-webkit-scrollbar-thumb:hover {
193
+ background-color: var(--color-token-scrollbar-slider-hover-background);
194
+ }
195
+
196
+ .library-scroll::-webkit-scrollbar-thumb:active,
197
+ .drawer-scroll::-webkit-scrollbar-thumb:active,
198
+ .source-menu::-webkit-scrollbar-thumb:active {
199
+ background-color: var(--color-token-scrollbar-slider-active-background);
200
+ }
201
+
202
+ .library-header,
203
+ .drawer-header {
204
+ height: 46px;
205
+ display: flex;
206
+ align-items: center;
207
+ border-bottom: 1px solid var(--color-border);
208
+ background: var(--color-token-main-surface-primary);
209
+ }
210
+
211
+ .library-header {
212
+ flex: 0 0 auto;
213
+ z-index: 4;
214
+ justify-content: space-between;
215
+ padding: 0 10px 0 16px;
216
+ }
217
+
218
+ .identity {
219
+ min-width: 0;
220
+ display: flex;
221
+ align-items: center;
222
+ gap: 7px;
223
+ }
224
+
225
+ h1,
226
+ h2,
227
+ h3,
228
+ p { margin: 0; }
229
+
230
+ h1,
231
+ .drawer-header h2 {
232
+ font-size: var(--text-base);
233
+ font-weight: 600;
234
+ letter-spacing: -0.01em;
235
+ }
236
+
237
+ .library-toolbar {
238
+ min-height: 42px;
239
+ padding: 0 10px 0 12px;
240
+ flex: 0 0 auto;
241
+ z-index: 3;
242
+ display: flex;
243
+ align-items: center;
244
+ justify-content: space-between;
245
+ gap: 12px;
246
+ border-bottom: 1px solid var(--color-border);
247
+ background: var(--color-token-main-surface-primary);
248
+ }
249
+
250
+ .drawer-open .library-pane,
251
+ .thread-context .library-pane {
252
+ width: 20%;
253
+ transform: translateX(-8px);
254
+ transition-duration: 200ms;
255
+ }
256
+
257
+ .drawer-open .library-toolbar,
258
+ .thread-context .library-toolbar { display: none; }
259
+
260
+ .source-filter,
261
+ .density-control {
262
+ min-width: 0;
263
+ position: relative;
264
+ }
265
+
266
+ .toolbar-actions {
267
+ flex: 0 0 auto;
268
+ display: flex;
269
+ align-items: center;
270
+ gap: 8px;
271
+ }
272
+
273
+ .toolbar-button {
274
+ height: 28px;
275
+ min-width: 0;
276
+ border: 1px solid transparent;
277
+ border-radius: 8px;
278
+ display: inline-flex;
279
+ align-items: center;
280
+ gap: 6px;
281
+ padding: 0 8px;
282
+ color: var(--color-text-foreground-secondary);
283
+ background: transparent;
284
+ cursor: pointer;
285
+ font-size: var(--text-xs);
286
+ font-weight: 500;
287
+ }
288
+
289
+ .toolbar-button:hover,
290
+ .toolbar-button[aria-expanded="true"] {
291
+ color: var(--color-text-foreground);
292
+ background: var(--color-background-button-tertiary-hover);
293
+ }
294
+
295
+ .source-filter-button {
296
+ width: auto;
297
+ max-width: 240px;
298
+ }
299
+
300
+ .filter-source-icon,
301
+ .source-option-icon {
302
+ flex: 0 0 auto;
303
+ display: grid;
304
+ place-items: center;
305
+ }
306
+
307
+ .filter-source-icon .source-icon,
308
+ .source-option-icon .source-icon {
309
+ width: 14px;
310
+ height: 14px;
311
+ }
312
+
313
+ .filter-label {
314
+ min-width: 0;
315
+ overflow: hidden;
316
+ text-overflow: ellipsis;
317
+ white-space: nowrap;
318
+ }
319
+
320
+ .filter-count,
321
+ .source-option-count,
322
+ .density-button-value {
323
+ color: var(--color-text-foreground-tertiary);
324
+ font-variant-numeric: tabular-nums;
325
+ }
326
+
327
+ .filter-count {
328
+ flex: 0 0 auto;
329
+ min-width: 20px;
330
+ padding: 2px 5px;
331
+ border-radius: 5px;
332
+ background: var(--color-background-button-secondary);
333
+ line-height: 1;
334
+ text-align: center;
335
+ }
336
+
337
+ .filter-chevron {
338
+ width: 13px;
339
+ height: 13px;
340
+ flex: 0 0 auto;
341
+ transition: transform 120ms ease;
342
+ }
343
+
344
+ .source-filter-button:hover,
345
+ .source-filter-button[aria-expanded="true"] { background: transparent; }
346
+ .source-filter-button[aria-expanded="true"] .filter-chevron { transform: rotate(180deg); }
347
+
348
+ .source-menu {
349
+ position: absolute;
350
+ top: calc(100% + 6px);
351
+ z-index: 20;
352
+ border: 1px solid var(--color-border-heavy);
353
+ border-radius: var(--radius-md);
354
+ background: var(--color-background-elevated-primary-opaque);
355
+ box-shadow: var(--shadow-xl);
356
+ }
357
+
358
+ .source-menu[hidden] { display: none; }
359
+
360
+ .source-menu {
361
+ left: 0;
362
+ width: 240px;
363
+ max-height: min(342px, calc(100vh - 108px));
364
+ padding: 5px;
365
+ overflow-y: auto;
366
+ }
367
+
368
+ .source-option {
369
+ width: 100%;
370
+ min-height: 32px;
371
+ border: 0;
372
+ border-radius: 7px;
373
+ display: grid;
374
+ grid-template-columns: 16px minmax(0, 1fr) auto;
375
+ align-items: center;
376
+ gap: 7px;
377
+ padding: 5px 8px;
378
+ color: var(--color-text-foreground-secondary);
379
+ background: transparent;
380
+ cursor: pointer;
381
+ text-align: left;
382
+ font-size: var(--text-xs);
383
+ }
384
+
385
+ .source-option:hover,
386
+ .source-option[aria-selected="true"] {
387
+ color: var(--color-text-foreground);
388
+ background: var(--color-token-list-hover-background);
389
+ }
390
+
391
+ .source-option-label {
392
+ min-width: 0;
393
+ overflow: hidden;
394
+ text-overflow: ellipsis;
395
+ white-space: nowrap;
396
+ }
397
+
398
+ .source-option-count { padding-left: 8px; }
399
+
400
+ .source-menu-divider {
401
+ height: 1px;
402
+ margin: 5px 4px;
403
+ background: var(--color-border);
404
+ }
405
+
406
+ .density-control {
407
+ height: 28px;
408
+ border-radius: 8px;
409
+ display: flex;
410
+ align-items: center;
411
+ gap: 6px;
412
+ padding: 0 4px 0 7px;
413
+ color: var(--color-text-foreground-tertiary);
414
+ }
415
+
416
+ .density-icon {
417
+ width: 14px;
418
+ height: 14px;
419
+ flex: 0 0 auto;
420
+ }
421
+
422
+ .density-slider {
423
+ width: 92px;
424
+ height: 18px;
425
+ margin: 0;
426
+ appearance: none;
427
+ border: 0;
428
+ outline: 0;
429
+ background: transparent;
430
+ cursor: pointer;
431
+ }
432
+
433
+ .density-slider::-webkit-slider-runnable-track {
434
+ height: 4px;
435
+ border: 0;
436
+ border-radius: 999px;
437
+ background: var(--color-border-heavy);
438
+ }
439
+
440
+ .density-slider::-webkit-slider-thumb {
441
+ width: 10px;
442
+ height: 10px;
443
+ margin-top: -3px;
444
+ appearance: none;
445
+ border: 0;
446
+ border-radius: 50%;
447
+ background: var(--color-text-foreground-secondary);
448
+ }
449
+
450
+ .density-slider:hover::-webkit-slider-thumb {
451
+ background: var(--color-text-foreground);
452
+ }
453
+
454
+ .density-slider::-moz-range-track {
455
+ height: 4px;
456
+ border: 0;
457
+ border-radius: 999px;
458
+ background: var(--color-border-heavy);
459
+ }
460
+
461
+ .density-slider::-moz-range-thumb {
462
+ width: 10px;
463
+ height: 10px;
464
+ border: 0;
465
+ border-radius: 50%;
466
+ background: var(--color-text-foreground-secondary);
467
+ }
468
+
469
+ .density-button-value {
470
+ min-width: 10px;
471
+ font-size: 10px;
472
+ text-align: center;
473
+ }
474
+
475
+ .group-button[aria-pressed="true"] {
476
+ color: var(--color-text-foreground);
477
+ background: var(--color-background-button-secondary-hover);
478
+ }
479
+
480
+ .secondary-button,
481
+ .primary-button,
482
+ .icon-button {
483
+ min-height: 32px;
484
+ border: 1px solid transparent;
485
+ border-radius: var(--radius-md);
486
+ display: inline-flex;
487
+ align-items: center;
488
+ justify-content: center;
489
+ gap: 6px;
490
+ padding: 0 12px;
491
+ color: inherit;
492
+ cursor: pointer;
493
+ font-size: var(--text-sm);
494
+ font-weight: 500;
495
+ text-decoration: none;
496
+ transition: background-color 120ms ease, border-color 120ms ease, opacity 120ms ease;
497
+ }
498
+
499
+ .secondary-button {
500
+ border-color: var(--color-border);
501
+ background: var(--color-background-button-secondary);
502
+ }
503
+
504
+ .secondary-button:hover { background: var(--color-background-button-secondary-hover); }
505
+
506
+ .primary-button {
507
+ color: var(--color-text-primary-solid);
508
+ background: var(--color-background-primary-solid);
509
+ }
510
+
511
+ .primary-button:hover { opacity: 0.88; }
512
+ .primary-button:disabled { opacity: 0.45; cursor: default; }
513
+
514
+ .icon-button {
515
+ width: 28px;
516
+ min-height: 28px;
517
+ padding: 0;
518
+ color: var(--color-icon-tertiary);
519
+ background: transparent;
520
+ }
521
+
522
+ .icon-button:hover { background: var(--color-background-button-tertiary-hover); }
523
+ .icon-button:disabled { opacity: 0.45; cursor: default; }
524
+
525
+ .lucide {
526
+ width: 16px;
527
+ height: 16px;
528
+ fill: none;
529
+ stroke: currentColor;
530
+ stroke-width: 1.5;
531
+ stroke-linecap: round;
532
+ stroke-linejoin: round;
533
+ }
534
+
535
+ .loading-ring-icon { display: none; }
536
+ .rescan-button.is-loading { color: var(--color-text-foreground-secondary); }
537
+ .rescan-button.is-loading .refresh-icon { display: none; }
538
+ .rescan-button.is-loading .loading-ring-icon {
539
+ display: block;
540
+ animation: refresh-spin 700ms linear infinite;
541
+ }
542
+
543
+ @keyframes refresh-spin {
544
+ to { transform: rotate(360deg); }
545
+ }
546
+
547
+ .secondary-button:focus-visible,
548
+ .primary-button:focus-visible,
549
+ .icon-button:focus-visible,
550
+ .toolbar-button:focus-visible,
551
+ .source-option:focus-visible,
552
+ .density-slider:focus-visible,
553
+ .image-card:focus-visible,
554
+ .thread-board:focus-visible {
555
+ outline: 2px solid var(--color-border-focus);
556
+ outline-offset: 2px;
557
+ }
558
+
559
+ .image-grid {
560
+ --image-grid-gap: 16px;
561
+ --grid-columns: 3;
562
+ padding: 18px 20px 36px;
563
+ display: grid;
564
+ grid-template-columns: repeat(var(--grid-columns), minmax(0, 1fr));
565
+ grid-auto-rows: 1px;
566
+ column-gap: var(--image-grid-gap);
567
+ row-gap: 0;
568
+ align-items: start;
569
+ }
570
+
571
+ .page-sentinel {
572
+ height: 1px;
573
+ margin-top: -1px;
574
+ }
575
+
576
+ .image-card,
577
+ .thread-board {
578
+ width: 100%;
579
+ margin: 0 0 var(--image-grid-gap);
580
+ padding: 0;
581
+ overflow: hidden;
582
+ border: 1px solid var(--color-border);
583
+ border-radius: var(--radius-lg);
584
+ display: block;
585
+ color: var(--color-text-foreground);
586
+ background: var(--color-token-bg-secondary);
587
+ cursor: pointer;
588
+ text-align: left;
589
+ transition: background-color 120ms ease, border-color 120ms ease, transform 120ms ease;
590
+ }
591
+
592
+ .image-card:hover,
593
+ .image-card.is-selected,
594
+ .thread-board:hover {
595
+ border-color: var(--color-border-heavy);
596
+ background: var(--color-token-list-hover-background);
597
+ }
598
+
599
+ .image-card:hover,
600
+ .thread-board:hover { transform: translateY(-1px); }
601
+
602
+ .image-card img {
603
+ width: 100%;
604
+ height: auto;
605
+ display: block;
606
+ background: var(--color-token-bg-primary);
607
+ }
608
+
609
+ .thread-board-preview {
610
+ position: relative;
611
+ overflow: hidden;
612
+ display: flex;
613
+ flex-direction: column;
614
+ gap: 1px;
615
+ background: var(--color-border);
616
+ }
617
+
618
+ .thread-board-preview img {
619
+ width: 100%;
620
+ min-height: 76px;
621
+ aspect-ratio: 16 / 6;
622
+ display: block;
623
+ object-fit: cover;
624
+ background: var(--color-token-bg-primary);
625
+ }
626
+
627
+ .thread-board-preview.is-single img {
628
+ min-height: 180px;
629
+ aspect-ratio: auto;
630
+ object-fit: contain;
631
+ }
632
+
633
+ .thread-board-overflow {
634
+ position: absolute;
635
+ right: 8px;
636
+ bottom: 8px;
637
+ min-width: 32px;
638
+ height: 24px;
639
+ padding: 0 7px;
640
+ border: 1px solid rgb(255 255 255 / 20%);
641
+ border-radius: 7px;
642
+ display: inline-flex;
643
+ align-items: center;
644
+ justify-content: center;
645
+ color: #fff;
646
+ background: rgb(20 20 20 / 76%);
647
+ backdrop-filter: blur(8px);
648
+ font-size: var(--text-xs);
649
+ font-variant-numeric: tabular-nums;
650
+ }
651
+
652
+ .thread-board-caption {
653
+ min-height: 72px;
654
+ padding: 8px 10px 9px;
655
+ border-top: 1px solid var(--color-border);
656
+ display: flex;
657
+ flex-direction: column;
658
+ justify-content: center;
659
+ gap: 2px;
660
+ background: var(--color-background-panel);
661
+ font-size: var(--text-xs);
662
+ white-space: nowrap;
663
+ }
664
+
665
+ .thread-board-title {
666
+ overflow: hidden;
667
+ color: var(--color-text-foreground);
668
+ font-weight: 500;
669
+ text-overflow: ellipsis;
670
+ }
671
+
672
+ .thread-board-meta {
673
+ display: flex;
674
+ align-items: center;
675
+ justify-content: space-between;
676
+ gap: 8px;
677
+ color: var(--color-text-foreground-tertiary);
678
+ font-variant-numeric: tabular-nums;
679
+ }
680
+
681
+ .card-caption {
682
+ min-height: 54px;
683
+ padding: 7px 10px 8px;
684
+ border-top: 1px solid var(--color-border);
685
+ display: flex;
686
+ flex-direction: column;
687
+ align-items: stretch;
688
+ justify-content: center;
689
+ gap: 2px;
690
+ background: var(--color-background-panel);
691
+ font-size: var(--text-xs);
692
+ font-variant-numeric: tabular-nums;
693
+ white-space: nowrap;
694
+ }
695
+
696
+ .source-value {
697
+ min-width: 0;
698
+ display: flex;
699
+ align-items: center;
700
+ gap: 6px;
701
+ color: var(--color-text-foreground-secondary);
702
+ }
703
+
704
+ .source-value > span {
705
+ min-width: 0;
706
+ overflow: hidden;
707
+ text-overflow: ellipsis;
708
+ white-space: nowrap;
709
+ }
710
+
711
+ .source-icon {
712
+ width: 14px;
713
+ height: 14px;
714
+ flex: 0 0 auto;
715
+ }
716
+
717
+ .card-source { font-weight: 500; }
718
+ .card-time { color: var(--color-text-foreground-tertiary); }
719
+
720
+ .empty-state {
721
+ width: min(420px, calc(100% - 48px));
722
+ margin: 18vh auto 0;
723
+ padding: 28px;
724
+ text-align: center;
725
+ }
726
+
727
+ .empty-state h2 { font-size: var(--text-base); font-weight: 600; }
728
+ .empty-state p { margin-top: 6px; color: var(--color-text-foreground-secondary); font-size: var(--text-sm); }
729
+
730
+ .status-announcer {
731
+ position: absolute;
732
+ width: 1px;
733
+ height: 1px;
734
+ padding: 0;
735
+ margin: -1px;
736
+ overflow: hidden;
737
+ clip: rect(0, 0, 0, 0);
738
+ white-space: nowrap;
739
+ border: 0;
740
+ }
741
+
742
+ .detail-drawer {
743
+ position: absolute;
744
+ z-index: 4;
745
+ top: 0;
746
+ right: 0;
747
+ bottom: 0;
748
+ width: 80%;
749
+ overflow: hidden;
750
+ border-left: 1px solid var(--color-border);
751
+ background: var(--color-token-main-surface-primary);
752
+ transform: translateX(32px);
753
+ opacity: 0;
754
+ visibility: hidden;
755
+ pointer-events: none;
756
+ contain: layout paint;
757
+ overscroll-behavior: contain;
758
+ will-change: transform, opacity;
759
+ transition:
760
+ transform 160ms cubic-bezier(0.23, 1, 0.32, 1),
761
+ opacity 120ms cubic-bezier(0.23, 1, 0.32, 1),
762
+ visibility 0s linear 160ms;
763
+ }
764
+
765
+ .drawer-open .detail-drawer {
766
+ transform: translateX(0);
767
+ opacity: 1;
768
+ visibility: visible;
769
+ pointer-events: auto;
770
+ transition-delay: 0s;
771
+ transition-duration: 200ms, 160ms, 0s;
772
+ }
773
+
774
+ .drawer-surface {
775
+ width: 100%;
776
+ min-width: 0;
777
+ height: 100%;
778
+ display: flex;
779
+ flex-direction: column;
780
+ background: var(--color-token-main-surface-primary);
781
+ }
782
+
783
+ .drawer-open .image-grid {
784
+ --image-grid-gap: 12px;
785
+ grid-template-columns: 1fr;
786
+ }
787
+ .drawer-open .image-card .card-caption { display: none; }
788
+
789
+ .drawer-header {
790
+ flex: 0 0 auto;
791
+ justify-content: space-between;
792
+ padding: 0 9px 0 16px;
793
+ border-bottom: 0;
794
+ }
795
+
796
+ .drawer-scroll {
797
+ min-height: 0;
798
+ flex: 1 1 auto;
799
+ overflow: auto;
800
+ overscroll-behavior: contain;
801
+ }
802
+
803
+ .drawer-figure {
804
+ min-height: 180px;
805
+ margin: 0;
806
+ padding: 16px;
807
+ display: grid;
808
+ place-items: center;
809
+ background: var(--color-token-bg-primary);
810
+ }
811
+
812
+ .drawer-figure img {
813
+ max-width: 100%;
814
+ max-height: min(68vh, 720px);
815
+ display: block;
816
+ object-fit: contain;
817
+ border-radius: var(--radius-md);
818
+ }
819
+
820
+ .detail-section {
821
+ padding: 16px;
822
+ border-top: 1px solid var(--color-border);
823
+ }
824
+
825
+ .detail-section h3 {
826
+ margin-bottom: 10px;
827
+ color: var(--color-text-foreground);
828
+ font-size: var(--text-sm);
829
+ font-weight: 600;
830
+ }
831
+
832
+ .detail-section-heading {
833
+ display: flex;
834
+ align-items: center;
835
+ justify-content: space-between;
836
+ gap: 12px;
837
+ }
838
+
839
+ .detail-section-heading h3 { margin-bottom: 0; }
840
+ .detail-section-heading + .drawer-prompt { margin-top: 10px; }
841
+
842
+ .prompt-copy-button {
843
+ width: 26px;
844
+ min-height: 26px;
845
+ flex: 0 0 auto;
846
+ }
847
+
848
+ .prompt-copy-button.is-copied {
849
+ color: var(--color-text-foreground);
850
+ background: var(--color-background-button-secondary);
851
+ }
852
+ .prompt-copy-button svg[hidden] { display: none; }
853
+
854
+ .drawer-prompt {
855
+ overflow-wrap: anywhere;
856
+ white-space: pre-wrap;
857
+ color: var(--color-text-foreground-secondary);
858
+ font-size: var(--text-sm);
859
+ line-height: 1.55;
860
+ }
861
+
862
+ .drawer-prompt.is-loading,
863
+ .drawer-prompt.is-missing { color: var(--color-text-foreground-tertiary); }
864
+
865
+ .image-information { margin: 0; }
866
+
867
+ .image-information div {
868
+ min-height: 32px;
869
+ padding: 6px 0;
870
+ display: grid;
871
+ grid-template-columns: 86px minmax(0, 1fr);
872
+ gap: 12px;
873
+ }
874
+
875
+ .image-information div[hidden] { display: none; }
876
+
877
+ .image-information dt {
878
+ color: var(--color-text-foreground-tertiary);
879
+ font-size: var(--text-xs);
880
+ }
881
+
882
+ .image-information dd {
883
+ min-width: 0;
884
+ margin: 0;
885
+ color: var(--color-text-foreground-secondary);
886
+ font-size: var(--text-xs);
887
+ font-variant-numeric: tabular-nums;
888
+ }
889
+
890
+ .drawer-actions {
891
+ min-height: 56px;
892
+ padding: 10px 12px;
893
+ flex: 0 0 auto;
894
+ display: grid;
895
+ grid-template-columns: repeat(2, minmax(0, 200px));
896
+ justify-content: end;
897
+ gap: 12px;
898
+ border-top: 1px solid var(--color-border);
899
+ background: var(--color-token-main-surface-primary);
900
+ }
901
+
902
+ .source-action {
903
+ min-width: 0;
904
+ position: relative;
905
+ display: flex;
906
+ }
907
+
908
+ .source-button { width: 100%; }
909
+ .save-button { width: 100%; }
910
+
911
+ .source-action.is-disabled .source-button {
912
+ pointer-events: none;
913
+ opacity: 0.45;
914
+ cursor: not-allowed;
915
+ }
916
+
917
+ .source-tooltip {
918
+ position: absolute;
919
+ z-index: 2;
920
+ left: 50%;
921
+ bottom: calc(100% + 8px);
922
+ width: max-content;
923
+ max-width: min(260px, 70vw);
924
+ padding: 6px 8px;
925
+ border: 1px solid var(--color-border-heavy);
926
+ border-radius: 7px;
927
+ color: var(--color-text-foreground);
928
+ background: var(--color-background-elevated-primary-opaque);
929
+ box-shadow: var(--shadow-xl);
930
+ font-size: var(--text-xs);
931
+ font-weight: 400;
932
+ line-height: 1.35;
933
+ text-align: center;
934
+ transform: translateX(-50%);
935
+ opacity: 0;
936
+ visibility: hidden;
937
+ transition: opacity 100ms ease, visibility 100ms ease;
938
+ pointer-events: none;
939
+ }
940
+
941
+ .source-tooltip[hidden] { display: none; }
942
+
943
+ .source-action.is-disabled:hover .source-tooltip {
944
+ opacity: 1;
945
+ visibility: visible;
946
+ }
947
+
948
+ @media (max-width: 640px) {
949
+ .detail-drawer {
950
+ position: fixed;
951
+ z-index: 10;
952
+ top: 0;
953
+ right: 0;
954
+ bottom: 0;
955
+ width: 100vw;
956
+ transform: translateX(100%);
957
+ }
958
+
959
+ .drawer-open .detail-drawer {
960
+ width: 100vw;
961
+ transform: translateX(0);
962
+ }
963
+
964
+ .drawer-surface {
965
+ width: 100%;
966
+ min-width: 0;
967
+ }
968
+ }
969
+
970
+ @container (max-width: 820px) {
971
+ .image-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
972
+ }
973
+
974
+ @container (max-width: 520px) {
975
+ .library-toolbar { padding-left: 8px; }
976
+ .density-slider { width: 64px; }
977
+ .density-button-value { display: none; }
978
+ .image-grid { grid-template-columns: 1fr; }
979
+ }
980
+
981
+ @media (max-width: 520px) {
982
+ .image-grid {
983
+ padding: 10px;
984
+ }
985
+ }
986
+
987
+ @media (prefers-reduced-motion: reduce) {
988
+ *,
989
+ *::before,
990
+ *::after {
991
+ scroll-behavior: auto !important;
992
+ transition-duration: 0.01ms !important;
993
+ }
994
+ }