@ttt-productions/theme-core 0.1.19 → 0.1.22

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.
@@ -1,11 +1,8 @@
1
- @layer base {
2
- html, body {
3
- background-color: hsl(var(--background));
4
- color: hsl(var(--foreground));
5
- }
6
-
7
- * {
8
- border-color: hsl(var(--border));
9
- }
10
- }
11
-
1
+ html, body {
2
+ background-color: hsl(var(--background));
3
+ color: hsl(var(--foreground));
4
+ }
5
+
6
+ * {
7
+ border-color: hsl(var(--border));
8
+ }
@@ -1,333 +1,632 @@
1
- @layer components {
2
- /* ===================
3
- LAYOUT / CARDS
4
- =================== */
5
- .page-container {
6
- @apply flex-1 w-full mx-auto py-4;
7
- }
8
1
 
9
- .page-card {
10
- @apply w-full bg-card text-card-foreground shadow-xl rounded-lg border-2 border-border;
11
- }
2
+ /* =========================================================
3
+ FOUNDATIONS (icon + layout bundles) replaces inline utils
4
+ ========================================================= */
5
+
6
+ /* Icons */
7
+ .icon-xxs { @apply h-3 w-3; }
8
+ .icon-xs { @apply h-4 w-4; }
9
+ .icon-sm { @apply h-5 w-5; }
10
+ .icon-md { @apply h-6 w-6; }
11
+ .icon-lg { @apply h-8 w-8; }
12
+ .icon-xl { @apply h-10 w-10; }
13
+ .icon-2xl { @apply h-12 w-12; }
14
+
15
+ /* Spinners */
16
+ .spinner-xs { @apply icon-xs animate-spin; color: hsl(var(--primary)); }
17
+ .spinner-sm { @apply icon-sm animate-spin; color: hsl(var(--primary)); }
18
+ .spinner-md { @apply icon-md animate-spin; color: hsl(var(--primary)); }
19
+ .spinner-lg { @apply icon-lg animate-spin; color: hsl(var(--primary)); }
20
+ .spinner-xl { @apply icon-xl animate-spin; color: hsl(var(--primary)); }
21
+ .spinner-with-gap { @apply mr-2; }
22
+
23
+ /* Common centering */
24
+ .center-row { @apply flex items-center justify-center; }
25
+ .center-col { @apply flex flex-col items-center justify-center; }
26
+ .loading-block { @apply center-row py-8; }
27
+ .loading-block-padded { @apply center-row p-8; }
28
+ .loading-screen { @apply flex flex-col h-screen-mobile w-screen items-center justify-center bg-background space-y-4; }
29
+
30
+ /* Stacks */
31
+ .stack-1 { @apply space-y-1; }
32
+ .stack-2 { @apply space-y-2; }
33
+ .stack-4 { @apply space-y-4; }
34
+ .stack-6 { @apply space-y-6; }
35
+
36
+ /* =========================================================
37
+ PAGE LAYOUT
38
+ ========================================================= */
39
+ .page-container {
40
+ @apply flex-1 w-full mx-auto py-4;
41
+ }
12
42
 
13
- .page-card-header {
14
- @apply text-center p-4 sm:p-6;
15
- }
43
+ .page-card {
44
+ @apply w-full bg-card text-card-foreground shadow-xl rounded-lg border-2 border-border;
45
+ }
16
46
 
17
- .page-card-title {
18
- @apply text-3xl font-bold text-foreground;
19
- }
47
+ .page-card-header {
48
+ @apply text-center p-4 sm:p-6 items-center;
49
+ }
20
50
 
21
- .page-card-content {
22
- @apply px-2 sm:px-6 pb-4;
23
- }
51
+ .page-card-header-left {
52
+ @apply p-4 sm:p-6 text-left;
53
+ }
24
54
 
25
- .inner-card-container {
26
- @apply px-4 py-2;
27
- }
55
+ .page-card-title {
56
+ @apply text-3xl font-bold text-foreground;
57
+ }
28
58
 
29
- /* ===================
30
- TEXT UTILITIES
31
- =================== */
32
- .card-title {
33
- color: hsl(var(--foreground));
34
- }
59
+ .page-card-content {
60
+ @apply px-2 sm:px-6 pb-4;
61
+ }
35
62
 
36
- .card-description {
37
- @apply text-sm font-bold;
38
- color: hsl(var(--muted-foreground));
39
- }
63
+ .inner-card-container {
64
+ @apply px-4 py-2;
65
+ }
40
66
 
41
- .input-description {
42
- @apply text-xs;
43
- color: hsl(var(--muted-foreground));
44
- }
67
+ /* =========================================================
68
+ TYPOGRAPHY (high-level)
69
+ ========================================================= */
70
+ .text-body {
71
+ @apply text-sm font-medium;
72
+ color: hsl(var(--foreground));
73
+ }
45
74
 
46
- .disclaimer-text {
47
- @apply text-sm font-bold text-center;
48
- color: hsl(var(--muted-foreground));
49
- }
75
+ .text-muted {
76
+ @apply text-sm font-medium;
77
+ color: hsl(var(--muted-foreground));
78
+ }
50
79
 
51
- .text-small {
52
- @apply text-sm font-bold;
53
- color: hsl(var(--foreground));
54
- }
80
+ .text-caption {
81
+ @apply text-xs font-medium;
82
+ color: hsl(var(--muted-foreground));
83
+ }
55
84
 
56
- .text-xs-bold {
57
- @apply text-xs font-bold;
58
- color: hsl(var(--foreground));
59
- }
85
+ .text-small {
86
+ @apply text-sm font-bold;
87
+ color: hsl(var(--foreground));
88
+ }
60
89
 
61
- .text-label {
62
- @apply font-bold;
63
- color: hsl(var(--foreground));
64
- }
90
+ .text-xs-bold {
91
+ @apply text-xs font-bold;
92
+ color: hsl(var(--foreground));
93
+ }
65
94
 
66
- .text-counter {
67
- @apply text-sm font-bold;
68
- color: hsl(var(--muted-foreground));
69
- }
95
+ .text-label {
96
+ @apply font-bold;
97
+ color: hsl(var(--foreground));
98
+ }
70
99
 
71
- .empty-state-text {
72
- @apply text-center py-8 font-bold;
73
- color: hsl(var(--muted-foreground));
74
- }
100
+ .text-counter {
101
+ @apply text-sm font-bold;
102
+ color: hsl(var(--muted-foreground));
103
+ }
75
104
 
76
- /* ===================
77
- LINKS
78
- =================== */
79
- .auth-link {
80
- @apply text-sm underline font-semibold;
81
- color: hsl(var(--primary));
82
- }
105
+ .empty-state-text {
106
+ @apply text-center py-8 font-bold;
107
+ color: hsl(var(--muted-foreground));
108
+ }
83
109
 
84
- /* ===================
85
- POPOVERS
86
- =================== */
87
- .app-popover {
88
- @apply w-80 p-2 border-2;
89
- background-color: hsl(var(--card));
90
- border-color: hsl(var(--border));
91
- color: hsl(var(--card-foreground));
92
- }
110
+ .card-description {
111
+ @apply text-sm font-bold;
112
+ color: hsl(var(--muted-foreground));
113
+ }
93
114
 
94
- /* ===================
95
- ALERT DIALOGS
96
- =================== */
97
- .alert-dialog-overlay {
98
- background-color: rgba(0, 0, 0, 0.8);
99
- }
115
+ .input-description {
116
+ @apply text-xs;
117
+ color: hsl(var(--muted-foreground));
118
+ }
100
119
 
101
- .alert-dialog-content {
102
- background-color: hsl(var(--card)) !important;
103
- border-color: hsl(var(--border)) !important;
104
- color: hsl(var(--card-foreground)) !important;
105
- @apply border-2;
106
- }
120
+ .disclaimer-text {
121
+ @apply text-sm font-bold text-center;
122
+ color: hsl(var(--muted-foreground));
123
+ }
107
124
 
108
- .alert-dialog-title {
109
- color: hsl(var(--foreground)) !important;
110
- }
125
+ /* Error blocks / inline */
126
+ .text-error {
127
+ @apply text-sm font-bold;
128
+ color: hsl(var(--destructive));
129
+ }
111
130
 
112
- .alert-dialog-description {
113
- color: hsl(var(--muted-foreground)) !important;
114
- @apply font-bold;
115
- }
131
+ .text-error-block {
132
+ @apply text-center p-4 font-bold rounded-md border;
133
+ color: hsl(var(--destructive));
134
+ border-color: hsl(var(--destructive) / 0.5);
135
+ background-color: hsl(var(--destructive) / 0.10);
136
+ }
116
137
 
117
- /* ===================
118
- SELECTS (GENERIC)
119
- =================== */
120
- .form-select-trigger {
121
- @apply font-semibold rounded-xl h-11 px-4 shadow-sm border-2;
122
- background-color: hsl(var(--background));
123
- border-color: hsl(var(--border)) !important;
124
- color: hsl(var(--foreground));
125
- }
138
+ /* =========================================================
139
+ LINKS
140
+ ========================================================= */
141
+ .auth-link {
142
+ @apply text-sm underline font-semibold;
143
+ color: hsl(var(--primary));
144
+ }
126
145
 
127
- /* ===================
128
- FILTER & SORT (GENERIC)
129
- =================== */
130
- .filter-select-trigger,
131
- .sort-select-trigger {
132
- @apply w-full sm:w-auto rounded-xl h-11 px-4 font-bold shadow-sm border-2;
133
- background-color: hsl(var(--primary));
134
- border-color: hsl(var(--border));
135
- color: hsl(var(--primary-foreground));
136
- }
146
+ /* =========================================================
147
+ CHAT
148
+ ========================================================= */
149
+ .chat-date-separator {
150
+ @apply text-xs font-bold bg-muted px-3 py-1 rounded-full;
151
+ color: hsl(var(--foreground));
152
+ }
137
153
 
138
- .filter-select-content,
139
- .sort-select-content {
140
- background-color: hsl(var(--popover));
141
- border-color: hsl(var(--border));
142
- color: hsl(var(--popover-foreground));
143
- }
154
+ /* Status pills (replaces bg-blue-100/text-blue-700 etc.) */
155
+ .status-pill {
156
+ @apply text-xs-bold px-2 py-0.5 rounded-full inline-flex items-center;
157
+ }
144
158
 
145
- .filter-select-item,
146
- .sort-select-item {
147
- @apply font-bold;
148
- color: hsl(var(--foreground));
149
- }
159
+ .status-pill--info {
160
+ background-color: hsl(var(--info) / 0.15);
161
+ color: hsl(var(--info));
162
+ }
150
163
 
151
- .filter-select-item:hover,
152
- .sort-select-item:hover {
153
- background-color: hsl(var(--accent));
154
- color: hsl(var(--accent-foreground));
155
- }
164
+ .status-pill--success {
165
+ background-color: hsl(var(--success) / 0.15);
166
+ color: hsl(var(--success));
167
+ }
156
168
 
157
- /* High contrast behavior */
158
- .high-contrast .filter-select-trigger,
159
- .high-contrast .sort-select-trigger {
160
- background-color: hsl(var(--background));
161
- border-color: hsl(var(--border));
162
- color: hsl(var(--foreground));
163
- }
169
+ .status-pill--warning {
170
+ background-color: hsl(var(--warning) / 0.15);
171
+ color: hsl(var(--warning));
172
+ }
164
173
 
165
- .high-contrast .filter-select-content,
166
- .high-contrast .sort-select-content {
167
- background-color: hsl(var(--background));
168
- border-color: hsl(var(--border));
169
- color: hsl(var(--foreground));
170
- }
174
+ .status-pill--muted {
175
+ background-color: hsl(var(--muted));
176
+ color: hsl(var(--muted-foreground));
177
+ }
171
178
 
172
- .high-contrast .filter-select-item:hover,
173
- .high-contrast .sort-select-item:hover {
174
- background-color: hsl(var(--foreground));
175
- color: hsl(var(--background));
176
- }
179
+ /* High contrast pills: pure B/W */
180
+ .high-contrast .status-pill--info,
181
+ .high-contrast .status-pill--success,
182
+ .high-contrast .status-pill--warning,
183
+ .high-contrast .status-pill--muted {
184
+ background-color: hsl(var(--background));
185
+ color: hsl(var(--foreground));
186
+ border: 2px solid hsl(var(--border));
187
+ }
177
188
 
178
- /* ===================
179
- VIEW TOGGLE (GENERIC)
180
- =================== */
181
- .view-toggle-container {
182
- @apply flex items-center p-1 rounded-xl border-2 shadow-sm;
183
- background-color: hsl(var(--muted));
184
- border-color: hsl(var(--border));
189
+ /* ===================
190
+ SCREEN ADAPTIVE VIEW
191
+ =================== */
192
+ .screen-adaptive-root {
193
+ @apply flex flex-1 flex-col w-full;
185
194
  }
186
195
 
187
- .view-toggle-button {
188
- @apply rounded-lg h-8 w-8;
189
- color: hsl(var(--foreground));
196
+ .screen-adaptive-inner {
197
+ @apply mx-auto w-full;
190
198
  }
191
199
 
192
- /* ===================
193
- DATE PICKER (GENERIC)
194
- =================== */
195
- .date-picker-popover {
196
- background-color: hsl(var(--card)) !important;
197
- border-color: hsl(var(--border)) !important;
198
- color: hsl(var(--card-foreground)) !important;
199
- @apply border-2;
200
- }
200
+ /* Max width variants */
201
+ .screen-max-w-none { max-width: none; }
202
+ .screen-max-w-full { max-width: 100%; }
201
203
 
202
- .date-picker-caption {
203
- color: hsl(var(--foreground)) !important;
204
- }
204
+ .screen-max-w-sm { max-width: 24rem; } /* 384px */
205
+ .screen-max-w-md { max-width: 28rem; } /* 448px */
206
+ .screen-max-w-lg { max-width: 32rem; } /* 512px */
207
+ .screen-max-w-xl { max-width: 36rem; } /* 576px */
205
208
 
206
- .date-picker-day-label {
207
- color: hsl(var(--muted-foreground)) !important;
208
- @apply font-bold text-center;
209
- }
209
+ .screen-max-w-2xl { max-width: 42rem; } /* 672px */
210
+ .screen-max-w-3xl { max-width: 48rem; } /* 768px */
211
+ .screen-max-w-4xl { max-width: 56rem; } /* 896px */
212
+ .screen-max-w-5xl { max-width: 64rem; } /* 1024px */
213
+ .screen-max-w-6xl { max-width: 72rem; } /* 1152px */
214
+ .screen-max-w-7xl { max-width: 80rem; } /* 1280px */
210
215
 
211
- .date-picker-day {
212
- color: hsl(var(--foreground)) !important;
213
- @apply font-semibold;
214
- }
216
+ /* =========================================================
217
+ RULE CARDS
218
+ ========================================================= */
219
+ .rule-card {
220
+ @apply p-4 rounded-lg border-2 border-border bg-card;
221
+ }
215
222
 
216
- .date-picker-day-today {
217
- background-color: hsl(var(--accent)) !important;
218
- color: hsl(var(--accent-foreground)) !important;
219
- @apply font-bold;
220
- }
223
+ .rule-card-title {
224
+ @apply font-bold mb-2;
225
+ color: hsl(var(--foreground));
226
+ }
221
227
 
222
- .date-picker-day-selected {
223
- background-color: hsl(var(--primary)) !important;
224
- color: hsl(var(--primary-foreground)) !important;
225
- @apply font-bold;
226
- }
228
+ .rule-card-description {
229
+ @apply text-sm leading-relaxed font-bold;
230
+ color: hsl(var(--muted-foreground));
231
+ }
227
232
 
228
- .date-picker-day:hover {
229
- background-color: hsl(var(--primary) / 0.12) !important;
230
- color: hsl(var(--foreground)) !important;
231
- }
233
+ /* =========================================================
234
+ ACCORDION
235
+ ========================================================= */
236
+ .accordion-trigger {
237
+ @apply p-6 hover:no-underline rounded-t-lg;
238
+ }
232
239
 
233
- .date-picker-day-disabled {
234
- opacity: 0.3;
235
- cursor: not-allowed;
236
- }
240
+ .accordion-icon-container {
241
+ @apply p-2 rounded-lg;
242
+ background-color: hsl(var(--primary) / 0.10);
243
+ color: hsl(var(--primary));
244
+ }
237
245
 
238
- .date-picker-nav-button {
239
- background-color: hsl(var(--primary)) !important;
240
- color: hsl(var(--primary-foreground)) !important;
241
- border: none !important;
242
- }
246
+ .accordion-title {
247
+ @apply text-lg font-semibold;
248
+ color: hsl(var(--foreground));
249
+ }
243
250
 
244
- .high-contrast .date-picker-nav-button {
245
- border: 2px solid hsl(var(--border)) !important;
246
- }
251
+ .accordion-content-container {
252
+ @apply px-6 py-4 rounded-b-lg space-y-4 bg-card;
253
+ }
247
254
 
248
- /* ===================
249
- TOAST (Radix/shadcn-friendly)
250
- =================== */
251
- .toast-viewport {
252
- @apply fixed bottom-0 right-0 z-50 flex max-h-screen w-full flex-col p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px];
253
- }
255
+ /* =========================================================
256
+ DETAILS (nested accordions)
257
+ ========================================================= */
258
+ .details-summary {
259
+ @apply flex items-center justify-between cursor-pointer list-none p-4 rounded-lg border-2 border-border bg-card transition-all;
260
+ }
254
261
 
255
- .toast-root {
256
- @apply relative overflow-hidden rounded-lg border-2 p-4 shadow-lg;
257
- background-color: hsl(var(--card));
258
- border-color: hsl(var(--border));
259
- color: hsl(var(--card-foreground));
260
- }
262
+ .details-summary:hover {
263
+ border-color: hsl(var(--primary));
264
+ background-color: hsl(var(--primary) / 0.05);
265
+ }
261
266
 
262
- .toast-root[data-variant="success"] {
263
- border-color: hsl(var(--success));
264
- }
267
+ .details-icon-container {
268
+ @apply p-2 rounded-lg transition-colors;
269
+ background-color: hsl(var(--primary) / 0.10);
270
+ color: hsl(var(--primary));
271
+ }
265
272
 
266
- .toast-root[data-variant="warning"] {
267
- border-color: hsl(var(--warning));
268
- }
273
+ .group\/details:hover .details-icon-container {
274
+ background-color: hsl(var(--primary));
275
+ color: hsl(var(--primary-foreground));
276
+ }
269
277
 
270
- .toast-root[data-variant="error"],
271
- .toast-root[data-variant="destructive"] {
272
- border-color: hsl(var(--destructive));
273
- }
278
+ .details-title {
279
+ @apply font-semibold text-base;
280
+ color: hsl(var(--foreground));
281
+ }
274
282
 
275
- .toast-dismiss {
276
- @apply absolute right-2 top-2 inline-flex h-8 w-8 items-center justify-center rounded-md text-sm font-bold;
277
- background-color: transparent;
278
- color: hsl(var(--muted-foreground));
279
- }
283
+ .details-chevron {
284
+ color: hsl(var(--primary));
285
+ }
280
286
 
281
- .toast-dismiss:hover,
282
- .toast-dismiss:focus-visible {
283
- background-color: hsl(var(--accent));
284
- color: hsl(var(--accent-foreground));
285
- }
287
+ /* =========================================================
288
+ AGREEMENT LIST ITEMS
289
+ ========================================================= */
290
+ .agreement-list-item {
291
+ @apply flex gap-2 text-sm font-bold;
292
+ color: hsl(var(--muted-foreground));
293
+ }
286
294
 
287
- /* countdown bar (uses --toast-duration; can be overridden per-toast) */
288
- .toast-progress {
289
- @apply absolute bottom-0 left-0 h-1 w-full;
290
- background-color: hsl(var(--foreground));
291
- transform-origin: left center;
292
- animation: toast-life var(--toast-duration) linear forwards;
293
- opacity: 0.35;
294
- }
295
+ /* =========================================================
296
+ FUTURE PLANS / MEDIA
297
+ ========================================================= */
298
+ .future-plan-description {
299
+ @apply text-base whitespace-pre-wrap leading-relaxed max-w-prose font-bold;
300
+ color: hsl(var(--muted-foreground));
301
+ }
295
302
 
296
- .high-contrast .toast-progress {
297
- opacity: 1;
298
- }
303
+ .future-plan-media {
304
+ @apply w-full aspect-video rounded-lg overflow-hidden border;
305
+ border-color: hsl(var(--border));
306
+ background-color: hsl(var(--muted));
299
307
  }
300
308
 
301
- /* Radix swipe support (works if toast root is Radix Toast.Root) */
302
- [data-swipe="move"] {
303
- transform: translateX(var(--radix-toast-swipe-move-x));
309
+ /* Media helpers (replaces repeated w/full/max-w/aspect) */
310
+ .media-image-sm-centered {
311
+ @apply w-full h-auto max-w-sm mx-auto;
304
312
  }
305
313
 
306
- [data-swipe="cancel"] {
307
- transform: translateX(0);
308
- transition: transform 200ms ease-out;
314
+ .media-square-centered {
315
+ @apply w-full max-w-[400px] mx-auto aspect-square rounded-md overflow-hidden;
316
+ background-color: hsl(var(--muted));
309
317
  }
310
318
 
311
- [data-swipe="end"] {
312
- animation: toast-swipe-out 120ms ease-out forwards;
319
+ .media-wide {
320
+ @apply w-full aspect-video rounded-lg overflow-hidden border;
321
+ border-color: hsl(var(--border));
322
+ background-color: hsl(var(--muted));
313
323
  }
314
324
 
315
- @keyframes toast-life {
316
- from {
317
- transform: scaleX(1);
318
- }
319
- to {
320
- transform: scaleX(0);
321
- }
325
+ /* =========================================================
326
+ INFO SECTIONS
327
+ ========================================================= */
328
+ .info-section {
329
+ @apply flex items-start gap-4;
322
330
  }
323
331
 
324
- @keyframes toast-swipe-out {
325
- from {
326
- transform: translateX(var(--radix-toast-swipe-end-x));
327
- opacity: 1;
328
- }
329
- to {
330
- transform: translateX(calc(var(--radix-toast-swipe-end-x) * 1.2));
331
- opacity: 0;
332
+ .info-section-icon {
333
+ @apply mt-1;
334
+ color: hsl(var(--primary));
335
+ }
336
+
337
+ .info-section-title {
338
+ @apply font-semibold;
339
+ color: hsl(var(--foreground));
340
+ }
341
+
342
+ .info-section-description {
343
+ @apply text-sm font-bold;
344
+ color: hsl(var(--muted-foreground));
345
+ }
346
+
347
+ .info-section-divider {
348
+ @apply w-full h-px;
349
+ background-color: hsl(var(--border));
350
+ }
351
+
352
+ .info-section-header {
353
+ @apply text-lg font-semibold text-center pt-4;
354
+ color: hsl(var(--foreground));
355
+ }
356
+
357
+ /* =========================================================
358
+ ATTRIBUTION SECTIONS
359
+ ========================================================= */
360
+ .attribution-item {
361
+ @apply flex items-start gap-4;
362
+ }
363
+
364
+ .attribution-icon {
365
+ @apply mt-1;
366
+ color: hsl(var(--primary));
367
+ }
368
+
369
+ .attribution-title {
370
+ @apply font-semibold;
371
+ color: hsl(var(--foreground));
372
+ }
373
+
374
+ .attribution-cost {
375
+ @apply text-sm font-semibold;
376
+ color: hsl(var(--primary));
377
+ }
378
+
379
+ .attribution-description {
380
+ @apply text-sm mt-1 font-bold;
381
+ color: hsl(var(--muted-foreground));
382
+ }
383
+
384
+ /* =========================================================
385
+ DEDICATION SECTIONS
386
+ ========================================================= */
387
+ .dedication-section {
388
+ @apply text-center space-y-2;
389
+ }
390
+
391
+ .dedication-header {
392
+ @apply inline-flex items-center gap-2;
393
+ }
394
+
395
+ .dedication-title {
396
+ @apply font-semibold text-lg;
397
+ color: hsl(var(--foreground));
398
+ }
399
+
400
+ .dedication-content {
401
+ @apply font-bold;
402
+ color: hsl(var(--muted-foreground));
403
+ }
404
+
405
+ /* =========================================================
406
+ DMCA INFO
407
+ ========================================================= */
408
+ .dmca-section-title {
409
+ @apply text-lg font-semibold;
410
+ color: hsl(var(--foreground));
411
+ }
412
+
413
+ .dmca-info-container {
414
+ @apply space-y-2 pl-4 border-l-2;
415
+ border-color: hsl(var(--border));
416
+ }
417
+
418
+ .dmca-info-row {
419
+ @apply flex flex-col sm:flex-row sm:items-center;
420
+ }
421
+
422
+ .dmca-label {
423
+ @apply w-full sm:w-40 font-semibold shrink-0;
424
+ color: hsl(var(--foreground));
425
+ }
426
+
427
+ .dmca-value {
428
+ @apply break-all font-bold;
429
+ color: hsl(var(--muted-foreground));
430
+ }
431
+
432
+ /* =========================================================
433
+ BUTTONS
434
+ ========================================================= */
435
+ .primary-action-button {
436
+ @apply w-full text-lg py-6;
437
+ }
438
+
439
+ .secondary-action-grid {
440
+ @apply grid grid-cols-2 md:grid-cols-3 gap-4 mt-6;
441
+ }
442
+
443
+ .secondary-action-button {
444
+ @apply justify-center;
445
+ }
446
+
447
+ /* =========================================================
448
+ FOOTER
449
+ ========================================================= */
450
+ .app-footer {
451
+ @apply w-full h-12 flex-shrink-0 bg-secondary pt-4;
452
+ }
453
+
454
+ /* =========================================================
455
+ CUSTOM FORM ELEMENTS
456
+ ========================================================= */
457
+ .form-select-trigger {
458
+ @apply font-semibold rounded-xl h-11 px-4 shadow-sm border-2;
459
+ background-color: hsl(var(--background));
460
+ border-color: hsl(var(--border)) !important;
461
+ color: hsl(var(--foreground));
462
+ }
463
+
464
+ /* =========================================================
465
+ SAFE AREA UTILITIES
466
+ ========================================================= */
467
+ .fixed-header {
468
+ padding-top: max(1rem, var(--sat));
469
+ }
470
+
471
+ .fixed-footer {
472
+ padding-bottom: max(1rem, var(--sab));
473
+ }
474
+
475
+ /* =========================================================
476
+ LANDING PAGE
477
+ ========================================================= */
478
+ .landing-tabs-list {
479
+ @apply grid w-full grid-cols-2 bg-transparent p-0 gap-2 mb-4;
480
+ }
481
+
482
+ .landing-tab-trigger {
483
+ @apply flex-1;
484
+ }
485
+
486
+ .landing-section-title {
487
+ @apply text-xl font-semibold text-center;
488
+ color: hsl(var(--foreground));
489
+ }
490
+
491
+ .landing-section-description {
492
+ @apply text-center font-bold;
493
+ color: hsl(var(--muted-foreground));
494
+ }
495
+
496
+ .landing-video-container {
497
+ @apply aspect-video w-full rounded-lg overflow-hidden border;
498
+ border-color: hsl(var(--border));
499
+ background-color: hsl(var(--muted));
500
+ }
501
+
502
+ /* =========================================================
503
+ APP HEADER
504
+ ========================================================= */
505
+ .app-header {
506
+ @apply flex items-center h-[60px] shadow-md;
507
+ background-color: hsl(var(--secondary));
508
+ border-bottom: 2px solid hsl(var(--border));
509
+ }
510
+
511
+ .app-header-container {
512
+ @apply flex items-center justify-between w-full px-0.5;
513
+ }
514
+
515
+ .app-header-actions {
516
+ @apply flex items-center space-x-3;
517
+ }
518
+
519
+ .app-header-menu-button {
520
+ @apply flex items-center space-x-2 h-10 px-3 rounded-full;
521
+ }
522
+
523
+ .app-dropdown-menu {
524
+ @apply w-56 border-2;
525
+ background-color: hsl(var(--card));
526
+ border-color: hsl(var(--border));
527
+ }
528
+
529
+ .app-dropdown-item {
530
+ @apply flex items-center cursor-pointer font-bold;
531
+ color: hsl(var(--foreground)) !important;
532
+ }
533
+
534
+ .app-dropdown-item:hover,
535
+ .app-dropdown-item:focus {
536
+ background-color: hsl(var(--accent));
537
+ color: hsl(var(--accent-foreground)) !important;
538
+ }
539
+
540
+ /* =========================================================
541
+ POPOVERS
542
+ ========================================================= */
543
+ .app-popover {
544
+ @apply w-80 p-2 border-2;
545
+ background-color: hsl(var(--card));
546
+ border-color: hsl(var(--border));
547
+ color: hsl(var(--card-foreground));
548
+ }
549
+
550
+ /* =========================================================
551
+ HELP DIALOG
552
+ ========================================================= */
553
+ .help-dialog-title {
554
+ @apply font-semibold;
555
+ color: hsl(var(--foreground)) !important;
556
+ }
557
+
558
+ .help-dialog-body {
559
+ font-weight: 700 !important;
560
+ color: hsl(var(--muted-foreground)) !important;
561
+ }
562
+
563
+ @media (prefers-contrast: more) {
564
+ .help-dialog-body {
565
+ color: #ffffff !important;
332
566
  }
333
567
  }
568
+
569
+ /* =========================================================
570
+ FILTER & SORT (GENERIC)
571
+ ========================================================= */
572
+ .filter-select-trigger,
573
+ .sort-select-trigger {
574
+ @apply w-full sm:w-auto rounded-xl h-11 px-4 font-bold shadow-sm border-2;
575
+ background-color: hsl(var(--primary));
576
+ border-color: hsl(var(--border));
577
+ color: hsl(var(--primary-foreground));
578
+ }
579
+
580
+ .filter-select-content,
581
+ .sort-select-content {
582
+ background-color: hsl(var(--popover));
583
+ border-color: hsl(var(--border));
584
+ color: hsl(var(--popover-foreground));
585
+ }
586
+
587
+ .filter-select-item,
588
+ .sort-select-item {
589
+ @apply font-bold;
590
+ color: hsl(var(--foreground));
591
+ }
592
+
593
+ .filter-select-item:hover,
594
+ .sort-select-item:hover {
595
+ background-color: hsl(var(--accent));
596
+ color: hsl(var(--accent-foreground));
597
+ }
598
+
599
+ /* High contrast behavior */
600
+ .high-contrast .filter-select-trigger,
601
+ .high-contrast .sort-select-trigger {
602
+ background-color: hsl(var(--background));
603
+ border-color: hsl(var(--border));
604
+ color: hsl(var(--foreground));
605
+ }
606
+
607
+ .high-contrast .filter-select-content,
608
+ .high-contrast .sort-select-content {
609
+ background-color: hsl(var(--background));
610
+ border-color: hsl(var(--border));
611
+ color: hsl(var(--foreground));
612
+ }
613
+
614
+ .high-contrast .filter-select-item:hover,
615
+ .high-contrast .sort-select-item:hover {
616
+ background-color: hsl(var(--foreground));
617
+ color: hsl(var(--background));
618
+ }
619
+
620
+ /* =========================================================
621
+ VIEW TOGGLE (GENERIC)
622
+ ========================================================= */
623
+ .view-toggle-container {
624
+ @apply flex items-center p-1 rounded-xl border-2 shadow-sm;
625
+ background-color: hsl(var(--muted));
626
+ border-color: hsl(var(--border));
627
+ }
628
+
629
+ .view-toggle-button {
630
+ @apply rounded-lg h-8 w-8;
631
+ color: hsl(var(--foreground));
632
+ }
@@ -1,37 +1,30 @@
1
- @layer base {
2
- :root {
3
- /* Loud fallbacks: if you see this color, the app did not define required brand contract */
4
- --brand-primary: 999 100% 50%;
5
- --brand-secondary: 999 100% 50%;
6
- --brand-accent: 999 100% 50%;
7
1
 
8
- /* Always-available neutrals (theme-core owned) */
9
- --neutral-white: 0 0% 100%;
10
- --neutral-black: 0 0% 0%;
2
+ :root {
3
+ /* Loud fallbacks: if you see this, app did NOT define required brand tokens */
4
+ --brand-primary: 999 100% 50%;
5
+ --brand-secondary: 999 100% 50%;
6
+ --brand-accent: 999 100% 50%;
11
7
 
12
- /* OPTIONAL status colors (apps can override) */
13
- --color-for-success: 142 71% 45%;
14
- --color-for-warning: 38 92% 50%;
15
- --color-for-error: 0 84% 60%;
8
+ /* Status tokens: OPTIONAL (sane defaults) */
9
+ --status-success: 140 70% 45%;
10
+ --status-warning: 45 90% 50%;
11
+ --status-error: 0 84% 60%;
12
+ --status-info: 221 83% 53%;
16
13
 
17
- /* Mapped status tokens used by theme-core */
18
- --status-success: var(--color-for-success);
19
- --status-warning: var(--color-for-warning);
20
- --status-error: var(--color-for-error);
21
- }
22
-
23
- /* High contrast must be pure B/W (prevents bleed from any app colors) */
24
- .high-contrast {
25
- --brand-primary: 0 0% 0%;
26
- --brand-secondary: 0 0% 0%;
27
- --brand-accent: 0 0% 100%;
14
+ /* Neutrals */
15
+ --neutral-white: 0 0% 100%;
16
+ --neutral-black: 0 0% 0%;
17
+ }
28
18
 
29
- --color-for-success: 0 0% 0%;
30
- --color-for-warning: 0 0% 0%;
31
- --color-for-error: 0 0% 0%;
19
+ /* High contrast must be pure B/W: override brand + status tokens too (prevents bleed) */
20
+ .high-contrast {
21
+ --brand-primary: 0 0% 0%;
22
+ --brand-secondary: 0 0% 0%;
23
+ --brand-accent: 0 0% 100%;
32
24
 
33
- --status-success: 0 0% 0%;
34
- --status-warning: 0 0% 0%;
35
- --status-error: 0 0% 0%;
36
- }
25
+ --status-success: 0 0% 0%;
26
+ --status-warning: 0 0% 0%;
27
+ --status-error: 0 0% 0%;
28
+ --status-info: 0 0% 0%;
37
29
  }
30
+
@@ -0,0 +1,93 @@
1
+
2
+
3
+ /* ===================
4
+ BUTTONS
5
+ =================== */
6
+ .btn-destructive {
7
+ @apply bg-destructive text-destructive-foreground hover:bg-destructive/90;
8
+ }
9
+
10
+ /* ===================
11
+ MESSAGE BUBBLES
12
+ =================== */
13
+ .msg-bubble {
14
+ @apply p-3 rounded-lg;
15
+ }
16
+
17
+ .msg-bubble--mine {
18
+ background-color: hsl(var(--primary) / 0.10);
19
+ }
20
+
21
+ .msg-bubble--theirs {
22
+ @apply bg-muted;
23
+ }
24
+
25
+ /* ===================
26
+ STATUS PILLS
27
+ =================== */
28
+ .status-pill {
29
+ @apply text-xs-bold px-2 py-0.5 rounded-full;
30
+ }
31
+
32
+ /* map to semantic tokens (no blue/yellow/green hardcodes) */
33
+ .status-pill--open-user {
34
+ background-color: hsl(var(--info) / 0.15);
35
+ color: hsl(var(--info-foreground));
36
+ }
37
+
38
+ .status-pill--admin-reply {
39
+ background-color: hsl(var(--warning) / 0.20);
40
+ color: hsl(var(--warning-foreground));
41
+ }
42
+
43
+ .status-pill--user-reply {
44
+ background-color: hsl(var(--success) / 0.18);
45
+ color: hsl(var(--success-foreground));
46
+ }
47
+
48
+ .status-pill--closed {
49
+ @apply bg-muted text-muted-foreground;
50
+ }
51
+
52
+ .status-pill--default {
53
+ @apply bg-muted text-muted-foreground;
54
+ }
55
+
56
+ /* ===================
57
+ STATUS ICONS
58
+ =================== */
59
+ .status-icon {
60
+ @apply h-5 w-5;
61
+ }
62
+
63
+ .status-icon--success { color: hsl(var(--success)); }
64
+ .status-icon--warning { color: hsl(var(--warning)); }
65
+ .status-icon--info { color: hsl(var(--info)); }
66
+ .status-icon--error { color: hsl(var(--destructive)); }
67
+
68
+ /* ===================
69
+ NOTIFICATIONS
70
+ =================== */
71
+ .notify-dot {
72
+ @apply absolute top-1 right-1 h-2 w-2 rounded-full;
73
+ background-color: hsl(var(--destructive));
74
+ }
75
+
76
+ .notify-empty-icon {
77
+ color: hsl(var(--success));
78
+ }
79
+
80
+ /* ===================
81
+ MEDIA PREVIEW
82
+ =================== */
83
+ .media-preview {
84
+ @apply relative w-full h-full;
85
+ }
86
+
87
+ .media-preview--frame {
88
+ @apply w-full h-auto max-w-sm mx-auto;
89
+ }
90
+
91
+ .media-preview--fullwidth {
92
+ @apply w-full h-auto;
93
+ }
@@ -1,4 +1,5 @@
1
1
  @import "./contract.css";
2
2
  @import "./tokens.css";
3
3
  @import "./base.css";
4
+ @import "./hooks.css";
4
5
  /* components.css is a separate entrypoint: @ttt-productions/theme-core/components.css */
@@ -1,110 +1,104 @@
1
- @layer base {
2
- :root {
3
- /* Semantic tokens (default = light) */
4
- --background: var(--neutral-white);
5
- --foreground: var(--neutral-black);
6
1
 
7
- --card: var(--neutral-white);
8
- --card-foreground: var(--neutral-black);
2
+ :root {
3
+ /* Semantic tokens (default = light) */
4
+ --background: var(--neutral-white);
5
+ --foreground: var(--neutral-black);
9
6
 
10
- --popover: var(--neutral-white);
11
- --popover-foreground: var(--neutral-black);
7
+ --card: var(--neutral-white);
8
+ --card-foreground: var(--neutral-black);
12
9
 
13
- --muted: 0 0% 95%;
14
- --muted-foreground: var(--neutral-black);
10
+ --popover: var(--neutral-white);
11
+ --popover-foreground: var(--neutral-black);
15
12
 
16
- --accent: var(--brand-accent);
17
- --accent-foreground: var(--neutral-black);
13
+ --muted: 0 0% 95%;
14
+ --muted-foreground: 0 0% 25%;
18
15
 
19
- --primary: var(--brand-primary);
20
- --primary-foreground: var(--neutral-white);
16
+ --accent: var(--brand-accent);
17
+ --accent-foreground: var(--neutral-black);
21
18
 
22
- --secondary: var(--brand-secondary);
23
- --secondary-foreground: var(--neutral-white);
19
+ --primary: var(--brand-primary);
20
+ --primary-foreground: var(--neutral-white);
24
21
 
25
- /* canonical shadcn name */
26
- --destructive: var(--status-error);
27
- --destructive-foreground: var(--neutral-white);
22
+ --secondary: var(--brand-secondary);
23
+ --secondary-foreground: var(--neutral-white);
28
24
 
29
- /* extra semantic status tokens */
30
- --success: var(--status-success);
31
- --success-foreground: var(--neutral-white);
25
+ --destructive: var(--status-error);
26
+ --destructive-foreground: var(--neutral-white);
32
27
 
33
- --warning: var(--status-warning);
34
- --warning-foreground: var(--neutral-black);
28
+ /* Extra semantic status colors (used by pills/toasts/etc.) */
29
+ --success: var(--status-success);
30
+ --success-foreground: var(--neutral-white);
35
31
 
36
- --error: var(--status-error);
37
- --error-foreground: var(--neutral-white);
32
+ --warning: var(--status-warning);
33
+ --warning-foreground: var(--neutral-black);
38
34
 
39
- --border: var(--brand-primary);
40
- --ring: var(--brand-primary);
35
+ --info: var(--status-info);
36
+ --info-foreground: var(--neutral-white);
41
37
 
42
- --radius: 1rem;
38
+ --border: var(--brand-primary);
39
+ --ring: var(--brand-primary);
43
40
 
44
- /* toast defaults (overridable per-toast via inline CSS var) */
45
- --toast-duration: 5000ms;
46
- }
41
+ --radius: 1rem;
42
+ }
47
43
 
48
- .dark {
49
- /* Keep semantic token mapping; apps can override brand tokens per-mode if they want */
50
- --background: 240 6% 10%;
51
- --foreground: 0 0% 100%;
44
+ .dark {
45
+ /* Dark base (brand tokens are still app-controlled) */
46
+ --background: 240 6% 10%;
47
+ --foreground: 0 0% 100%;
52
48
 
53
- --card: 240 6% 12%;
54
- --card-foreground: 0 0% 100%;
49
+ --card: 240 6% 12%;
50
+ --card-foreground: 0 0% 100%;
55
51
 
56
- --popover: 240 6% 12%;
57
- --popover-foreground: 0 0% 100%;
52
+ --popover: 240 6% 12%;
53
+ --popover-foreground: 0 0% 100%;
58
54
 
59
- --muted: 240 4% 20%;
60
- --muted-foreground: 0 0% 100%;
55
+ --muted: 240 4% 20%;
56
+ --muted-foreground: 0 0% 85%;
61
57
 
62
- --border: 0 0% 100%;
63
- --ring: 0 0% 100%;
58
+ --border: 0 0% 100%;
59
+ --ring: 0 0% 100%;
64
60
 
65
- /* status foregrounds in dark */
66
- --destructive-foreground: 0 0% 100%;
67
- --success-foreground: 0 0% 100%;
68
- --warning-foreground: 0 0% 0%;
69
- --error-foreground: 0 0% 100%;
70
- }
61
+ /* status foregrounds still reasonable in dark */
62
+ --success-foreground: 0 0% 0%;
63
+ --warning-foreground: 0 0% 0%;
64
+ --info-foreground: 0 0% 0%;
65
+ }
71
66
 
72
- .high-contrast {
73
- /* Pure B/W semantic tokens */
74
- --background: 0 0% 0%;
75
- --foreground: 0 0% 100%;
67
+ .high-contrast {
68
+ /* Pure B/W semantic tokens */
69
+ --background: 0 0% 0%;
70
+ --foreground: 0 0% 100%;
76
71
 
77
- --card: 0 0% 0%;
78
- --card-foreground: 0 0% 100%;
72
+ --card: 0 0% 0%;
73
+ --card-foreground: 0 0% 100%;
79
74
 
80
- --popover: 0 0% 0%;
81
- --popover-foreground: 0 0% 100%;
75
+ --popover: 0 0% 0%;
76
+ --popover-foreground: 0 0% 100%;
82
77
 
83
- --muted: 0 0% 0%;
84
- --muted-foreground: 0 0% 100%;
78
+ --muted: 0 0% 0%;
79
+ --muted-foreground: 0 0% 100%;
85
80
 
86
- --accent: 0 0% 0%;
87
- --accent-foreground: 0 0% 100%;
81
+ --accent: 0 0% 0%;
82
+ --accent-foreground: 0 0% 100%;
88
83
 
89
- --primary: 0 0% 100%;
90
- --primary-foreground: 0 0% 0%;
84
+ --primary: 0 0% 100%;
85
+ --primary-foreground: 0 0% 0%;
91
86
 
92
- --secondary: 0 0% 100%;
93
- --secondary-foreground: 0 0% 0%;
87
+ --secondary: 0 0% 100%;
88
+ --secondary-foreground: 0 0% 0%;
94
89
 
95
- --destructive: 0 0% 100%;
96
- --destructive-foreground: 0 0% 0%;
90
+ --destructive: 0 0% 100%;
91
+ --destructive-foreground: 0 0% 0%;
97
92
 
98
- --success: 0 0% 100%;
99
- --success-foreground: 0 0% 0%;
93
+ --success: 0 0% 100%;
94
+ --success-foreground: 0 0% 0%;
100
95
 
101
- --warning: 0 0% 100%;
102
- --warning-foreground: 0 0% 0%;
96
+ --warning: 0 0% 100%;
97
+ --warning-foreground: 0 0% 0%;
103
98
 
104
- --error: 0 0% 100%;
105
- --error-foreground: 0 0% 0%;
99
+ --info: 0 0% 100%;
100
+ --info-foreground: 0 0% 0%;
106
101
 
107
- --border: 0 0% 100%;
108
- --ring: 0 0% 100%;
109
- }
102
+ --border: 0 0% 100%;
103
+ --ring: 0 0% 100%;
110
104
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/theme-core",
3
- "version": "0.1.19",
3
+ "version": "0.1.22",
4
4
  "description": "Theme provider + CSS token contract for TTT Productions apps",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",