@kouji-ui/components 0.9.2 → 0.9.3

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 (70) hide show
  1. package/package.json +1 -1
  2. package/src/accordion/accordion.css +68 -0
  3. package/src/action-sheet/action-sheet.css +79 -0
  4. package/src/alert/alert.css +133 -0
  5. package/src/avatar/avatar.css +93 -0
  6. package/src/badge/badge.css +59 -0
  7. package/src/breadcrumb/breadcrumb.css +145 -0
  8. package/src/button/button.css +295 -0
  9. package/src/button-group/button-group.css +114 -0
  10. package/src/calendar/calendar.css +129 -0
  11. package/src/card/card.css +120 -0
  12. package/src/carousel/carousel.css +181 -0
  13. package/src/cascade-select/cascade-select.css +120 -0
  14. package/src/chart/chart.css +26 -0
  15. package/src/chat/chat-ai.css +352 -0
  16. package/src/chat/chat.css +231 -0
  17. package/src/checkbox/checkbox.css +74 -0
  18. package/src/color-picker/color-picker.css +183 -0
  19. package/src/combobox/combobox.css +101 -0
  20. package/src/command-palette/command-palette.css +234 -0
  21. package/src/confirm-popup/confirm-popup.css +47 -0
  22. package/src/date-picker/date-picker.css +61 -0
  23. package/src/date-range-presets/date-range-presets.css +49 -0
  24. package/src/datetime-picker/datetime-picker.css +84 -0
  25. package/src/dialog/dialog.css +56 -0
  26. package/src/direction-toggle/direction-toggle.css +55 -0
  27. package/src/divider/divider.css +93 -0
  28. package/src/drawer/drawer.css +130 -0
  29. package/src/dropdown-menu/dropdown-menu.css +108 -0
  30. package/src/editor/editor.css +140 -0
  31. package/src/empty-state/empty-state.css +114 -0
  32. package/src/field/field.css +148 -0
  33. package/src/file-upload/file-upload.css +207 -0
  34. package/src/form/form.css +63 -0
  35. package/src/input/input.css +70 -0
  36. package/src/input-group/input-group.css +125 -0
  37. package/src/input-mask/input-mask.css +39 -0
  38. package/src/input-otp/input-otp.css +87 -0
  39. package/src/kbd/kbd.css +67 -0
  40. package/src/link/link.css +104 -0
  41. package/src/list/list.css +166 -0
  42. package/src/menubar/menubar.css +62 -0
  43. package/src/number-input/number-input.css +115 -0
  44. package/src/overflow/overflow.css +43 -0
  45. package/src/overlay/overlay.css +45 -0
  46. package/src/overlay-badge/overlay-badge.css +118 -0
  47. package/src/pagination/pagination.css +146 -0
  48. package/src/password-input/password-input.css +155 -0
  49. package/src/popover/popover.css +71 -0
  50. package/src/progress-bar/progress-bar.css +113 -0
  51. package/src/radio/radio.css +58 -0
  52. package/src/rich-text/rich-text-editor.css +351 -0
  53. package/src/select/select.css +91 -0
  54. package/src/sheet/sheet.css +121 -0
  55. package/src/skeleton/skeleton.css +111 -0
  56. package/src/skip-link/skip-link.css +58 -0
  57. package/src/slider/slider.css +172 -0
  58. package/src/speed-dial/speed-dial.css +137 -0
  59. package/src/spinner/spinner.css +161 -0
  60. package/src/stepper/stepper.css +147 -0
  61. package/src/table/table-filters/filters.css +53 -0
  62. package/src/table/table.css +509 -0
  63. package/src/tabs/tabs.css +162 -0
  64. package/src/tag/tag.css +183 -0
  65. package/src/textarea/textarea.css +117 -0
  66. package/src/time-picker/time-picker.css +126 -0
  67. package/src/toast/toast.css +115 -0
  68. package/src/toggle/toggle.css +123 -0
  69. package/src/tooltip/tooltip.css +61 -0
  70. package/src/tree-select/tree-select.css +220 -0
@@ -0,0 +1,181 @@
1
+ @layer kj.component {
2
+ .kj-carousel {
3
+ --kj-carousel-gap: var(--kj-space-md);
4
+ --kj-carousel-radius: var(--kj-radius-box);
5
+ --kj-carousel-control-size: 44px;
6
+ --kj-carousel-control-bg: var(--kj-bg-body);
7
+ --kj-carousel-control-fg: var(--kj-fg-default);
8
+ --kj-carousel-indicator-size: 10px;
9
+ --kj-carousel-indicator-active: var(--kj-bg-primary);
10
+ --kj-carousel-indicator-idle: var(--kj-bg-field);
11
+
12
+ position: relative;
13
+ display: grid;
14
+ grid-template-columns: auto 1fr auto;
15
+ grid-template-rows: 1fr auto;
16
+ gap: var(--kj-carousel-gap);
17
+ align-items: center;
18
+ }
19
+
20
+ .kj-carousel[data-orientation="vertical"] {
21
+ grid-template-columns: 1fr auto;
22
+ grid-template-rows: auto 1fr auto auto;
23
+ }
24
+
25
+ .kj-carousel-viewport {
26
+ grid-column: 2;
27
+ grid-row: 1;
28
+ display: flex;
29
+ flex-direction: row;
30
+ overflow-x: auto;
31
+ overflow-y: hidden;
32
+ scroll-snap-type: x mandatory;
33
+ scrollbar-width: none;
34
+ border-radius: var(--kj-carousel-radius);
35
+ gap: var(--kj-carousel-gap);
36
+ scroll-behavior: smooth;
37
+ }
38
+ .kj-carousel-viewport::-webkit-scrollbar { display: none; }
39
+
40
+ .kj-carousel[data-orientation="vertical"] .kj-carousel-viewport {
41
+ flex-direction: column;
42
+ overflow-x: hidden;
43
+ overflow-y: auto;
44
+ scroll-snap-type: y mandatory;
45
+ grid-column: 1;
46
+ grid-row: 2;
47
+ /* Grid items default to `min-height: auto`, which lets the viewport
48
+ grow past its `1fr` row when slides are taller than the share —
49
+ defeating the scroll-snap container. Pin to 0 so the row's
50
+ fraction actually constrains the viewport height. */
51
+ min-height: 0;
52
+ }
53
+
54
+ .kj-carousel-slide {
55
+ flex: 0 0 calc(100% / var(--kj-carousel-slides-per-view, 1));
56
+ scroll-snap-align: start;
57
+ scroll-snap-stop: always;
58
+ border-radius: var(--kj-carousel-radius);
59
+ background: var(--kj-bg-body);
60
+ color: var(--kj-fg-default);
61
+ padding: var(--kj-space-lg);
62
+ min-height: 0;
63
+ }
64
+
65
+ .kj-carousel-slide[data-align="center"] { scroll-snap-align: center; }
66
+ .kj-carousel-slide[data-align="end"] { scroll-snap-align: end; }
67
+
68
+ .kj-carousel-control {
69
+ grid-row: 1;
70
+ width: var(--kj-carousel-control-size);
71
+ height: var(--kj-carousel-control-size);
72
+ min-width: var(--kj-carousel-control-size);
73
+ min-height: var(--kj-carousel-control-size);
74
+ border-radius: 50%;
75
+ border: var(--kj-border) solid var(--kj-border-default);
76
+ background: var(--kj-carousel-control-bg);
77
+ color: var(--kj-carousel-control-fg);
78
+ cursor: pointer;
79
+ display: inline-flex;
80
+ align-items: center;
81
+ justify-content: center;
82
+ font: 1rem var(--kj-font-sans);
83
+ transition: var(--kj-transition);
84
+ }
85
+ .kj-carousel-control:hover { background: var(--kj-bg-surface); }
86
+ .kj-carousel-control:focus-visible {
87
+ outline: 2px solid var(--kj-border-focus);
88
+ outline-offset: 2px;
89
+ }
90
+ .kj-carousel-control[aria-disabled="true"] {
91
+ opacity: 0.4;
92
+ cursor: not-allowed;
93
+ }
94
+
95
+ .kj-carousel-previous { grid-column: 1; }
96
+ .kj-carousel-next { grid-column: 3; }
97
+
98
+ .kj-carousel[data-orientation="vertical"] .kj-carousel-previous { grid-column: 1; grid-row: 1; }
99
+ .kj-carousel[data-orientation="vertical"] .kj-carousel-next { grid-column: 1; grid-row: 3; }
100
+
101
+ .kj-carousel-indicators {
102
+ grid-column: 2;
103
+ grid-row: 2;
104
+ display: inline-flex;
105
+ gap: var(--kj-space-sm);
106
+ align-items: center;
107
+ justify-content: center;
108
+ padding: var(--kj-space-sm) 0;
109
+ }
110
+ .kj-carousel[data-orientation="vertical"] .kj-carousel-indicators {
111
+ grid-column: 1;
112
+ grid-row: 4;
113
+ flex-direction: row;
114
+ }
115
+
116
+ .kj-carousel-indicator {
117
+ width: var(--kj-carousel-indicator-size);
118
+ height: var(--kj-carousel-indicator-size);
119
+ min-width: 44px;
120
+ min-height: 44px;
121
+ padding: 0;
122
+ border: 0;
123
+ background: transparent;
124
+ cursor: pointer;
125
+ position: relative;
126
+ display: inline-flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ }
130
+ .kj-carousel-indicator::before {
131
+ content: '';
132
+ width: var(--kj-carousel-indicator-size);
133
+ height: var(--kj-carousel-indicator-size);
134
+ border-radius: 50%;
135
+ background: var(--kj-carousel-indicator-idle);
136
+ transition: var(--kj-transition);
137
+ }
138
+ .kj-carousel-indicator[aria-current="true"]::before,
139
+ .kj-carousel-indicator[aria-selected="true"]::before {
140
+ background: var(--kj-carousel-indicator-active);
141
+ transform: scale(1.25);
142
+ }
143
+ .kj-carousel-indicator:focus-visible {
144
+ outline: 2px solid var(--kj-border-focus);
145
+ outline-offset: 2px;
146
+ border-radius: 50%;
147
+ }
148
+
149
+ .kj-carousel-pause {
150
+ grid-column: 3;
151
+ grid-row: 2;
152
+ width: var(--kj-carousel-control-size);
153
+ height: var(--kj-carousel-control-size);
154
+ border-radius: 50%;
155
+ border: var(--kj-border) solid var(--kj-border-default);
156
+ background: var(--kj-carousel-control-bg);
157
+ color: var(--kj-carousel-control-fg);
158
+ cursor: pointer;
159
+ display: inline-flex;
160
+ align-items: center;
161
+ justify-content: center;
162
+ font: 1rem var(--kj-font-sans);
163
+ }
164
+ .kj-carousel-pause:focus-visible {
165
+ outline: 2px solid var(--kj-border-focus);
166
+ outline-offset: 2px;
167
+ }
168
+ .kj-carousel-pause[aria-pressed="true"] {
169
+ background: var(--kj-bg-primary);
170
+ color: var(--kj-fg-on-primary);
171
+ }
172
+ .kj-carousel-pause[disabled] {
173
+ opacity: 0.4;
174
+ cursor: not-allowed;
175
+ }
176
+
177
+ @media (prefers-reduced-motion: reduce) {
178
+ .kj-carousel-viewport { scroll-behavior: auto; }
179
+ .kj-carousel-indicator::before { transition: none; }
180
+ }
181
+ }
@@ -0,0 +1,120 @@
1
+ @layer kj.component {
2
+ /* ── Root ────────────────────────────────────────────────────────────── */
3
+ .kj-cascade-select {
4
+ position: relative;
5
+ display: inline-block;
6
+ min-width: 12rem;
7
+ }
8
+
9
+ /* ── Trigger button ──────────────────────────────────────────────────── */
10
+ .kj-cascade-trigger {
11
+ width: 100%;
12
+ display: inline-flex;
13
+ align-items: center;
14
+ justify-content: space-between;
15
+ gap: var(--kj-space-sm);
16
+ background: var(--kj-bg-field);
17
+ color: var(--kj-fg-default);
18
+ border: 1px solid var(--kj-border-default);
19
+ border-radius: var(--kj-radius-field);
20
+ padding: var(--kj-space-sm) var(--kj-space-md);
21
+ font: 0.875rem var(--kj-font-sans);
22
+ cursor: pointer;
23
+ min-height: 2.75rem; /* 44px touch target */
24
+ }
25
+ .kj-cascade-trigger:focus-visible {
26
+ outline: 2px solid var(--kj-border-focus);
27
+ outline-offset: 2px;
28
+ }
29
+ .kj-cascade-select[data-disabled] .kj-cascade-trigger {
30
+ opacity: 0.45;
31
+ cursor: not-allowed;
32
+ pointer-events: none;
33
+ }
34
+
35
+ /* ── Root panel ──────────────────────────────────────────────────────── */
36
+ .kj-cascade-panel {
37
+ box-sizing: border-box;
38
+ background: var(--kj-bg-elevated);
39
+ border: 1px solid var(--kj-border-default);
40
+ border-radius: var(--kj-radius-field);
41
+ box-shadow: var(--kj-shadow-md);
42
+ padding: 4px;
43
+ min-width: 12rem;
44
+ max-height: 20rem;
45
+ overflow: auto;
46
+ z-index: var(--kj-overlay-z, 200);
47
+ }
48
+ .kj-cascade-panel[hidden] { display: none; }
49
+
50
+ /* ── Sub-panel ───────────────────────────────────────────────────────── */
51
+ /* `position: fixed` so the sub-panel escapes the root panel's
52
+ `overflow: auto`. Coords are written inline by the sub-panel directive
53
+ based on the parent option's bounding rect. */
54
+ .kj-cascade-sub-panel {
55
+ position: fixed;
56
+ background: var(--kj-bg-elevated);
57
+ border: 1px solid var(--kj-border-default);
58
+ border-radius: var(--kj-radius-field);
59
+ box-shadow: var(--kj-shadow-md);
60
+ padding: 4px;
61
+ min-width: 12rem;
62
+ max-height: 20rem;
63
+ overflow: auto;
64
+ z-index: 1001;
65
+ }
66
+ .kj-cascade-sub-panel[hidden] { display: none; }
67
+
68
+ /* ── Option row ──────────────────────────────────────────────────────── */
69
+ .kj-cascade-option {
70
+ display: flex;
71
+ align-items: center;
72
+ justify-content: space-between;
73
+ padding: var(--kj-space-sm) var(--kj-space-md);
74
+ border-radius: var(--kj-radius-selector);
75
+ cursor: pointer;
76
+ color: var(--kj-fg-default);
77
+ font: 0.875rem var(--kj-font-sans);
78
+ min-height: 2.75rem; /* 44px touch target */
79
+ position: relative;
80
+ }
81
+ .kj-cascade-option:hover,
82
+ .kj-cascade-option[data-active] {
83
+ background: var(--kj-bg-surface);
84
+ }
85
+ .kj-cascade-option[aria-selected="true"] {
86
+ background: var(--kj-bg-primary-subtle, var(--kj-bg-surface));
87
+ color: var(--kj-fg-primary, var(--kj-fg-default));
88
+ }
89
+ .kj-cascade-option[data-disabled] {
90
+ opacity: 0.45;
91
+ cursor: not-allowed;
92
+ pointer-events: none;
93
+ }
94
+ .kj-cascade-option[data-active-path] {
95
+ font-weight: 500;
96
+ }
97
+
98
+ /* ── Option label ────────────────────────────────────────────────────── */
99
+ .kj-cascade-option-label {
100
+ flex: 1;
101
+ min-width: 0;
102
+ overflow: hidden;
103
+ text-overflow: ellipsis;
104
+ white-space: nowrap;
105
+ }
106
+
107
+ /* ── Chevron ─────────────────────────────────────────────────────────── */
108
+ .kj-cascade-option-chevron {
109
+ flex-shrink: 0;
110
+ font-size: 1rem;
111
+ color: var(--kj-fg-muted, currentColor);
112
+ opacity: 0.6;
113
+ margin-left: var(--kj-space-sm);
114
+ }
115
+ /* Hide chevron on leaf options (data-leaf="true" is set on the host element) */
116
+ [data-leaf="true"] .kj-cascade-option-chevron,
117
+ [data-leaf="true"].kj-cascade-option .kj-cascade-option-chevron {
118
+ display: none;
119
+ }
120
+ }
@@ -0,0 +1,26 @@
1
+ /* ─────────────────────────────────────────────────────────────
2
+ .kj-chart — component-layer tokens + structural CSS
3
+ ──────────────────────────────────────────────────────────── */
4
+
5
+ @layer kj.component {
6
+ .kj-chart {
7
+ display: block;
8
+ width: 100%;
9
+ /* height is applied via style binding from the `height` input */
10
+ }
11
+
12
+ /* Visually-hidden caption/summary — readable to AT via aria-describedby,
13
+ removed from the visual + layout flow. Mirrors the library `.sr-only`
14
+ technique used by textarea/carousel live regions. */
15
+ .kj-chart__caption {
16
+ position: absolute;
17
+ width: 1px;
18
+ height: 1px;
19
+ padding: 0;
20
+ margin: -1px;
21
+ overflow: hidden;
22
+ clip: rect(0, 0, 0, 0);
23
+ white-space: nowrap;
24
+ border: 0;
25
+ }
26
+ }
@@ -0,0 +1,352 @@
1
+ @layer kj.component {
2
+ /* Visually-hidden utility (scoped; ViewEncapsulation.None). */
3
+ .kj-visually-hidden {
4
+ position: absolute;
5
+ width: 1px;
6
+ height: 1px;
7
+ padding: 0;
8
+ margin: -1px;
9
+ overflow: hidden;
10
+ clip: rect(0, 0, 0, 0);
11
+ white-space: nowrap;
12
+ border: 0;
13
+ }
14
+
15
+ /* ── Thread / log surface ─────────────────────────────────── */
16
+ .kj-chat-thread {
17
+ display: flex;
18
+ flex-direction: column;
19
+ gap: var(--kj-space-md);
20
+ padding: var(--kj-space-md);
21
+ background: var(--kj-bg-body);
22
+ color: var(--kj-fg-default);
23
+ border-radius: var(--kj-radius-box);
24
+ overflow-y: auto;
25
+ font-family: var(--kj-font-sans);
26
+ }
27
+
28
+ /* ── Message row ──────────────────────────────────────────── */
29
+ .kj-chat-msg {
30
+ display: flex;
31
+ gap: var(--kj-space-sm);
32
+ align-items: flex-start;
33
+ max-width: 100%;
34
+ }
35
+ .kj-chat-msg[data-side='end'] {
36
+ flex-direction: row-reverse;
37
+ margin-inline-start: auto;
38
+ }
39
+ .kj-chat-msg[data-role='system'] {
40
+ justify-content: center;
41
+ }
42
+
43
+ .kj-chat-msg__avatar {
44
+ flex: 0 0 auto;
45
+ width: 2rem;
46
+ height: 2rem;
47
+ border-radius: 50%;
48
+ display: grid;
49
+ place-items: center;
50
+ font-size: var(--kj-text-sm);
51
+ font-weight: 600;
52
+ background: var(--kj-bg-surface);
53
+ color: var(--kj-fg-default);
54
+ border: 1px solid var(--kj-border-default);
55
+ }
56
+
57
+ .kj-chat-msg__bubble {
58
+ display: flex;
59
+ flex-direction: column;
60
+ gap: var(--kj-space-xs);
61
+ padding: var(--kj-space-sm) var(--kj-space-md);
62
+ border-radius: var(--kj-radius-box);
63
+ background: var(--kj-bg-surface);
64
+ color: var(--kj-fg-default);
65
+ max-width: min(48rem, 100%);
66
+ overflow-wrap: anywhere;
67
+ }
68
+ .kj-chat-msg[data-role='user'] .kj-chat-msg__bubble {
69
+ background: var(--kj-bg-primary);
70
+ color: var(--kj-fg-on-primary);
71
+ }
72
+ .kj-chat-msg[data-role='system'] .kj-chat-msg__bubble {
73
+ background: transparent;
74
+ color: var(--kj-fg-muted);
75
+ font-size: var(--kj-text-sm);
76
+ text-align: center;
77
+ padding-block: var(--kj-space-xs);
78
+ }
79
+
80
+ .kj-chat-msg__body :is(p) {
81
+ margin: 0 0 var(--kj-space-xs);
82
+ }
83
+ .kj-chat-msg__body :is(p):last-child {
84
+ margin-bottom: 0;
85
+ }
86
+ .kj-chat-msg__error {
87
+ margin: 0;
88
+ color: var(--kj-fg-danger);
89
+ font-size: var(--kj-text-sm);
90
+ }
91
+
92
+ .kj-md-link {
93
+ color: inherit;
94
+ text-decoration: underline;
95
+ }
96
+ .kj-md-code {
97
+ font-family: ui-monospace, monospace;
98
+ background: color-mix(in srgb, currentColor 12%, transparent);
99
+ padding: 0.1em 0.35em;
100
+ border-radius: var(--kj-radius-field);
101
+ font-size: 0.9em;
102
+ }
103
+
104
+ /* ── Code block with copy button ──────────────────────────── */
105
+ .kj-chat-code {
106
+ border: 1px solid var(--kj-border-default);
107
+ border-radius: var(--kj-radius-field);
108
+ overflow: hidden;
109
+ margin: var(--kj-space-xs) 0;
110
+ background: var(--kj-bg-body);
111
+ }
112
+ .kj-chat-code__bar {
113
+ display: flex;
114
+ align-items: center;
115
+ justify-content: space-between;
116
+ padding: 0.25rem var(--kj-space-sm);
117
+ background: var(--kj-bg-surface);
118
+ border-bottom: 1px solid var(--kj-border-default);
119
+ font-size: var(--kj-text-sm);
120
+ color: var(--kj-fg-muted);
121
+ }
122
+ .kj-chat-code__copy {
123
+ min-height: 1.75rem;
124
+ padding: 0.25rem 0.6rem;
125
+ border: 1px solid var(--kj-border-default);
126
+ border-radius: var(--kj-radius-field);
127
+ background: var(--kj-bg-body);
128
+ color: var(--kj-fg-default);
129
+ font-size: var(--kj-text-sm);
130
+ cursor: pointer;
131
+ }
132
+ .kj-chat-code__copy:hover {
133
+ background: var(--kj-bg-surface);
134
+ }
135
+ .kj-chat-code__copy:focus-visible {
136
+ outline: 2px solid var(--kj-border-focus);
137
+ outline-offset: 2px;
138
+ }
139
+ .kj-chat-code__pre {
140
+ margin: 0;
141
+ padding: var(--kj-space-sm);
142
+ overflow-x: auto;
143
+ font-family: ui-monospace, monospace;
144
+ font-size: 0.9em;
145
+ color: var(--kj-fg-default);
146
+ }
147
+
148
+ /* ── Tool-call card ───────────────────────────────────────── */
149
+ .kj-chat-tool {
150
+ display: flex;
151
+ align-items: center;
152
+ gap: var(--kj-space-xs);
153
+ padding: 0.35rem var(--kj-space-sm);
154
+ border: 1px solid var(--kj-border-default);
155
+ border-radius: var(--kj-radius-field);
156
+ background: var(--kj-bg-body);
157
+ font-size: var(--kj-text-sm);
158
+ }
159
+ .kj-chat-tool__name {
160
+ font-weight: 600;
161
+ font-family: ui-monospace, monospace;
162
+ }
163
+ .kj-chat-tool__status {
164
+ margin-inline-start: auto;
165
+ color: var(--kj-fg-muted);
166
+ text-transform: capitalize;
167
+ }
168
+ .kj-chat-tool[data-status='error'] {
169
+ border-color: var(--kj-border-danger);
170
+ }
171
+ .kj-chat-tool[data-status='error'] .kj-chat-tool__status {
172
+ color: var(--kj-fg-danger);
173
+ }
174
+ .kj-chat-tool__error {
175
+ color: var(--kj-fg-danger);
176
+ }
177
+
178
+ /* ── Citations ────────────────────────────────────────────── */
179
+ .kj-chat-cites {
180
+ list-style: none;
181
+ margin: var(--kj-space-xs) 0 0;
182
+ padding: 0;
183
+ display: flex;
184
+ flex-wrap: wrap;
185
+ gap: var(--kj-space-xs);
186
+ }
187
+ .kj-chat-cite {
188
+ display: inline-flex;
189
+ align-items: baseline;
190
+ gap: 0.35rem;
191
+ padding: 0.15rem 0.5rem;
192
+ border: 1px solid var(--kj-border-default);
193
+ border-radius: 999px;
194
+ font-size: var(--kj-text-sm);
195
+ background: var(--kj-bg-body);
196
+ }
197
+ .kj-chat-cite__link {
198
+ color: var(--kj-fg-info);
199
+ text-decoration: none;
200
+ }
201
+ .kj-chat-cite__link:hover {
202
+ text-decoration: underline;
203
+ }
204
+ .kj-chat-cite__snippet {
205
+ color: var(--kj-fg-muted);
206
+ }
207
+
208
+ /* ── Typing indicator (reduced-motion aware) ──────────────── */
209
+ .kj-chat-typing {
210
+ display: inline-flex;
211
+ gap: 0.25rem;
212
+ align-items: center;
213
+ padding: 0.25rem 0;
214
+ }
215
+ .kj-chat-typing__dot {
216
+ width: 0.5rem;
217
+ height: 0.5rem;
218
+ border-radius: 50%;
219
+ background: var(--kj-fg-muted);
220
+ animation: kj-chat-bounce 1.2s infinite ease-in-out both;
221
+ }
222
+ .kj-chat-typing__dot:nth-child(2) {
223
+ animation-delay: 0.15s;
224
+ }
225
+ .kj-chat-typing__dot:nth-child(3) {
226
+ animation-delay: 0.3s;
227
+ }
228
+ @keyframes kj-chat-bounce {
229
+ 0%,
230
+ 80%,
231
+ 100% {
232
+ transform: scale(0.5);
233
+ opacity: 0.4;
234
+ }
235
+ 40% {
236
+ transform: scale(1);
237
+ opacity: 1;
238
+ }
239
+ }
240
+ @media (prefers-reduced-motion: reduce) {
241
+ .kj-chat-typing__dot {
242
+ animation: none;
243
+ opacity: 0.6;
244
+ }
245
+ }
246
+
247
+ /* ── Prompt input ─────────────────────────────────────────── */
248
+ .kj-prompt {
249
+ position: relative;
250
+ display: flex;
251
+ align-items: flex-end;
252
+ gap: var(--kj-space-sm);
253
+ padding: var(--kj-space-sm);
254
+ border: 1px solid var(--kj-border-default);
255
+ border-radius: var(--kj-radius-box);
256
+ background: var(--kj-bg-field, var(--kj-input-bg));
257
+ }
258
+ .kj-prompt:focus-within {
259
+ border-color: var(--kj-border-focus);
260
+ }
261
+ .kj-prompt__textarea {
262
+ flex: 1 1 auto;
263
+ resize: none;
264
+ border: none;
265
+ outline: none;
266
+ background: transparent;
267
+ color: var(--kj-input-fg, var(--kj-fg-default));
268
+ font-family: var(--kj-font-sans);
269
+ font-size: var(--kj-input-font-size, 1rem);
270
+ line-height: 1.5;
271
+ max-height: 200px;
272
+ overflow-y: auto;
273
+ }
274
+ .kj-prompt__textarea::placeholder {
275
+ color: var(--kj-input-placeholder-fg, var(--kj-fg-muted));
276
+ }
277
+ .kj-prompt__actions {
278
+ display: flex;
279
+ align-items: center;
280
+ gap: var(--kj-space-xs);
281
+ flex: 0 0 auto;
282
+ }
283
+ .kj-prompt__btn {
284
+ display: grid;
285
+ place-items: center;
286
+ width: 2.75rem;
287
+ height: 2.75rem; /* WCAG 2.5.5 target */
288
+ border-radius: 50%;
289
+ border: none;
290
+ cursor: pointer;
291
+ font-size: 1.1rem;
292
+ }
293
+ .kj-prompt__btn:focus-visible {
294
+ outline: 2px solid var(--kj-border-focus);
295
+ outline-offset: 2px;
296
+ }
297
+ .kj-prompt__btn--send {
298
+ background: var(--kj-bg-primary);
299
+ color: var(--kj-fg-on-primary);
300
+ }
301
+ .kj-prompt__btn--send:disabled {
302
+ opacity: 0.5;
303
+ cursor: not-allowed;
304
+ }
305
+ .kj-prompt__btn--stop {
306
+ background: var(--kj-bg-danger);
307
+ color: var(--kj-fg-on-danger);
308
+ }
309
+
310
+ /* ── Slash-command menu ───────────────────────────────────── */
311
+ .kj-prompt__slash {
312
+ position: absolute;
313
+ bottom: calc(100% + 0.25rem);
314
+ left: 0;
315
+ right: 0;
316
+ margin: 0;
317
+ padding: 0.25rem;
318
+ list-style: none;
319
+ background: var(--kj-bg-surface);
320
+ border: 1px solid var(--kj-border-default);
321
+ border-radius: var(--kj-radius-field);
322
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
323
+ max-height: 14rem;
324
+ overflow-y: auto;
325
+ z-index: 10;
326
+ }
327
+ .kj-prompt__slash-item {
328
+ display: flex;
329
+ flex-direction: column;
330
+ gap: 0.1rem;
331
+ padding: var(--kj-space-xs) var(--kj-space-sm);
332
+ border-radius: var(--kj-radius-field);
333
+ cursor: pointer;
334
+ }
335
+ .kj-prompt__slash-item.is-active,
336
+ .kj-prompt__slash-item:hover {
337
+ background: var(--kj-bg-primary);
338
+ color: var(--kj-fg-on-primary);
339
+ }
340
+ .kj-prompt__slash-name {
341
+ font-family: ui-monospace, monospace;
342
+ font-weight: 600;
343
+ }
344
+ .kj-prompt__slash-desc {
345
+ font-size: var(--kj-text-sm);
346
+ color: var(--kj-fg-muted);
347
+ }
348
+ .kj-prompt__slash-item.is-active .kj-prompt__slash-desc,
349
+ .kj-prompt__slash-item:hover .kj-prompt__slash-desc {
350
+ color: inherit;
351
+ }
352
+ }