@sarchauhan/chat 0.0.0-stage → 0.0.1

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,30 @@
1
+ /* transitions-dev — 09-icon-swap.md (verbatim) */
2
+
3
+ .t-icon-swap {
4
+ position: relative;
5
+ display: inline-grid;
6
+ }
7
+ .t-icon-swap .t-icon {
8
+ grid-area: 1 / 1;
9
+ transition:
10
+ opacity var(--icon-swap-dur) var(--icon-swap-ease),
11
+ filter var(--icon-swap-dur) var(--icon-swap-ease),
12
+ transform var(--icon-swap-dur) var(--icon-swap-ease);
13
+ will-change: opacity, filter, transform;
14
+ }
15
+ .t-icon-swap[data-state="a"] .t-icon[data-icon="a"],
16
+ .t-icon-swap[data-state="b"] .t-icon[data-icon="b"] {
17
+ opacity: 1;
18
+ filter: blur(0);
19
+ transform: scale(1);
20
+ }
21
+ .t-icon-swap[data-state="a"] .t-icon[data-icon="b"],
22
+ .t-icon-swap[data-state="b"] .t-icon[data-icon="a"] {
23
+ opacity: 0;
24
+ filter: blur(var(--icon-swap-blur));
25
+ transform: scale(var(--icon-swap-start-scale));
26
+ }
27
+
28
+ @media (prefers-reduced-motion: reduce) {
29
+ .t-icon-swap .t-icon { transition: none !important; }
30
+ }
@@ -0,0 +1,6 @@
1
+ @import "./tokens.css";
2
+ @import "./text-states-swap.css";
3
+ @import "./icon-swap.css";
4
+ @import "./success-check.css";
5
+ @import "./menu-dropdown.css";
6
+ @import "./error-state-shake.css";
@@ -0,0 +1,35 @@
1
+ /* transitions-dev — 05-menu-dropdown.md (verbatim) */
2
+
3
+ .t-dropdown {
4
+ transform-origin: top left;
5
+ transform: scale(var(--dropdown-pre-scale));
6
+ opacity: 0;
7
+ pointer-events: none;
8
+ transition:
9
+ transform var(--dropdown-open-dur) var(--dropdown-ease),
10
+ opacity var(--dropdown-open-dur) var(--dropdown-ease);
11
+ will-change: transform, opacity;
12
+ }
13
+ .t-dropdown[data-origin="top-right"] { transform-origin: top right; }
14
+ .t-dropdown[data-origin="top-center"] { transform-origin: top center; }
15
+ .t-dropdown[data-origin="bottom-left"] { transform-origin: bottom left; }
16
+ .t-dropdown[data-origin="bottom-center"] { transform-origin: bottom center; }
17
+ .t-dropdown[data-origin="bottom-right"] { transform-origin: bottom right; }
18
+
19
+ .t-dropdown.is-open {
20
+ transform: scale(1);
21
+ opacity: 1;
22
+ pointer-events: auto;
23
+ }
24
+ .t-dropdown.is-closing {
25
+ transform: scale(var(--dropdown-closing-scale));
26
+ opacity: 0;
27
+ pointer-events: none;
28
+ transition:
29
+ transform var(--dropdown-close-dur) var(--dropdown-ease),
30
+ opacity var(--dropdown-close-dur) var(--dropdown-ease);
31
+ }
32
+
33
+ @media (prefers-reduced-motion: reduce) {
34
+ .t-dropdown { transition: none !important; }
35
+ }
@@ -0,0 +1,51 @@
1
+ /* transitions-dev — 10-success-check.md (verbatim) */
2
+
3
+ /* Wrapper drives the appear animation; it doesn't own any
4
+ sizing or color so you can drop in any icon. */
5
+ .t-success-check {
6
+ display: inline-block;
7
+ transform-origin: center;
8
+ opacity: 0;
9
+ will-change: transform, opacity, filter;
10
+ }
11
+ /* overflow: visible keeps the stroke from clipping while it
12
+ draws; display: block kills the inline whitespace under SVGs. */
13
+ .t-success-check svg { display: block; overflow: visible; }
14
+ /* Stroke-draw setup. Replace 20 with the result of
15
+ path.getTotalLength() for your path; round caps mean any
16
+ sub-pixel overshoot is invisible. */
17
+ .t-success-check svg path {
18
+ stroke-dasharray: 20;
19
+ stroke-dashoffset: 20;
20
+ }
21
+
22
+ .t-success-check[data-state="in"] {
23
+ animation:
24
+ t-check-fade var(--check-opacity-dur) var(--check-ease-opacity) forwards,
25
+ t-check-rotate var(--check-rotate-dur) var(--check-ease-rotate) forwards,
26
+ t-check-blur var(--check-blur-dur) var(--check-ease-out) forwards,
27
+ t-check-bob var(--check-bob-dur) var(--check-ease-bob) forwards;
28
+ }
29
+ .t-success-check[data-state="in"] svg path {
30
+ animation: t-check-draw var(--check-path-dur) var(--check-ease-path) var(--check-path-delay, 0ms) forwards;
31
+ }
32
+
33
+ @keyframes t-check-fade { from { opacity: 0; } to { opacity: 1; } }
34
+ @keyframes t-check-rotate {
35
+ from { transform: rotate(var(--check-rotate-from)); }
36
+ to { transform: rotate(0deg); }
37
+ }
38
+ @keyframes t-check-blur {
39
+ from { filter: blur(var(--check-blur-from)); }
40
+ to { filter: blur(0); }
41
+ }
42
+ @keyframes t-check-bob {
43
+ from { translate: 0 var(--check-y-amount); }
44
+ to { translate: 0 0; }
45
+ }
46
+ @keyframes t-check-draw { to { stroke-dashoffset: 0; } }
47
+
48
+ @media (prefers-reduced-motion: reduce) {
49
+ .t-success-check { animation: none !important; opacity: 1; }
50
+ .t-success-check svg path { animation: none !important; stroke-dashoffset: 0 !important; }
51
+ }
@@ -0,0 +1,28 @@
1
+ /* transitions-dev — 04-text-states-swap.md (verbatim) */
2
+
3
+ .t-text-swap {
4
+ display: inline-block;
5
+ transform: translateY(0);
6
+ filter: blur(0);
7
+ opacity: 1;
8
+ transition:
9
+ transform var(--text-swap-dur) var(--text-swap-ease),
10
+ filter var(--text-swap-dur) var(--text-swap-ease),
11
+ opacity var(--text-swap-dur) var(--text-swap-ease);
12
+ will-change: transform, filter, opacity;
13
+ }
14
+ .t-text-swap.is-exit {
15
+ transform: translateY(calc(var(--text-swap-translate-y) * -1));
16
+ filter: blur(var(--text-swap-blur));
17
+ opacity: 0;
18
+ }
19
+ .t-text-swap.is-enter-start {
20
+ transform: translateY(var(--text-swap-translate-y));
21
+ filter: blur(var(--text-swap-blur));
22
+ opacity: 0;
23
+ transition: none;
24
+ }
25
+
26
+ @media (prefers-reduced-motion: reduce) {
27
+ .t-text-swap { transition: none !important; }
28
+ }
@@ -0,0 +1,96 @@
1
+ /* transitions-dev — install block scoped to .chat-root so host pages
2
+ do not inherit global :root motion vars. Variable names are unchanged.
3
+ Source: https://github.com/Jakubantalik/transitions-dev/blob/main/skills/transitions-dev/_root.css */
4
+
5
+ .chat-root {
6
+ /* Card resize */
7
+ --resize-dur: 300ms;
8
+ --resize-ease: cubic-bezier(0.22, 1, 0.36, 1);
9
+ /* Number pop-in */
10
+ --digit-dur: 500ms;
11
+ --digit-distance: 8px;
12
+ --digit-stagger: 70ms;
13
+ --digit-blur: 2px;
14
+ --digit-ease: cubic-bezier(0.34, 1.45, 0.64, 1);
15
+ --digit-dir-x: 0;
16
+ --digit-dir-y: 1;
17
+ /* Notification badge */
18
+ --badge-slide-dur: 260ms;
19
+ --badge-pop-dur: 500ms;
20
+ --badge-pop-close-dur: 180ms;
21
+ --badge-fade-dur: 400ms;
22
+ --badge-fade-close-dur: 180ms;
23
+ --badge-blur: 2px;
24
+ --badge-offset-x: -8.2px;
25
+ --badge-offset-y: 12.4px;
26
+ --badge-slide-ease: cubic-bezier(0.22, 1, 0.36, 1);
27
+ --badge-pop-ease: cubic-bezier(0.34, 1.36, 0.64, 1);
28
+ --badge-close-ease: cubic-bezier(0.4, 0, 0.2, 1);
29
+ /* Text states swap */
30
+ --text-swap-dur: 200ms;
31
+ --text-swap-translate-y: 8px;
32
+ --text-swap-blur: 2px;
33
+ --text-swap-ease: ease-out;
34
+ /* Menu dropdown */
35
+ --dropdown-open-dur: 250ms;
36
+ --dropdown-close-dur: 150ms;
37
+ --dropdown-pre-scale: 0.97;
38
+ --dropdown-closing-scale: 0.99;
39
+ --dropdown-ease: cubic-bezier(0.22, 1, 0.36, 1);
40
+ /* Modal open / close */
41
+ --modal-open-dur: 250ms;
42
+ --modal-close-dur: 150ms;
43
+ --modal-scale: 0.96;
44
+ --modal-scale-close: 0.96;
45
+ --modal-ease: cubic-bezier(0.22, 1, 0.36, 1);
46
+ /* Panel reveal */
47
+ --panel-open-dur: 400ms;
48
+ --panel-close-dur: 350ms;
49
+ --panel-translate-y: 100px;
50
+ --panel-blur: 2px;
51
+ --panel-ease: cubic-bezier(0.22, 1, 0.36, 1);
52
+ /* Page side-by-side */
53
+ --page-slide-dur: 200ms;
54
+ --page-fade-dur: 200ms;
55
+ --page-slide-distance: 8px;
56
+ --page-blur: 3px;
57
+ --page-stagger: 0ms;
58
+ --page-exit-enabled: 1;
59
+ --page-slide-ease: cubic-bezier(0.22, 1, 0.36, 1);
60
+ --page-fade-ease: cubic-bezier(0.22, 1, 0.36, 1);
61
+ /* Icon swap */
62
+ --icon-swap-dur: 200ms;
63
+ --icon-swap-blur: 2px;
64
+ --icon-swap-start-scale: 0.25;
65
+ --icon-swap-ease: ease-in-out;
66
+ /* Success check — defaults from the recipe; tool chips override locally */
67
+ --check-opacity-dur: 550ms;
68
+ --check-rotate-dur: 550ms;
69
+ --check-rotate-from: 80deg;
70
+ --check-bob-dur: 450ms;
71
+ --check-y-amount: 40px;
72
+ --check-blur-dur: 500ms;
73
+ --check-blur-from: 10px;
74
+ --check-path-dur: 550ms;
75
+ --check-path-delay: 80ms;
76
+ --check-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
77
+ --check-ease-opacity: cubic-bezier(0.22, 1, 0.36, 1);
78
+ --check-ease-rotate: cubic-bezier(0.22, 1, 0.36, 1);
79
+ --check-ease-bob: cubic-bezier(0.34, 1.35, 0.64, 1);
80
+ --check-ease-path: cubic-bezier(0.22, 1, 0.36, 1);
81
+ /* Avatar group hover */
82
+ --avatar-lift: -4px;
83
+ --avatar-dur: 320ms;
84
+ --avatar-scale: 1.05;
85
+ --avatar-falloff: 0.45;
86
+ --avatar-ease-in: cubic-bezier(0.22, 1, 0.36, 1);
87
+ --avatar-ease-out: cubic-bezier(0.34, 3.85, 0.64, 1);
88
+ /* Error state shake */
89
+ --shake-distance: 6px;
90
+ --shake-overshoot: 4px;
91
+ --shake-dur-a: 80ms;
92
+ --shake-dur-b: 60ms;
93
+ --shake-ease: cubic-bezier(0.22, 1, 0.36, 1);
94
+ --revert-hold: 3000ms;
95
+ --revert-dur: 280ms;
96
+ }
@@ -0,0 +1,11 @@
1
+ @import "@fontsource/geist-sans/latin.css";
2
+ @import "@fontsource/geist-mono/latin.css";
3
+ @import "@sarchauhan/code-markdown/styles.css";
4
+ @import "./theme/typography.css";
5
+ @import "./markdown.css";
6
+ @import "./chat.css";
7
+ @import "./chat.select.css";
8
+ @import "./blocks.css";
9
+ @import "./chips.css";
10
+ @import "./widgets.css";
11
+ @import "./motion/index.css";
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Chat design tokens.
3
+ *
4
+ * Vercel restraint, content-first reading column: calm neutrals, clear
5
+ * turn-taking. Hierarchy comes from type and spacing; color only marks
6
+ * real state (streaming, approval, error). Chrome stays quiet. See
7
+ * /design.md — do not invent a parallel visual system.
8
+ */
9
+
10
+ .chat-root,
11
+ .chat-root[data-theme="light"] {
12
+ color-scheme: light;
13
+
14
+ /* Surfaces */
15
+ --chat-bg: #f7f7f8;
16
+ --chat-bg-elevated: #ffffff;
17
+ --chat-fg: #0d0d0d;
18
+ --chat-fg-muted: #6e6e80;
19
+ --chat-fg-subtle: #8e8ea0;
20
+
21
+ /* Conversation roles */
22
+ --chat-user-bg: #ececf1;
23
+ --chat-user-fg: #0d0d0d;
24
+ --chat-assistant-fg: #0d0d0d;
25
+
26
+ /* Chrome */
27
+ --chat-border: rgba(0, 0, 0, 0.08);
28
+ --chat-border-strong: rgba(0, 0, 0, 0.12);
29
+ --chat-ring: rgba(0, 0, 0, 0.18);
30
+ --chat-overlay: rgba(247, 247, 248, 0.92);
31
+ --chat-composer-bg: #ffffff;
32
+ --chat-composer-shadow:
33
+ 0 0 0 1px rgba(0, 0, 0, 0.06),
34
+ 0 4px 16px rgba(0, 0, 0, 0.04);
35
+ --chat-control-bg: rgba(0, 0, 0, 0.04);
36
+ --chat-control-hover: rgba(0, 0, 0, 0.07);
37
+ --chat-primary: #0d0d0d;
38
+ --chat-primary-fg: #ffffff;
39
+ --chat-danger: #b42318;
40
+ --chat-accent: #10a37f;
41
+ --chat-warning: #d97706;
42
+ --chat-success: #059669;
43
+
44
+ /* Type — Geist tryout (opt-in, falls back to system) */
45
+ --chat-font-sans: "Geist Sans", "Geist", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
46
+ "Segoe UI", sans-serif;
47
+ --chat-font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
48
+
49
+ /* Type scale — 11 / 12 / 13 / 14 / 15.5 / 16 / 18 / 22 */
50
+ --chat-fs-11: 0.6875rem;
51
+ --chat-fs-12: 0.75rem;
52
+ --chat-fs-13: 0.8125rem;
53
+ --chat-fs-14: 0.875rem;
54
+ --chat-fs-15: 0.9375rem;
55
+ --chat-fs-155: 0.975rem;
56
+ --chat-fs-16: 1rem;
57
+ --chat-fs-18: 1.125rem;
58
+ --chat-fs-22: 1.375rem;
59
+
60
+ /* Legacy aliases — keep for compat, all map to scale */
61
+ --chat-text: var(--chat-fs-155);
62
+ --chat-text-sm: var(--chat-fs-14);
63
+ --chat-text-xs: var(--chat-fs-12);
64
+
65
+ /* Leading — paired to size */
66
+ --chat-leading-none: 1;
67
+ --chat-leading-tight: 1.25;
68
+ --chat-leading-snug: 1.35;
69
+ --chat-leading-normal: 1.5;
70
+ --chat-leading-relaxed: 1.7;
71
+ --chat-leading: var(--chat-leading-relaxed);
72
+ --chat-leading-body: var(--chat-leading-relaxed);
73
+ --chat-leading-ui: var(--chat-leading-snug);
74
+ --chat-leading-heading: var(--chat-leading-tight);
75
+
76
+ /* Weight — 400 / 500 / 600 / 700 only */
77
+ --chat-weight-regular: 400;
78
+ --chat-weight-medium: 500;
79
+ --chat-weight-semibold: 600;
80
+ --chat-weight-bold: 700;
81
+
82
+ /* Tracking */
83
+ --chat-tracking-tighter: -0.03em;
84
+ --chat-tracking-tight: -0.02em;
85
+ --chat-tracking-snug: -0.015em;
86
+ --chat-tracking-normal: -0.01em;
87
+ --chat-tracking-wide: 0.03em;
88
+
89
+ /* Semantic type — body / heading / label / caption / code */
90
+ --chat-body-size: var(--chat-fs-155);
91
+ --chat-body-leading: 1.65;
92
+ --chat-body-weight: var(--chat-weight-regular);
93
+ --chat-body-tracking: -0.011em;
94
+
95
+ --chat-body-sm-size: var(--chat-fs-14);
96
+ --chat-body-sm-leading: var(--chat-leading-normal);
97
+ --chat-body-sm-weight: var(--chat-weight-regular);
98
+
99
+ --chat-heading-1-size: var(--chat-fs-22);
100
+ --chat-heading-1-leading: var(--chat-leading-tight);
101
+ --chat-heading-1-weight: var(--chat-weight-semibold);
102
+ --chat-heading-1-tracking: var(--chat-tracking-tighter);
103
+
104
+ --chat-heading-2-size: var(--chat-fs-16);
105
+ --chat-heading-2-leading: var(--chat-leading-tight);
106
+ --chat-heading-2-weight: var(--chat-weight-semibold);
107
+ --chat-heading-2-tracking: var(--chat-tracking-tight);
108
+
109
+ --chat-label-size: var(--chat-fs-11);
110
+ --chat-label-leading: var(--chat-leading-tight);
111
+ --chat-label-weight: var(--chat-weight-medium);
112
+ --chat-label-tracking: var(--chat-tracking-wide);
113
+
114
+ --chat-caption-size: var(--chat-fs-12);
115
+ --chat-caption-leading: var(--chat-leading-snug);
116
+ --chat-caption-weight: var(--chat-weight-regular);
117
+
118
+ --chat-code-size: 0.875em;
119
+ --chat-code-leading: var(--chat-leading-normal);
120
+ --chat-code-weight: var(--chat-weight-regular);
121
+ /* Radius — unified control radius, lg only for composer/bubble/root */
122
+ --chat-radius-xs: 0.25rem;
123
+ --chat-radius-sm: 0.5rem;
124
+ --chat-radius-md: 0.5rem;
125
+ --chat-radius: 0.5rem;
126
+ --chat-radius-lg: 1rem;
127
+ --chat-radius-pill: 999px;
128
+ --chat-radius-full: 999px;
129
+ /* Legacy aliases */
130
+ --chat-radius-card: var(--chat-radius);
131
+ --chat-radius-control: var(--chat-radius);
132
+ --chat-space-05: 0.125rem;
133
+ --chat-space-1: 0.25rem;
134
+ --chat-space-1_5: 0.375rem;
135
+ --chat-space-2: 0.5rem;
136
+ --chat-space-2_5: 0.625rem;
137
+ --chat-space-3: 0.75rem;
138
+ --chat-space-3_5: 0.875rem;
139
+ --chat-space-4: 1rem;
140
+ --chat-space-5: 1.25rem;
141
+ --chat-space-6: 1.5rem;
142
+ --chat-space-8: 2rem;
143
+ --chat-column: 48rem;
144
+ --chat-composer-space: 9.5rem;
145
+ --chat-composer-fade: 0.5rem;
146
+ --chat-transition: 160ms ease;
147
+ }
148
+
149
+ .chat-root[data-theme="dark"] {
150
+ color-scheme: dark;
151
+
152
+ --chat-bg: #212121;
153
+ --chat-bg-elevated: #2f2f2f;
154
+ --chat-fg: #ececec;
155
+ --chat-fg-muted: #b4b4b4;
156
+ --chat-fg-subtle: #8f8f8f;
157
+
158
+ --chat-user-bg: #303030;
159
+ --chat-user-fg: #ececec;
160
+ --chat-assistant-fg: #ececec;
161
+
162
+ --chat-border: rgba(255, 255, 255, 0.08);
163
+ --chat-border-strong: rgba(255, 255, 255, 0.14);
164
+ --chat-ring: rgba(255, 255, 255, 0.22);
165
+ --chat-overlay: rgba(33, 33, 33, 0.92);
166
+ --chat-composer-bg: #2f2f2f;
167
+ --chat-composer-shadow:
168
+ 0 0 0 1px rgba(255, 255, 255, 0.08),
169
+ 0 6px 18px rgba(0, 0, 0, 0.22);
170
+ --chat-control-bg: rgba(255, 255, 255, 0.06);
171
+ --chat-control-hover: rgba(255, 255, 255, 0.1);
172
+ --chat-primary: #ececec;
173
+ --chat-primary-fg: #212121;
174
+ --chat-danger: #f97066;
175
+ --chat-accent: #1a7f64;
176
+ --chat-warning: #fbbf24;
177
+ --chat-success: #34d399;
178
+ }
179
+
180
+ @media (prefers-color-scheme: dark) {
181
+ .chat-root[data-theme="system"] {
182
+ color-scheme: dark;
183
+
184
+ --chat-bg: #212121;
185
+ --chat-bg-elevated: #2f2f2f;
186
+ --chat-fg: #ececec;
187
+ --chat-fg-muted: #b4b4b4;
188
+ --chat-fg-subtle: #8e8ea0;
189
+
190
+ --chat-user-bg: #303030;
191
+ --chat-user-fg: #ececec;
192
+ --chat-assistant-fg: #ececec;
193
+
194
+ --chat-border: rgba(255, 255, 255, 0.08);
195
+ --chat-border-strong: rgba(255, 255, 255, 0.14);
196
+ --chat-ring: rgba(255, 255, 255, 0.22);
197
+ --chat-overlay: rgba(33, 33, 33, 0.92);
198
+ --chat-composer-bg: #2f2f2f;
199
+ --chat-composer-shadow:
200
+ 0 0 0 1px rgba(255, 255, 255, 0.08),
201
+ 0 6px 18px rgba(0, 0, 0, 0.22);
202
+ --chat-control-bg: rgba(255, 255, 255, 0.06);
203
+ --chat-control-hover: rgba(255, 255, 255, 0.1);
204
+ --chat-primary: #ececec;
205
+ --chat-primary-fg: #212121;
206
+ --chat-danger: #f97066;
207
+ --chat-accent: #1a7f64;
208
+ --chat-warning: #fbbf24;
209
+ --chat-success: #34d399;
210
+ }
211
+ }
212
+
213
+ /* Responsive type & layout — mobile / tablet / desktop */
214
+ @media (max-width: 640px) {
215
+ .chat-root,
216
+ .chat-root[data-theme="light"],
217
+ .chat-root[data-theme="dark"],
218
+ .chat-root[data-theme="system"] {
219
+ --chat-body-size: var(--chat-fs-15);
220
+ --chat-body-sm-size: var(--chat-fs-13);
221
+ --chat-heading-1-size: var(--chat-fs-18);
222
+ --chat-heading-2-size: var(--chat-fs-15);
223
+ --chat-caption-size: var(--chat-fs-11);
224
+ --chat-column: 100%;
225
+ --chat-composer-space: 8.5rem;
226
+ }
227
+ }
228
+
229
+ @media (min-width: 641px) and (max-width: 1024px) {
230
+ .chat-root,
231
+ .chat-root[data-theme="light"],
232
+ .chat-root[data-theme="dark"],
233
+ .chat-root[data-theme="system"] {
234
+ --chat-body-size: var(--chat-fs-155);
235
+ --chat-heading-1-size: var(--chat-fs-22);
236
+ --chat-heading-2-size: var(--chat-fs-16);
237
+ --chat-column: 42rem;
238
+ --chat-composer-space: 9rem;
239
+ }
240
+ }
241
+
242
+ @media (min-width: 1025px) {
243
+ .chat-root,
244
+ .chat-root[data-theme="light"],
245
+ .chat-root[data-theme="dark"],
246
+ .chat-root[data-theme="system"] {
247
+ --chat-body-size: var(--chat-fs-155);
248
+ --chat-heading-1-size: var(--chat-fs-22);
249
+ --chat-heading-2-size: var(--chat-fs-16);
250
+ --chat-column: 48rem;
251
+ --chat-composer-space: 9.5rem;
252
+ }
253
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Typography primitives — scoped to .chat-root
3
+ * Professional reading scale: all sizes flow through --chat-* tokens.
4
+ * Use these classes or the CSS vars directly; never hard-code rem/px.
5
+ */
6
+
7
+ .chat-root {
8
+ font-family: var(--chat-font-sans);
9
+ font-size: var(--chat-body-size);
10
+ line-height: var(--chat-body-leading);
11
+ font-weight: var(--chat-body-weight);
12
+ letter-spacing: var(--chat-body-tracking);
13
+ -webkit-font-smoothing: antialiased;
14
+ -moz-osx-font-smoothing: grayscale;
15
+ text-rendering: geometricPrecision;
16
+ font-synthesis: none;
17
+ font-variant-ligatures: none;
18
+ font-feature-settings: "rlig" 1, "calt" 1;
19
+ }
20
+
21
+ /* Headings — display hierarchy via tracking + weight, not color */
22
+ .chat-text-heading-1,
23
+ .chat-text-display {
24
+ font-size: var(--chat-heading-1-size);
25
+ line-height: var(--chat-heading-1-leading);
26
+ font-weight: var(--chat-heading-1-weight);
27
+ letter-spacing: var(--chat-heading-1-tracking);
28
+ }
29
+
30
+ .chat-text-heading-2,
31
+ .chat-text-heading {
32
+ font-size: var(--chat-heading-2-size);
33
+ line-height: var(--chat-heading-2-leading);
34
+ font-weight: var(--chat-heading-2-weight);
35
+ letter-spacing: var(--chat-heading-2-tracking);
36
+ }
37
+
38
+ /* Body — reading column */
39
+ .chat-text-body {
40
+ font-size: var(--chat-body-size);
41
+ line-height: var(--chat-body-leading);
42
+ font-weight: var(--chat-body-weight);
43
+ letter-spacing: var(--chat-body-tracking);
44
+ }
45
+
46
+ .chat-text-body-sm {
47
+ font-size: var(--chat-body-sm-size);
48
+ line-height: var(--chat-body-sm-leading);
49
+ font-weight: var(--chat-body-sm-weight);
50
+ letter-spacing: var(--chat-tracking-normal);
51
+ }
52
+
53
+ /* Label / caption — metadata, tool states, timestamps */
54
+ .chat-text-label {
55
+ font-size: var(--chat-label-size);
56
+ line-height: var(--chat-label-leading);
57
+ font-weight: var(--chat-label-weight);
58
+ letter-spacing: var(--chat-label-tracking);
59
+ text-transform: uppercase;
60
+ }
61
+
62
+ .chat-text-caption {
63
+ font-size: var(--chat-caption-size);
64
+ line-height: var(--chat-caption-leading);
65
+ font-weight: var(--chat-caption-weight);
66
+ letter-spacing: var(--chat-tracking-normal);
67
+ }
68
+
69
+ .chat-text-caption-strong {
70
+ font-size: var(--chat-caption-size);
71
+ line-height: var(--chat-caption-leading);
72
+ font-weight: var(--chat-weight-medium);
73
+ letter-spacing: var(--chat-tracking-normal);
74
+ }
75
+
76
+ /* Code — mono, slightly smaller in context */
77
+ .chat-text-code,
78
+ .chat-text-mono {
79
+ font-family: var(--chat-font-mono);
80
+ font-size: var(--chat-code-size);
81
+ line-height: var(--chat-code-leading);
82
+ font-weight: var(--chat-code-weight);
83
+ font-variant-ligatures: none;
84
+ }
85
+
86
+ /* UI — controls, inputs, selects, buttons (snug leading, 14px) */
87
+ .chat-text-ui {
88
+ font-size: var(--chat-fs-14);
89
+ line-height: var(--chat-leading-ui);
90
+ font-weight: var(--chat-weight-regular);
91
+ letter-spacing: var(--chat-tracking-normal);
92
+ }
93
+
94
+ .chat-text-ui-sm {
95
+ font-size: var(--chat-fs-13);
96
+ line-height: var(--chat-leading-ui);
97
+ font-weight: var(--chat-weight-regular);
98
+ letter-spacing: var(--chat-tracking-normal);
99
+ }
100
+
101
+ .chat-text-ui-strong {
102
+ font-size: var(--chat-fs-14);
103
+ line-height: var(--chat-leading-ui);
104
+ font-weight: var(--chat-weight-medium);
105
+ letter-spacing: var(--chat-tracking-normal);
106
+ }
107
+
108
+ /* Utilities — paired padding for vertical rhythm */
109
+ .chat-pad-body {
110
+ padding-block: 0.15rem;
111
+ }
112
+
113
+ .chat-pad-ui {
114
+ padding-block: 0.3rem;
115
+ }