twico-ui 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.
@@ -0,0 +1,546 @@
1
+ /* ============================================================
2
+ twico-ui — bundled stylesheet (design tokens + base reset + webfonts)
3
+ Import ONCE at your app root: import "twico-ui/styles.css";
4
+ Dark mode: add class="dark" (or data-theme="dark") to <html>.
5
+ Fonts ship beside this file in ./fonts/ (self-hosted, OFL).
6
+ ============================================================ */
7
+
8
+ /* ===== tokens/fonts.css ===== */
9
+ /* ============================================================
10
+ Twico UI — Webfonts (self-hosted, OFL licensed)
11
+ Plus Jakarta Sans (UI) + JetBrains Mono (code).
12
+ Variable fonts: one file covers weights 200–800.
13
+ ============================================================ */
14
+
15
+ @font-face {
16
+ font-family: "Plus Jakarta Sans";
17
+ src: url("./fonts/PlusJakartaSans-Variable.ttf") format("truetype-variations");
18
+ font-weight: 200 800;
19
+ font-style: normal;
20
+ font-display: swap;
21
+ }
22
+
23
+ @font-face {
24
+ font-family: "Plus Jakarta Sans";
25
+ src: url("./fonts/PlusJakartaSans-Italic-Variable.ttf") format("truetype-variations");
26
+ font-weight: 200 800;
27
+ font-style: italic;
28
+ font-display: swap;
29
+ }
30
+
31
+ @font-face {
32
+ font-family: "JetBrains Mono";
33
+ src: url("./fonts/JetBrainsMono-Variable.ttf") format("truetype-variations");
34
+ font-weight: 100 800;
35
+ font-style: normal;
36
+ font-display: swap;
37
+ }
38
+
39
+ /* ===== tokens/colors.css ===== */
40
+ /* ============================================================
41
+ Twico UI — Color tokens
42
+ Primitive palettes (raw scales) + semantic aliases.
43
+ Semantic aliases flip under .dark / [data-theme="dark"].
44
+ Re-theme by overriding the --brand-* scale or the --color-* aliases.
45
+ ============================================================ */
46
+
47
+ :root {
48
+ /* ---- Primitive: Indigo (brand) ---- */
49
+ --indigo-50: #eef2ff;
50
+ --indigo-100: #e0e7ff;
51
+ --indigo-200: #c7d2fe;
52
+ --indigo-300: #a5b4fc;
53
+ --indigo-400: #818cf8;
54
+ --indigo-500: #6366f1;
55
+ --indigo-600: #4f46e5;
56
+ --indigo-700: #4338ca;
57
+ --indigo-800: #3730a3;
58
+ --indigo-900: #312e81;
59
+ --indigo-950: #1e1b4b;
60
+
61
+ /* Brand alias — remap these to re-skin the whole library */
62
+ --brand-50: var(--indigo-50);
63
+ --brand-100: var(--indigo-100);
64
+ --brand-200: var(--indigo-200);
65
+ --brand-300: var(--indigo-300);
66
+ --brand-400: var(--indigo-400);
67
+ --brand-500: var(--indigo-500);
68
+ --brand-600: var(--indigo-600);
69
+ --brand-700: var(--indigo-700);
70
+ --brand-800: var(--indigo-800);
71
+ --brand-900: var(--indigo-900);
72
+ --brand-950: var(--indigo-950);
73
+
74
+ /* ---- Primitive: Slate (neutral) ---- */
75
+ --slate-50: #f8fafc;
76
+ --slate-100: #f1f5f9;
77
+ --slate-200: #e2e8f0;
78
+ --slate-300: #cbd5e1;
79
+ --slate-400: #94a3b8;
80
+ --slate-500: #64748b;
81
+ --slate-600: #475569;
82
+ --slate-700: #334155;
83
+ --slate-800: #1e293b;
84
+ --slate-900: #0f172a;
85
+ --slate-950: #020617;
86
+
87
+ /* ---- Primitive: Semantic hues ---- */
88
+ --emerald-400: #34d399;
89
+ --emerald-500: #10b981;
90
+ --emerald-600: #059669;
91
+ --emerald-50: #ecfdf5;
92
+
93
+ --amber-400: #fbbf24;
94
+ --amber-500: #f59e0b;
95
+ --amber-600: #d97706;
96
+ --amber-50: #fffbeb;
97
+
98
+ --rose-400: #fb7185;
99
+ --rose-500: #f43f5e;
100
+ --rose-600: #e11d48;
101
+ --rose-50: #fff1f2;
102
+
103
+ --sky-400: #38bdf8;
104
+ --sky-500: #0ea5e9;
105
+ --sky-600: #0284c7;
106
+ --sky-50: #f0f9ff;
107
+
108
+ /* ============================================================
109
+ SEMANTIC ALIASES — LIGHT (default)
110
+ ============================================================ */
111
+
112
+ /* Surfaces & backgrounds */
113
+ --color-bg: var(--slate-50); /* app/page background */
114
+ --color-surface: #ffffff; /* cards, panels, sheets */
115
+ --color-surface-raised: #ffffff; /* menus, popovers (with shadow) */
116
+ --color-surface-sunken: var(--slate-100); /* wells, inset areas */
117
+ --color-overlay: rgb(15 23 42 / 0.45); /* modal scrim */
118
+
119
+ /* Borders & dividers */
120
+ --color-border: var(--slate-200);
121
+ --color-border-strong: var(--slate-300);
122
+ --color-divider: var(--slate-200);
123
+
124
+ /* Text */
125
+ --color-text: var(--slate-900);
126
+ --color-text-muted: var(--slate-600);
127
+ --color-text-subtle: var(--slate-400);
128
+ --color-text-inverted: #ffffff;
129
+
130
+ /* Primary / brand */
131
+ --color-primary: var(--brand-500);
132
+ --color-primary-hover: var(--brand-600);
133
+ --color-primary-active: var(--brand-700);
134
+ --color-primary-fg: #ffffff;
135
+ --color-primary-subtle: var(--brand-50);
136
+ --color-primary-subtle-fg: var(--brand-700);
137
+ --color-primary-border: var(--brand-200);
138
+
139
+ /* Focus ring */
140
+ --color-ring: rgb(99 102 241 / 0.45);
141
+
142
+ /* Success */
143
+ --color-success: var(--emerald-600);
144
+ --color-success-fg: #ffffff;
145
+ --color-success-subtle: var(--emerald-50);
146
+ --color-success-subtle-fg: var(--emerald-600);
147
+
148
+ /* Warning */
149
+ --color-warning: var(--amber-500);
150
+ --color-warning-fg: #ffffff;
151
+ --color-warning-subtle: var(--amber-50);
152
+ --color-warning-subtle-fg: var(--amber-600);
153
+
154
+ /* Danger */
155
+ --color-danger: var(--rose-500);
156
+ --color-danger-hover: var(--rose-600);
157
+ --color-danger-fg: #ffffff;
158
+ --color-danger-subtle: var(--rose-50);
159
+ --color-danger-subtle-fg: var(--rose-600);
160
+
161
+ /* Info */
162
+ --color-info: var(--sky-500);
163
+ --color-info-fg: #ffffff;
164
+ --color-info-subtle: var(--sky-50);
165
+ --color-info-subtle-fg: var(--sky-600);
166
+ }
167
+
168
+ /* ============================================================
169
+ SEMANTIC ALIASES — DARK
170
+ Toggle by adding class="dark" or data-theme="dark" to <html>.
171
+ ============================================================ */
172
+
173
+ .dark,
174
+ [data-theme="dark"] {
175
+ --color-bg: var(--slate-950);
176
+ --color-surface: var(--slate-900);
177
+ --color-surface-raised: var(--slate-800);
178
+ --color-surface-sunken: #0b1222;
179
+ --color-overlay: rgb(2 6 23 / 0.65);
180
+
181
+ --color-border: #25324a;
182
+ --color-border-strong: var(--slate-700);
183
+ --color-divider: #1c2840;
184
+
185
+ --color-text: var(--slate-50);
186
+ --color-text-muted: var(--slate-300);
187
+ --color-text-subtle: var(--slate-500);
188
+ --color-text-inverted: var(--slate-900);
189
+
190
+ --color-primary: var(--brand-500);
191
+ --color-primary-hover: var(--brand-400);
192
+ --color-primary-active: var(--brand-300);
193
+ --color-primary-fg: #ffffff;
194
+ --color-primary-subtle: rgb(99 102 241 / 0.16);
195
+ --color-primary-subtle-fg: var(--brand-300);
196
+ --color-primary-border: rgb(99 102 241 / 0.35);
197
+
198
+ --color-ring: rgb(129 140 248 / 0.55);
199
+
200
+ --color-success: var(--emerald-500);
201
+ --color-success-fg: #052e1d;
202
+ --color-success-subtle: rgb(16 185 129 / 0.15);
203
+ --color-success-subtle-fg: var(--emerald-400);
204
+
205
+ --color-warning: var(--amber-500);
206
+ --color-warning-fg: #2c1701;
207
+ --color-warning-subtle: rgb(245 158 11 / 0.15);
208
+ --color-warning-subtle-fg: var(--amber-400);
209
+
210
+ --color-danger: var(--rose-500);
211
+ --color-danger-hover: var(--rose-400);
212
+ --color-danger-fg: #2c0610;
213
+ --color-danger-subtle: rgb(244 63 94 / 0.15);
214
+ --color-danger-subtle-fg: var(--rose-400);
215
+
216
+ --color-info: var(--sky-500);
217
+ --color-info-fg: #04212f;
218
+ --color-info-subtle: rgb(14 165 233 / 0.15);
219
+ --color-info-subtle-fg: var(--sky-400);
220
+ }
221
+
222
+ /* ===== tokens/typography.css ===== */
223
+ /* ============================================================
224
+ Twico UI — Typography tokens
225
+ Family: Plus Jakarta Sans (UI) · JetBrains Mono (code)
226
+ ============================================================ */
227
+
228
+ :root {
229
+ /* Families */
230
+ --font-sans: "Plus Jakarta Sans", ui-sans-serif, system-ui, -apple-system,
231
+ "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
232
+ --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Code",
233
+ Menlo, Consolas, monospace;
234
+
235
+ /* Type scale (rem, 16px root) */
236
+ --text-xs: 0.75rem; /* 12 */
237
+ --text-sm: 0.875rem; /* 14 */
238
+ --text-base: 1rem; /* 16 */
239
+ --text-lg: 1.125rem; /* 18 */
240
+ --text-xl: 1.25rem; /* 20 */
241
+ --text-2xl: 1.5rem; /* 24 */
242
+ --text-3xl: 1.875rem; /* 30 */
243
+ --text-4xl: 2.25rem; /* 36 */
244
+ --text-5xl: 3rem; /* 48 */
245
+ --text-6xl: 3.75rem; /* 60 */
246
+ --text-7xl: 4.5rem; /* 72 */
247
+
248
+ /* Weights */
249
+ --font-normal: 400;
250
+ --font-medium: 500;
251
+ --font-semibold: 600;
252
+ --font-bold: 700;
253
+ --font-extrabold: 800;
254
+
255
+ /* Line heights */
256
+ --leading-none: 1;
257
+ --leading-tight: 1.2;
258
+ --leading-snug: 1.35;
259
+ --leading-normal: 1.5;
260
+ --leading-relaxed: 1.65;
261
+
262
+ /* Letter spacing */
263
+ --tracking-tighter: -0.03em; /* display headings */
264
+ --tracking-tight: -0.015em; /* headings */
265
+ --tracking-normal: 0em;
266
+ --tracking-wide: 0.02em;
267
+ --tracking-wider: 0.06em; /* eyebrows / labels (uppercase) */
268
+
269
+ /* Semantic role tokens */
270
+ --text-display: var(--text-6xl);
271
+ --text-h1: var(--text-4xl);
272
+ --text-h2: var(--text-3xl);
273
+ --text-h3: var(--text-2xl);
274
+ --text-h4: var(--text-xl);
275
+ --text-body: var(--text-base);
276
+ --text-body-sm: var(--text-sm);
277
+ --text-caption: var(--text-xs);
278
+ }
279
+
280
+ /* ===== tokens/spacing.css ===== */
281
+ /* ============================================================
282
+ Twico UI — Spacing & sizing tokens
283
+ 4px base grid.
284
+ ============================================================ */
285
+
286
+ :root {
287
+ --space-0: 0;
288
+ --space-px: 1px;
289
+ --space-0-5: 0.125rem; /* 2 */
290
+ --space-1: 0.25rem; /* 4 */
291
+ --space-1-5: 0.375rem; /* 6 */
292
+ --space-2: 0.5rem; /* 8 */
293
+ --space-2-5: 0.625rem; /* 10 */
294
+ --space-3: 0.75rem; /* 12 */
295
+ --space-4: 1rem; /* 16 */
296
+ --space-5: 1.25rem; /* 20 */
297
+ --space-6: 1.5rem; /* 24 */
298
+ --space-7: 1.75rem; /* 28 */
299
+ --space-8: 2rem; /* 32 */
300
+ --space-10: 2.5rem; /* 40 */
301
+ --space-12: 3rem; /* 48 */
302
+ --space-16: 4rem; /* 64 */
303
+ --space-20: 5rem; /* 80 */
304
+ --space-24: 6rem; /* 96 */
305
+ --space-32: 8rem; /* 128 */
306
+
307
+ /* Control heights (consistent across buttons / inputs / selects) */
308
+ --control-h-sm: 2rem; /* 32 */
309
+ --control-h-md: 2.5rem; /* 40 */
310
+ --control-h-lg: 3rem; /* 48 */
311
+
312
+ /* Layout */
313
+ --container-sm: 640px;
314
+ --container-md: 768px;
315
+ --container-lg: 1024px;
316
+ --container-xl: 1280px;
317
+ --container-2xl: 1440px;
318
+
319
+ /* Z-index scale */
320
+ --z-base: 0; /* @kind other */
321
+ --z-dropdown: 1000; /* @kind other */
322
+ --z-sticky: 1100; /* @kind other */
323
+ --z-overlay: 1200; /* @kind other */
324
+ --z-modal: 1300; /* @kind other */
325
+ --z-popover: 1400; /* @kind other */
326
+ --z-toast: 1500; /* @kind other */
327
+ --z-tooltip: 1600; /* @kind other */
328
+ }
329
+
330
+ /* ===== tokens/radius.css ===== */
331
+ /* ============================================================
332
+ Twico UI — Radius, borders & elevation
333
+ No pointy corners — everything rounds.
334
+ ============================================================ */
335
+
336
+ :root {
337
+ /* Corner radii — base control radius is --radius-md (10px) */
338
+ --radius-xs: 4px;
339
+ --radius-sm: 6px;
340
+ --radius-md: 10px; /* buttons, inputs, selects, badges */
341
+ --radius-lg: 14px; /* cards, popovers, menus */
342
+ --radius-xl: 18px; /* large cards, sheets */
343
+ --radius-2xl: 24px; /* hero panels, modals */
344
+ --radius-full: 9999px; /* pills, avatars, switches */
345
+
346
+ /* Border widths */
347
+ --border-thin: 1px;
348
+ --border-medium: 1.5px;
349
+ --border-thick: 2px;
350
+
351
+ /* Elevation — soft, slate-tinted, crisp (light) */
352
+ --shadow-xs: 0 1px 2px 0 rgb(15 23 42 / 0.05);
353
+ --shadow-sm: 0 1px 3px 0 rgb(15 23 42 / 0.08), 0 1px 2px -1px rgb(15 23 42 / 0.06);
354
+ --shadow-md: 0 4px 12px -2px rgb(15 23 42 / 0.10), 0 2px 6px -2px rgb(15 23 42 / 0.06);
355
+ --shadow-lg: 0 12px 28px -6px rgb(15 23 42 / 0.14), 0 4px 10px -4px rgb(15 23 42 / 0.08);
356
+ --shadow-xl: 0 24px 48px -12px rgb(15 23 42 / 0.20), 0 8px 16px -8px rgb(15 23 42 / 0.10);
357
+
358
+ /* Brand-tinted glow (primary buttons on hover, focus accents) */
359
+ --shadow-brand: 0 8px 24px -6px rgb(99 102 241 / 0.45);
360
+
361
+ /* Focus ring (composable as box-shadow) */
362
+ --ring-width: 3px;
363
+ --ring: 0 0 0 var(--ring-width) var(--color-ring);
364
+ --ring-offset: 0 0 0 2px var(--color-surface), 0 0 0 5px var(--color-ring);
365
+ }
366
+
367
+ /* Deeper, darker elevation in dark mode */
368
+ .dark,
369
+ [data-theme="dark"] {
370
+ --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.30);
371
+ --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.40), 0 1px 2px -1px rgb(0 0 0 / 0.30);
372
+ --shadow-md: 0 4px 12px -2px rgb(0 0 0 / 0.50), 0 2px 6px -2px rgb(0 0 0 / 0.40);
373
+ --shadow-lg: 0 12px 28px -6px rgb(0 0 0 / 0.60), 0 4px 10px -4px rgb(0 0 0 / 0.45);
374
+ --shadow-xl: 0 24px 48px -12px rgb(0 0 0 / 0.70), 0 8px 16px -8px rgb(0 0 0 / 0.50);
375
+ --shadow-brand: 0 8px 28px -6px rgb(99 102 241 / 0.60);
376
+ }
377
+
378
+ /* ===== tokens/motion.css ===== */
379
+ /* ============================================================
380
+ Twico UI — Motion tokens & keyframes
381
+ Lively: spring entrances, gentle press-scale, ripples.
382
+ ============================================================ */
383
+
384
+ :root {
385
+ /* Durations */
386
+ --duration-instant: 80ms; /* @kind other */
387
+ --duration-fast: 140ms; /* @kind other */
388
+ --duration-base: 220ms; /* @kind other */
389
+ --duration-slow: 320ms; /* @kind other */
390
+ --duration-slower: 480ms; /* @kind other */
391
+
392
+ /* Easing curves */
393
+ --ease-standard: cubic-bezier(0.4, 0, 0.2, 1); /* @kind other */
394
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* @kind other */
395
+ --ease-in: cubic-bezier(0.4, 0, 1, 1); /* @kind other */
396
+ --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* @kind other */
397
+ --ease-emphasis: cubic-bezier(0.2, 0.8, 0.2, 1); /* @kind other */
398
+
399
+ /* Press feedback */
400
+ --press-scale: 0.96; /* @kind other */
401
+ }
402
+
403
+ /* ---- Keyframes ---- */
404
+ @keyframes twico-fade-in {
405
+ from { opacity: 0; }
406
+ to { opacity: 1; }
407
+ }
408
+
409
+ @keyframes twico-scale-in {
410
+ from { opacity: 0; transform: scale(0.94); }
411
+ to { opacity: 1; transform: scale(1); }
412
+ }
413
+
414
+ @keyframes twico-pop-in {
415
+ 0% { opacity: 0; transform: scale(0.85); }
416
+ 60% { opacity: 1; transform: scale(1.03); }
417
+ 100% { opacity: 1; transform: scale(1); }
418
+ }
419
+
420
+ @keyframes twico-slide-up {
421
+ from { opacity: 0; transform: translateY(10px); }
422
+ to { opacity: 1; transform: translateY(0); }
423
+ }
424
+
425
+ @keyframes twico-slide-down {
426
+ from { opacity: 0; transform: translateY(-10px); }
427
+ to { opacity: 1; transform: translateY(0); }
428
+ }
429
+
430
+ @keyframes twico-slide-in-right {
431
+ from { opacity: 0; transform: translateX(24px); }
432
+ to { opacity: 1; transform: translateX(0); }
433
+ }
434
+
435
+ @keyframes twico-spin {
436
+ to { transform: rotate(360deg); }
437
+ }
438
+
439
+ @keyframes twico-ripple {
440
+ to { transform: scale(2.6); opacity: 0; }
441
+ }
442
+
443
+ @keyframes twico-shimmer {
444
+ 100% { transform: translateX(100%); }
445
+ }
446
+
447
+ @keyframes twico-pulse {
448
+ 0%, 100% { opacity: 1; }
449
+ 50% { opacity: 0.5; }
450
+ }
451
+
452
+ @keyframes twico-progress-indeterminate {
453
+ 0% { left: -40%; right: 100%; }
454
+ 60% { left: 100%; right: -90%; }
455
+ 100% { left: 100%; right: -90%; }
456
+ }
457
+
458
+ /* ===== base.css ===== */
459
+ /* ============================================================
460
+ Twico UI — Base layer
461
+ Minimal, non-destructive resets + sensible element defaults.
462
+ Applies the brand font + semantic colors to the document.
463
+ ============================================================ */
464
+
465
+ *,
466
+ *::before,
467
+ *::after {
468
+ box-sizing: border-box;
469
+ }
470
+
471
+ html {
472
+ -webkit-text-size-adjust: 100%;
473
+ text-size-adjust: 100%;
474
+ font-feature-settings: "cv05" 1; /* single-storey a for Plus Jakarta */
475
+ }
476
+
477
+ body {
478
+ margin: 0;
479
+ font-family: var(--font-sans);
480
+ font-size: var(--text-base);
481
+ line-height: var(--leading-normal);
482
+ font-weight: var(--font-normal);
483
+ color: var(--color-text);
484
+ background-color: var(--color-bg);
485
+ -webkit-font-smoothing: antialiased;
486
+ -moz-osx-font-smoothing: grayscale;
487
+ text-rendering: optimizeLegibility;
488
+ transition: background-color var(--duration-base) var(--ease-standard),
489
+ color var(--duration-base) var(--ease-standard);
490
+ }
491
+
492
+ h1, h2, h3, h4, h5, h6 {
493
+ margin: 0;
494
+ font-weight: var(--font-bold);
495
+ line-height: var(--leading-tight);
496
+ letter-spacing: var(--tracking-tight);
497
+ color: var(--color-text);
498
+ }
499
+
500
+ p { margin: 0; }
501
+
502
+ a {
503
+ color: var(--color-primary);
504
+ text-decoration: none;
505
+ transition: color var(--duration-fast) var(--ease-standard);
506
+ }
507
+ a:hover { color: var(--color-primary-hover); }
508
+
509
+ code, pre, kbd, samp {
510
+ font-family: var(--font-mono);
511
+ font-size: 0.9em;
512
+ }
513
+
514
+ /* Keyboard focus ring for standalone interactive elements.
515
+ NOTE: text inputs / textarea / select are deliberately excluded — in Twico UI
516
+ every text field lives inside a bordered wrapper that shows focus via
517
+ :focus-within, so the bare control must NOT paint its own box ring (that was
518
+ the recurring "boxy purple outline" on search/command inputs). A field that is
519
+ genuinely standalone opts back in with its own higher-specificity :focus rule
520
+ (e.g. .twc-pagination__jump input, .twc-cp__hex). */
521
+ :focus-visible {
522
+ outline: none;
523
+ box-shadow: var(--ring);
524
+ }
525
+ input:focus-visible,
526
+ textarea:focus-visible,
527
+ select:focus-visible {
528
+ box-shadow: none;
529
+ }
530
+
531
+ ::selection {
532
+ background: var(--color-primary-subtle);
533
+ color: var(--color-primary-subtle-fg);
534
+ }
535
+
536
+ /* Honor reduced-motion globally */
537
+ @media (prefers-reduced-motion: reduce) {
538
+ *,
539
+ *::before,
540
+ *::after {
541
+ animation-duration: 0.01ms !important;
542
+ animation-iteration-count: 1 !important;
543
+ transition-duration: 0.01ms !important;
544
+ scroll-behavior: auto !important;
545
+ }
546
+ }