@cwim/kanban 1.0.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.
package/README.md ADDED
@@ -0,0 +1,232 @@
1
+ # CWIM Kanban
2
+
3
+ > Minimal Kanban task tracking with MCP integration for Claude Code. Local-first, zero-config, and purpose-built for long-running AI-assisted workflows.
4
+
5
+ ## Overview
6
+
7
+ CWIM Kanban is a complementary package to CWIM (Context Window Intelligence Manager) that adds visual task tracking to your Claude Code sessions. It consists of:
8
+
9
+ - **MCP Server** — Exposes Kanban operations as Claude Code tools (`task_create`, `task_move`, `task_list`, etc.)
10
+ - **Web Dashboard** — A clean, dark-themed Kanban board served locally at `http://localhost:3456`
11
+ - **CLI** — Full command-line interface for managing tasks outside of Claude
12
+ - **Local JSON Storage** — All data stored in `~/.kanban/tasks.json`, no cloud or database needed
13
+
14
+ As Claude works through complex multi-step tasks, it can create cards, move them across columns, and you watch progress unfold in real time on the board.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ # Install globally
20
+ npm install -g @cwim/kanban
21
+
22
+ # Or run directly with npx
23
+ npx @cwim/kanban
24
+
25
+ # Short command (after global install)
26
+ kanban
27
+ ```
28
+
29
+ ## Claude Code Integration (MCP)
30
+
31
+ Add CWIM Kanban to your Claude Code MCP configuration:
32
+
33
+ ```bash
34
+ # Add to your Claude Code config (e.g., ~/.claude/config.json)
35
+ {
36
+ "mcpServers": {
37
+ "kanban": {
38
+ "command": "npx",
39
+ "args": ["@cwim/kanban", "mcp"]
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ Once connected, Claude can use these tools during your sessions:
46
+
47
+ | Tool | Purpose |
48
+ |------|---------|
49
+ | `task_create` | Create a new task card |
50
+ | `task_update` | Edit task title, description, tags |
51
+ | `task_move` | Move a task to another column |
52
+ | `task_delete` | Remove a task |
53
+ | `task_list` | List all tasks (optionally filtered) |
54
+ | `task_get` | Show details of a specific task |
55
+
56
+ Claude will automatically detect the tools and use them to track progress on complex tasks. Tasks created via MCP are tagged with source "claude" so you can distinguish them from manually created ones.
57
+
58
+ ## CLI Commands
59
+
60
+ ### `kanban` (default) — Launch Dashboard
61
+
62
+ ```bash
63
+ # Start dashboard server and open browser
64
+ kanban
65
+
66
+ # Custom port
67
+ kanban --port 8080
68
+
69
+ # Don't auto-open browser
70
+ kanban --no-open
71
+ ```
72
+
73
+ ### `kanban mcp` — Start MCP Server
74
+
75
+ ```bash
76
+ # Run in MCP mode (stdio transport for Claude Code)
77
+ kanban mcp
78
+ ```
79
+
80
+ ### `kanban add` — Create Task
81
+
82
+ ```bash
83
+ # Simple task
84
+ kanban add "Fix auth middleware"
85
+
86
+ # With description and tags
87
+ kanban add "Refactor database layer" -d "Extract connection pooling" -t refactor,db
88
+
89
+ # Direct to a column
90
+ kanban add "Write tests" -s in-progress
91
+ ```
92
+
93
+ ### `kanban list` — List Tasks
94
+
95
+ ```bash
96
+ # All tasks
97
+ kanban list
98
+
99
+ # Filter by status
100
+ kanban list --status done
101
+
102
+ # Filter by tag
103
+ kanban list --tag refactor
104
+ ```
105
+
106
+ ### `kanban done` — Mark Complete
107
+
108
+ ```bash
109
+ kanban done tf-abc123
110
+ ```
111
+
112
+ ### `kanban move` — Change Status
113
+
114
+ ```bash
115
+ # Move to any column
116
+ kanban move tf-abc123 blocked
117
+ kanban move tf-abc123 in-progress
118
+ ```
119
+
120
+ ### `kanban status` — Board Overview
121
+
122
+ ```bash
123
+ # Quick summary of all columns
124
+ kanban status
125
+ ```
126
+
127
+ ### `kanban show` — Task Details
128
+
129
+ ```bash
130
+ kanban show tf-abc123
131
+ ```
132
+
133
+ ### `kanban remove` — Delete Task
134
+
135
+ ```bash
136
+ kanban remove tf-abc123
137
+ ```
138
+
139
+ ### `kanban init` — Initialize Storage
140
+
141
+ ```bash
142
+ # Creates ~/.kanban/ directory and empty tasks.json
143
+ kanban init
144
+ ```
145
+
146
+ ## Dashboard Features
147
+
148
+ - **Real-time updates** — Board refreshes every 2 seconds, showing changes as Claude moves tasks
149
+ - **4 columns** — To Do, In Progress, Done, Blocked
150
+ - **Visual indicators** — Color-coded borders, pulsing LIVE badge, flash animation on task moves
151
+ - **Session linking** — Auto-detects active Claude Code session and shows it in the header
152
+ - **Tag support** — Tasks show tags as badges for quick categorization
153
+ - **Source tracking** — Distinguishes between Claude-created and manually-created tasks
154
+ - **Keyboard shortcuts** — `r` to refresh, `1-4` to filter columns
155
+ - **New task toast** — Brief notification when a new task appears
156
+
157
+ ## Data Storage
158
+
159
+ All data is stored locally in `~/.kanban/tasks.json`:
160
+
161
+ ```json
162
+ {
163
+ "version": 1,
164
+ "updatedAt": "2026-05-23T10:30:00Z",
165
+ "session": {
166
+ "name": "my-project",
167
+ "path": "/home/user/.claude/projects/my-project"
168
+ },
169
+ "tasks": [
170
+ {
171
+ "id": "tf-001",
172
+ "title": "Refactor auth middleware",
173
+ "description": "Extract JWT validation into separate module",
174
+ "status": "in-progress",
175
+ "tags": ["refactor", "auth"],
176
+ "source": "claude",
177
+ "createdAt": "2026-05-23T10:15:00Z",
178
+ "updatedAt": "2026-05-23T10:20:00Z"
179
+ }
180
+ ]
181
+ }
182
+ ```
183
+
184
+ - **Local-first** — No cloud services, no accounts, no network required
185
+ - **Human-readable** — JSON format you can edit directly if needed
186
+ - **Session-aware** — Links tasks to Claude Code sessions when available
187
+ - **Portable** — Back up or version-control your `~/.kanban/` directory
188
+
189
+ ## Programmatic API
190
+
191
+ Core functions are exported for custom integrations:
192
+
193
+ ```typescript
194
+ import { createTask, listTasks, moveTask, getAllData } from '@cwim/kanban';
195
+
196
+ // Create a task programmatically
197
+ const task = await createTask({
198
+ title: 'My task',
199
+ description: 'Optional details',
200
+ status: 'todo',
201
+ tags: ['api'],
202
+ source: 'manual'
203
+ });
204
+
205
+ // Get all data
206
+ const data = await getAllData();
207
+ console.log(data.tasks);
208
+ ```
209
+
210
+ See `src/index.ts` for all available exports.
211
+
212
+ ## Architecture
213
+
214
+ ```
215
+ Claude Code → MCP Server (stdio) → tasks.json ← HTTP Server ← Dashboard UI
216
+ ↑ ↑
217
+ task_create, move, etc. polling /api/tasks
218
+ ```
219
+
220
+ - **MCP Server** and **HTTP Server** are separate processes
221
+ - They communicate through the shared JSON file, not sockets or IPC
222
+ - The dashboard polls `/api/tasks` every 2 seconds
223
+ - All mutations go through the MCP tools or CLI commands
224
+
225
+ ## Requirements
226
+
227
+ - Node.js 18+
228
+ - Claude Code (optional — dashboard works independently)
229
+
230
+ ## License
231
+
232
+ MIT
@@ -0,0 +1 @@
1
+ *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}*{--tw-border-opacity: 1;border-color:rgb(42 42 58 / var(--tw-border-opacity, 1))}body{--tw-bg-opacity: 1;background-color:rgb(10 10 15 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(232 232 240 / var(--tw-text-opacity, 1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:Inter,ui-sans-serif,system-ui,-apple-system,sans-serif}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:#2a2a3a;border-radius:3px}::-webkit-scrollbar-thumb:hover{background:#3d3d5c}.\!visible{visibility:visible!important}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.bottom-3{bottom:.75rem}.bottom-6{bottom:1.5rem}.left-1\/2{left:50%}.right-4{right:1rem}.z-50{z-index:50}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.ml-auto{margin-left:auto}.mt-4{margin-top:1rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.h-11{height:2.75rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-5{height:1.25rem}.h-full{height:100%}.h-screen{height:100vh}.min-h-0{min-height:0px}.w-2{width:.5rem}.w-5{width:1.25rem}.w-full{width:100%}.min-w-\[300px\]{min-width:300px}.min-w-max{min-width:-moz-max-content;min-width:max-content}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-default{cursor:default}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:.25rem}.rounded-\[10px\]{border-radius:10px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-xl{border-radius:calc(var(--radius) + 4px)}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-l-\[3px\]{border-left-width:3px}.border-\[\#2A2A3A\]{--tw-border-opacity: 1;border-color:rgb(42 42 58 / var(--tw-border-opacity, 1))}.border-\[\#2A2A3A\]\/50{border-color:#2a2a3a80}.border-\[\#3D3D5C\]{--tw-border-opacity: 1;border-color:rgb(61 61 92 / var(--tw-border-opacity, 1))}.bg-\[\#0A0A0F\]{--tw-bg-opacity: 1;background-color:rgb(10 10 15 / var(--tw-bg-opacity, 1))}.bg-\[\#10B981\]{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-\[\#111118\]{--tw-bg-opacity: 1;background-color:rgb(17 17 24 / var(--tw-bg-opacity, 1))}.bg-\[\#1E1E2A\]{--tw-bg-opacity: 1;background-color:rgb(30 30 42 / var(--tw-bg-opacity, 1))}.bg-\[\#27273A\]{--tw-bg-opacity: 1;background-color:rgb(39 39 58 / var(--tw-bg-opacity, 1))}.p-3{padding:.75rem}.p-4{padding:1rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.text-center{text-align:center}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.tracking-\[0\.05em\]{letter-spacing:.05em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-\[\#22D3EE\]{--tw-text-opacity: 1;color:rgb(34 211 238 / var(--tw-text-opacity, 1))}.text-\[\#555570\]{--tw-text-opacity: 1;color:rgb(85 85 112 / var(--tw-text-opacity, 1))}.text-\[\#8A8AA3\]{--tw-text-opacity: 1;color:rgb(138 138 163 / var(--tw-text-opacity, 1))}.text-\[\#E8E8F0\]{--tw-text-opacity: 1;color:rgb(232 232 240 / var(--tw-text-opacity, 1))}.text-\[\#EF4444\]{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.opacity-20{opacity:.2}.shadow-\[0_1px_3px_rgba\(0\,0\,0\,0\.3\)\,0_0_0_1px_rgba\(255\,255\,255\,0\.03\)\]{--tw-shadow: 0 1px 3px rgba(0,0,0,.3),0 0 0 1px rgba(255,255,255,.03);--tw-shadow-colored: 0 1px 3px var(--tw-shadow-color), 0 0 0 1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[inset_0_1px_0_rgba\(255\,255\,255\,0\.04\)\]{--tw-shadow: inset 0 1px 0 rgba(255,255,255,.04);--tw-shadow-colored: inset 0 1px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.duration-200{animation-duration:.2s}.ease-out{animation-timing-function:cubic-bezier(0,0,.2,1)}@keyframes cardEnter{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.animate-card-enter{animation:cardEnter .3s cubic-bezier(.16,1,.3,1) forwards}@keyframes columnFlash{0%{border-left-width:3px;box-shadow:none}30%{border-left-width:6px}to{border-left-width:3px;box-shadow:none}}.animate-column-flash-todo{animation:columnFlash .6s ease-out;border-left-color:#f59e0b;box-shadow:0 0 8px #f59e0b66}.animate-column-flash-inprogress{animation:columnFlash .6s ease-out;border-left-color:#3b82f6;box-shadow:0 0 8px #3b82f666}.animate-column-flash-done{animation:columnFlash .6s ease-out;border-left-color:#10b981;box-shadow:0 0 8px #10b98166}.animate-column-flash-blocked{animation:columnFlash .6s ease-out;border-left-color:#ef4444;box-shadow:0 0 8px #ef444466}@keyframes toastIn{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes toastOut{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(20px)}}.animate-toast-in{animation:toastIn .3s cubic-bezier(.16,1,.3,1) forwards}@keyframes pulseRing{0%{transform:scale(1);opacity:.6}to{transform:scale(2.5);opacity:0}}.animate-pulse-ring{animation:pulseRing 2s ease-out infinite}@keyframes emptyFade{0%{opacity:0}to{opacity:1}}.animate-empty-fade{animation:emptyFade .2s ease forwards}.hover\:bg-\[\#1A1A24\]:hover{--tw-bg-opacity: 1;background-color:rgb(26 26 36 / var(--tw-bg-opacity, 1))}.hover\:bg-\[\#27273A\]:hover{--tw-bg-opacity: 1;background-color:rgb(39 39 58 / var(--tw-bg-opacity, 1))}.hover\:shadow-\[0_4px_12px_rgba\(0\,0\,0\,0\.4\)\,0_0_0_1px_rgba\(255\,255\,255\,0\.05\)\]:hover{--tw-shadow: 0 4px 12px rgba(0,0,0,.4),0 0 0 1px rgba(255,255,255,.05);--tw-shadow-colored: 0 4px 12px var(--tw-shadow-color), 0 0 0 1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}