@fapost/jig-ui 0.2.0 → 0.3.0-next.38

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.
@@ -23,7 +23,19 @@ export function placeOf(task) {
23
23
  const id = columnOf(task);
24
24
  return { id, title: COLUMNS.find((c) => c.id === id)?.title ?? id };
25
25
  }
26
- /** The board: every column, in a fixed order, its cards in the order Jig listed them. Computed on every read, never stored. */
26
+ /** Jig's queue order: the top level first, then each open epic's by its name, by position there; a task not queued after them all. */
27
+ function byQueue(a, b) {
28
+ if (!a.queue || !b.queue)
29
+ return a.queue ? -1 : b.queue ? 1 : 0;
30
+ const [x, y] = [a.queue.level, b.queue.level];
31
+ if (x !== y)
32
+ return x === null ? -1 : y === null ? 1 : x < y ? -1 : 1;
33
+ return a.queue.position - b.queue.position;
34
+ }
35
+ /**
36
+ * The board: every column, in a fixed order, its cards in Jig's queue order and the tasks not queued after them in the
37
+ * order Jig listed them (the sort is stable). Computed on every read, never stored.
38
+ */
27
39
  export function columns(tasks) {
28
- return COLUMNS.map((c) => ({ ...c, cards: tasks.filter((t) => columnOf(t) === c.id) }));
40
+ return COLUMNS.map((c) => ({ ...c, cards: tasks.filter((t) => columnOf(t) === c.id).sort(byQueue) }));
29
41
  }
package/dist/http/app.js CHANGED
@@ -32,6 +32,41 @@ function absolute(path) {
32
32
  const expanded = path.trim().replace(/^~(?=$|[\\/])/, homedir());
33
33
  return isAbsolute(expanded) ? expanded : undefined;
34
34
  }
35
+ const isId = (v) => typeof v === 'string' && v !== '';
36
+ const isRevision = (v) => Number.isSafeInteger(v) && v >= 0;
37
+ const field = (body, key) => typeof body === 'object' && body !== null ? body[key] : undefined;
38
+ /** Where a drop puts a task: after another, or to the top or bottom of its level; `undefined` for anything else. */
39
+ function place(v) {
40
+ if (v === 'top' || v === 'bottom')
41
+ return v;
42
+ const after = field(v, 'after');
43
+ return isId(after) ? { after } : undefined;
44
+ }
45
+ /** A priority as the page sends it: 0 to 5, or `null` for none. */
46
+ const isPriority = (v) => v === null || (Number.isInteger(v) && v >= 0 && v <= 5);
47
+ /** A new task's id as Jig takes one (`jig_valid_id`): never empty, never led by `.` or `-`, so never a flag. */
48
+ const isNewId = (v) => typeof v === 'string' && /^[A-Za-z0-9_][A-Za-z0-9._-]*$/.test(v);
49
+ /** A goal as `jig task new --goal` takes one: a line of text, at most 500 characters; Jig refuses the rest as `usage`. */
50
+ const isGoal = (v) => typeof v === 'string' && v.trim() !== '' && v.length <= 500 && !/[\r\n]/.test(v);
51
+ /** The body of a write that names only a task: the task and the revision it was read at, `undefined` where invalid. */
52
+ function taskAt(body) {
53
+ const [task, revision] = [field(body, 'task'), field(body, 'revision')];
54
+ return { task: isId(task) ? task : undefined, revision: isRevision(revision) ? revision : undefined };
55
+ }
56
+ /** What a write came to, in the API's form. A refusal names no path: only Jig's code goes on. */
57
+ function written(c, w) {
58
+ if (w === undefined)
59
+ return refuse(c, 404, 'not-connected', 'No connected project has this id.');
60
+ if (w.state === 'written')
61
+ return c.json({ written: true }, 200);
62
+ if (w.state !== 'refused')
63
+ return c.json({ project: w }, 200);
64
+ if (w.code === 'stale-revision')
65
+ return refuse(c, 409, w.code, 'The project changed since the board was read.');
66
+ if (w.code === 'not-found')
67
+ return refuse(c, 404, w.code, 'This project has no live task with this id.');
68
+ return refuse(c, 422, w.code, 'Jig refused the change.');
69
+ }
35
70
  /**
36
71
  * The API, chained so that its type carries every route's answers: the page derives its types
37
72
  * from `AppType` and never declares them a second time.
@@ -47,7 +82,8 @@ function apiRoutes(source, version) {
47
82
  return refuse(c, 404, 'not-connected', 'No connected project has this id.');
48
83
  if (read.state !== 'ready')
49
84
  return c.json({ board: read }, 200);
50
- return c.json({ board: { id, state: read.state, columns: columns(read.tasks), finished: read.finished } }, 200);
85
+ const { state, finished, revision } = read;
86
+ return c.json({ board: { id, state, columns: columns(read.tasks), finished, revision } }, 200);
51
87
  })
52
88
  .get('/api/projects/:id/tasks/:task', async (c) => {
53
89
  const read = await source.task(c.req.param('id'), c.req.param('task'));
@@ -64,6 +100,64 @@ function apiRoutes(source, version) {
64
100
  if (read === undefined)
65
101
  return refuse(c, 404, 'not-connected', 'No connected project has this id.');
66
102
  return c.json({ specs: read }, 200);
103
+ })
104
+ // A write carries the revision of the board it was based on; Jig refuses it if anything was written since.
105
+ .post('/api/projects/:id/queue/move', validator('json', (body) => {
106
+ const [task, revision] = [field(body, 'task'), field(body, 'revision')];
107
+ return {
108
+ task: isId(task) ? task : undefined,
109
+ place: place(field(body, 'place')),
110
+ revision: isRevision(revision) ? revision : undefined,
111
+ };
112
+ }), async (c) => {
113
+ const { task, place, revision } = c.req.valid('json');
114
+ if (task === undefined || place === undefined || revision === undefined) {
115
+ return refuse(c, 422, 'usage', 'Give a task, where it goes and the revision it was read at.');
116
+ }
117
+ return written(c, await source.move(c.req.param('id'), task, place, revision));
118
+ })
119
+ .post('/api/projects/:id/queue/priority', validator('json', (body) => {
120
+ const [task, priority, revision] = [field(body, 'task'), field(body, 'priority'), field(body, 'revision')];
121
+ return {
122
+ task: isId(task) ? task : undefined,
123
+ // `undefined` for anything but 0 to 5 or null: a priority left out is no priority of none
124
+ priority: isPriority(priority) ? priority : undefined,
125
+ revision: isRevision(revision) ? revision : undefined,
126
+ };
127
+ }), async (c) => {
128
+ const { task, priority, revision } = c.req.valid('json');
129
+ if (task === undefined || priority === undefined || revision === undefined) {
130
+ return refuse(c, 422, 'usage', 'Give a task, a priority from 0 to 5 or null, and the revision it was read at.');
131
+ }
132
+ return written(c, await source.prioritise(c.req.param('id'), task, priority, revision));
133
+ })
134
+ // A pause is asked of the task, not made: Jig honours it at the task's next stage boundary.
135
+ .post('/api/projects/:id/queue/pause', validator('json', taskAt), async (c) => {
136
+ const { task, revision } = c.req.valid('json');
137
+ if (task === undefined || revision === undefined)
138
+ return refuse(c, 422, 'usage', 'Give a task and the revision it was read at.');
139
+ return written(c, await source.requestPause(c.req.param('id'), task, revision));
140
+ })
141
+ .post('/api/projects/:id/queue/pause/cancel', validator('json', taskAt), async (c) => {
142
+ const { task, revision } = c.req.valid('json');
143
+ if (task === undefined || revision === undefined)
144
+ return refuse(c, 422, 'usage', 'Give a task and the revision it was read at.');
145
+ return written(c, await source.cancelPause(c.req.param('id'), task, revision));
146
+ })
147
+ // A new task carries no revision: it writes nothing that exists (adr-20261022-filing-a-task-carries-no-revision).
148
+ .post('/api/projects/:id/tasks', validator('json', (body) => {
149
+ const [task, goal] = [field(body, 'task'), field(body, 'goal')];
150
+ return { task: isNewId(task) ? task : undefined, goal: isGoal(goal) ? goal : undefined };
151
+ }), async (c) => {
152
+ const { task, goal } = c.req.valid('json');
153
+ if (task === undefined || goal === undefined) {
154
+ return refuse(c, 422, 'usage', 'Give an id of letters, digits, ".", "_" or "-", not led by "." or "-", and a goal of one line.');
155
+ }
156
+ const w = await source.fileTask(c.req.param('id'), task, goal);
157
+ if (w?.state === 'refused' && w.code === 'already-exists') {
158
+ return refuse(c, 409, w.code, 'The project has a task with this id, maybe a finished one.');
159
+ }
160
+ return written(c, w);
67
161
  })
68
162
  .post('/api/projects', validator('json', (body) => ({
69
163
  path: absolute(body?.path),
@@ -4,9 +4,9 @@ import { join, resolve } from 'node:path';
4
4
  import { promisify } from 'node:util';
5
5
  import { z } from 'zod';
6
6
  const run = promisify(execFile);
7
- /** The oldest Jig whose reads Jig UI understands: 0.29.0 is the first that prints JSON. */
8
- export const MIN_JIG_VERSION = '0.29.0';
9
- const SCRIPT = join('.ai', 'scripts', 'jig');
7
+ /** The oldest Jig Jig UI reads and writes: 0.29.0 is the first that prints JSON, 0.31.0 the first with a queue. */
8
+ export const MIN_JIG_VERSION = '0.31.0';
9
+ const SCRIPT = '.ai/scripts/jig';
10
10
  const TIMEOUT_MS = 10_000;
11
11
  /** The directory whose changes may change what Jig reports: the main checkout's `.ai/`. */
12
12
  export const watchDir = (root) => join(root, '.ai');
@@ -33,9 +33,23 @@ async function bash(platform) {
33
33
  });
34
34
  return gitBash;
35
35
  }
36
- /** Runs the project's own Jig in its main checkout, without a shell. */
36
+ /**
37
+ * Runs the project's own Jig in its main checkout, without a shell. Git bash on Windows parses its own command line:
38
+ * it globs an argument Node left unquoted (a one-word goal `out*` became `out.json`), and with `MSYS=noglob` it reads
39
+ * `\"` as a backslash and a quote instead (CI, task `file-backlog-task`). There the arguments go in the environment,
40
+ * and a fixed script hands them to Jig, so nothing parses a person's text. The script sources Jig (which finds itself
41
+ * by `BASH_SOURCE`) rather than `exec` it: Git bash's `exec` starts a second bash and waits for it, and every run took
42
+ * half as long again (CI, task `conflict-display`).
43
+ */
37
44
  async function jig(root, args, platform) {
38
- const { stdout } = await run(await bash(platform), [SCRIPT, ...args], { cwd: root, timeout: TIMEOUT_MS });
45
+ const argv = [SCRIPT, ...args];
46
+ const { stdout } = platform === 'win32'
47
+ ? await run(await bash(platform), ['-c', `. ${argv.map((_, i) => `"$JIG_UI_ARG_${i}"`).join(' ')}`], {
48
+ cwd: root,
49
+ timeout: TIMEOUT_MS,
50
+ env: { ...process.env, ...Object.fromEntries(argv.map((arg, i) => [`JIG_UI_ARG_${i}`, arg])) },
51
+ })
52
+ : await run(await bash(platform), argv, { cwd: root, timeout: TIMEOUT_MS });
39
53
  return stdout;
40
54
  }
41
55
  /**
@@ -58,7 +72,7 @@ export class JigRefusal extends Error {
58
72
  this.code = code;
59
73
  }
60
74
  }
61
- const CODES = new Set(['usage', 'not-a-repository', 'not-initialised', 'failed']);
75
+ const CODES = new Set(['usage', 'not-a-repository', 'not-initialised', 'stale-revision', 'not-found', 'already-exists', 'failed']);
62
76
  /** Jig answered in a shape this Jig UI does not read: a Jig newer than the contract its tests pin. */
63
77
  export class JigShapeError extends Error {
64
78
  constructor() {
@@ -67,7 +81,7 @@ export class JigShapeError extends Error {
67
81
  }
68
82
  const isObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
69
83
  /**
70
- * Runs a `--json` read and returns its `data` and the clone's revision. Jig's refusal throws
84
+ * Runs a `--json` command and returns its `data` and the clone's revision — for a write, the one it was checked against. Jig's refusal throws
71
85
  * JigRefusal, as does output that is no JSON at all (a crash); an envelope of another shape throws
72
86
  * JigShapeError.
73
87
  */
@@ -131,7 +145,20 @@ export async function readStatus(root, platform = process.platform) {
131
145
  return { revision, attention, housekeepingStale: housekeeping?.stale === true };
132
146
  }
133
147
  /** Jig's action ids this Jig UI knows; Jig may add ids without raising `schema`, and a consumer ignores those. */
134
- const ACTIONS = new Set(['start', 'pause', 'resume', 'approve-gate', 'answer-stop', 'set-class', 'ship', 'close', 'abandon', 'reopen']);
148
+ const ACTIONS = new Set([
149
+ 'start',
150
+ 'pause',
151
+ 'resume',
152
+ 'request-pause',
153
+ 'cancel-pause-request',
154
+ 'approve-gate',
155
+ 'answer-stop',
156
+ 'set-class',
157
+ 'ship',
158
+ 'close',
159
+ 'abandon',
160
+ 'reopen',
161
+ ]);
135
162
  /** What a person may do next with a task, as Jig decides it from the task's state. */
136
163
  const TaskAction = z.object({
137
164
  id: text,
@@ -141,7 +168,7 @@ const TaskAction = z.object({
141
168
  /** Jig's refusal, word for word, when not offered; it may name a path. */
142
169
  reason: maybe,
143
170
  });
144
- /** A task as `jig task list --json` reports it, as far as Jig UI reads it; the statuses are Jig's (schemas/state.md). */
171
+ /** A task as `jig task list --all --json` reports it, as far as Jig UI reads it; the statuses are Jig's (schemas/state.md). */
145
172
  const TaskRow = z
146
173
  .object({
147
174
  id: text,
@@ -151,6 +178,8 @@ const TaskRow = z
151
178
  goal: maybe,
152
179
  knowledge_consolidated: z.boolean(),
153
180
  paused: z.boolean(),
181
+ /** A pause asked of the task and not yet honoured; its reason is a person's text and not read. */
182
+ pause_request: z.object({ requested_at: text }).nullable(),
154
183
  created_at: maybe,
155
184
  updated_at: maybe,
156
185
  /** `null` while the task has not been started. */
@@ -174,6 +203,7 @@ const TaskRow = z
174
203
  goal: t.goal,
175
204
  knowledgeConsolidated: t.knowledge_consolidated,
176
205
  paused: t.paused,
206
+ pauseRequest: t.pause_request && { requestedAt: t.pause_request.requested_at },
177
207
  createdAt: t.created_at,
178
208
  updatedAt: t.updated_at,
179
209
  branch: t.branch,
@@ -193,10 +223,10 @@ const TaskRow = z
193
223
  housekeepingFlags: t.housekeeping_flags,
194
224
  actions: t.actions.filter((a) => ACTIONS.has(a.id)),
195
225
  }));
196
- const TaskList = z.object({ tasks: z.array(TaskRow), hidden: z.number() });
197
- /** The project's live tasks (`jig task list --json`) and how many finished ones it left out. */
226
+ const TaskList = z.object({ tasks: z.array(TaskRow) });
227
+ /** The project's tasks, the finished ones too while Jig keeps their workspace (`jig task list --all --json`). */
198
228
  export async function readTasks(root, platform = process.platform) {
199
- const { revision, data } = await readJson(root, ['task', 'list'], platform);
229
+ const { revision, data } = await readJson(root, ['task', 'list', '--all'], platform);
200
230
  return { revision, ...parsed(TaskList, data) };
201
231
  }
202
232
  /** How far a roadmap or one of its phases is: items checked, all items, items with a task filed, fog items. */
@@ -243,6 +273,38 @@ export async function readSpecs(root, platform = process.platform) {
243
273
  const { data } = await readJson(root, ['spec', 'list'], platform);
244
274
  return parsed(SpecList, data).specs;
245
275
  }
276
+ /** A task in Jig's queue: its level (`null` the top, `epic:<spec>` an open epic's), its place there, its priority. */
277
+ const QueueItem = z.object({
278
+ kind: text,
279
+ id: text,
280
+ level: maybe,
281
+ /** Sparse; compared only within one level. */
282
+ position: z.int(),
283
+ /** 0, the most urgent, to 5; `null` unset. A label: the order is `position`'s. */
284
+ priority: z.int().min(0).max(5).nullable(),
285
+ });
286
+ const Queue = z.object({ items: z.array(QueueItem) });
287
+ /** The tasks in the project's queue (`jig queue list --json`), in Jig's order; a task not queued is not there, nor is an epic. */
288
+ export async function readQueue(root, platform = process.platform) {
289
+ const { revision, data } = await readJson(root, ['queue', 'list'], platform);
290
+ const items = parsed(Queue, data)
291
+ .items.filter((i) => i.kind === 'task')
292
+ .map(({ id, level, position, priority }) => ({ id, level, position, priority }));
293
+ return { revision, items };
294
+ }
295
+ /**
296
+ * Moves a task in the queue (`jig queue move`), adding it when it is not there; refused as `stale-revision`
297
+ * when anything was written in the clone since `revision`. Ids go to Jig as `task:<id>`, never as a flag.
298
+ */
299
+ export async function moveInQueue(root, task, place, revision, platform = process.platform) {
300
+ const where = place === 'top' ? ['--top'] : place === 'bottom' ? ['--bottom'] : ['--after', `task:${place.after}`];
301
+ await readJson(root, ['queue', 'move', `task:${task}`, ...where, '--revision', String(revision)], platform);
302
+ }
303
+ /** Sets a task's priority in the queue (`jig queue set`), `null` for none; refused as `moveInQueue` is. */
304
+ export async function setPriority(root, task, priority, revision, platform = process.platform) {
305
+ const value = priority === null ? 'none' : String(priority);
306
+ await readJson(root, ['queue', 'set', `task:${task}`, '--priority', value, '--revision', String(revision)], platform);
307
+ }
246
308
  /** True when `version` is at least the minimum Jig UI reads. */
247
309
  export function supports(version, minimum = MIN_JIG_VERSION) {
248
310
  const a = version.split('.').map(Number);
@@ -253,3 +315,22 @@ export function supports(version, minimum = MIN_JIG_VERSION) {
253
315
  }
254
316
  return true;
255
317
  }
318
+ /**
319
+ * Asks a task to pause at its next stage boundary (`jig queue request … pause`); refused as `already-exists` when a
320
+ * pause is already asked, `failed` when the task is paused or finished, and as `moveInQueue` is.
321
+ */
322
+ export async function requestPause(root, task, revision, platform = process.platform) {
323
+ await readJson(root, ['queue', 'request', `task:${task}`, 'pause', '--revision', String(revision)], platform);
324
+ }
325
+ /** Takes back a pause asked of a task (`jig queue cancel … pause`); refused as `not-found` when none is asked. */
326
+ export async function cancelPause(root, task, revision, platform = process.platform) {
327
+ await readJson(root, ['queue', 'cancel', `task:${task}`, 'pause', '--revision', String(revision)], platform);
328
+ }
329
+ /**
330
+ * Files a task with only its goal (`jig task new <id> --goal <text>`); refused as `already-exists` when the id is
331
+ * taken — by a finished task too — and `usage` for an id or goal Jig does not take. No revision: it writes nothing
332
+ * that exists (adr-20261022-filing-a-task-carries-no-revision).
333
+ */
334
+ export async function fileTask(root, id, goal, platform = process.platform) {
335
+ await readJson(root, ['task', 'new', id, '--goal', goal], platform);
336
+ }
@@ -1,5 +1,5 @@
1
1
  import { existsSync } from 'node:fs';
2
- import { JigRefusal, JigShapeError, jigVersion, MIN_JIG_VERSION, readSpecs, readStatus, readTasks, supports, watchDir, writtenByReads, } from '../jig/client.js';
2
+ import { cancelPause, fileTask, JigRefusal, JigShapeError, jigVersion, MIN_JIG_VERSION, moveInQueue, readQueue, readSpecs, readStatus, readTasks, requestPause, setPriority, supports, watchDir, writtenByReads, } from '../jig/client.js';
3
3
  import { addProject, readProjects, removeProject } from '../registry/projects.js';
4
4
  import { watchTree } from '../watch/watch.js';
5
5
  import { mainCheckout } from './checkout.js';
@@ -33,21 +33,33 @@ function count(tasks) {
33
33
  ready: tasks.filter((t) => t.status === 'ready' && !t.paused).length,
34
34
  };
35
35
  }
36
- /** A live task as a board's card shows it. */
37
- const card = (t) => ({
36
+ /** A finished task as the board's list of them shows it. */
37
+ const gone = (t) => ({
38
+ id: t.id,
39
+ status: t.status,
40
+ goal: t.goal,
41
+ updatedAt: t.updatedAt,
42
+ pullRequest: t.pullRequest && { url: t.pullRequest.url, state: t.pullRequest.state },
43
+ });
44
+ /** A live task as a board's card shows it, with its place in the queue if it has one. */
45
+ const card = (t, q) => ({
38
46
  id: t.id,
39
47
  class: t.class,
40
48
  status: t.status,
41
49
  goal: t.goal,
42
50
  paused: t.paused,
51
+ pauseRequest: t.pauseRequest,
52
+ pauseRequestable: t.actions.some((a) => a.id === 'request-pause' && a.offered),
43
53
  started: t.branch !== null,
44
54
  gate: t.gate?.state ?? null,
45
55
  autopilot: t.autopilot?.state ?? null,
46
56
  pullRequest: t.pullRequest,
57
+ priority: q?.priority ?? null,
58
+ queue: q ? { level: q.level, position: q.position } : null,
47
59
  });
48
60
  /** A live task in full; where its worktree is was never read, and an action Jig refuses is left out. */
49
- const details = (t, attention) => ({
50
- ...card(t),
61
+ const details = (t, q, attention) => ({
62
+ ...card(t, q),
51
63
  issue: t.issue,
52
64
  branch: t.branch,
53
65
  baseBranch: t.baseBranch,
@@ -92,27 +104,31 @@ async function reading({ id, path }, read) {
92
104
  }
93
105
  async function readProject(project) {
94
106
  const read = await reading(project, async (root, jigVersion) => {
95
- const [status, list, specs] = await Promise.all([readStatus(root), readTasks(root), readSpecs(root)]);
96
- return { status, list, specs, jigVersion };
107
+ const [status, list, queue, specs] = await Promise.all([readStatus(root), readTasks(root), readQueue(root), readSpecs(root)]);
108
+ return { status, list, queue, specs, jigVersion };
97
109
  });
98
110
  if (!('list' in read))
99
111
  return { view: read, tasks: read, details: [], specs: read, revision: null };
100
- const { status, list, specs, jigVersion } = read;
101
- // Jig's live list holds active and ready tasks only.
112
+ const { status, list, queue, specs, jigVersion } = read;
113
+ // Live: active and ready; the rest are finished.
102
114
  const live = list.tasks.filter((t) => t.status === 'active' || t.status === 'ready');
115
+ const finished = list.tasks.filter((t) => t.status === 'consolidated' || t.status === 'abandoned');
116
+ const queued = new Map(queue.items.map((q) => [q.id, q]));
117
+ // The oldest of the reads the board is made of: a write against it is refused if anything was written after any of them.
118
+ const revision = Math.min(status.revision, list.revision, queue.revision);
103
119
  return {
104
120
  view: {
105
121
  id: project.id,
106
122
  state: 'ready',
107
123
  jigVersion,
108
- counts: count(list.tasks),
124
+ counts: count(live),
109
125
  attention: status.attention,
110
126
  housekeepingStale: status.housekeepingStale,
111
127
  },
112
- tasks: { state: 'ready', tasks: live.map(card), finished: list.hidden },
113
- details: live.map((t) => details(t, status.attention)),
128
+ tasks: { state: 'ready', tasks: live.map((t) => card(t, queued.get(t.id))), finished: finished.map(gone), revision },
129
+ details: live.map((t) => details(t, queued.get(t.id), status.attention)),
114
130
  specs: { state: 'ready', specs },
115
- revision: list.revision,
131
+ revision,
116
132
  };
117
133
  }
118
134
  /** A read that may have caught Jig mid-write: worth one more try before it is believed. */
@@ -241,6 +257,31 @@ export function localSource(configDir, { rescanMs = 60_000, quietMs, maxWaitMs }
241
257
  entry.held = false;
242
258
  }
243
259
  }
260
+ /**
261
+ * Runs a write in a project once every task it names is live in what the project shows — so nothing but an id
262
+ * Jig itself listed reaches Jig's arguments; a new task's id names none, and the HTTP boundary checks it against
263
+ * Jig's grammar instead — then reads the project again, refused or not: the page reads next.
264
+ */
265
+ async function writing(id, taskIds, write) {
266
+ const project = (await readProjects(configDir)).find((p) => p.id === id);
267
+ if (!project)
268
+ return undefined;
269
+ const { tasks } = await shown(project);
270
+ if (tasks.state !== 'ready')
271
+ return tasks;
272
+ if (!taskIds.every((t) => tasks.tasks.some((live) => live.id === t)))
273
+ return { state: 'refused', code: 'not-found' };
274
+ let written = { state: 'written' };
275
+ try {
276
+ await write(project.path);
277
+ }
278
+ catch (error) {
279
+ // Only the code goes on: Jig's message may name a path.
280
+ written = { state: 'refused', code: error instanceof JigRefusal ? error.code : 'failed' };
281
+ }
282
+ await refresh(entryOf(project));
283
+ return written;
284
+ }
244
285
  return {
245
286
  async workspace() {
246
287
  return Promise.all((await readProjects(configDir)).map(async (p) => (await shown(p)).view));
@@ -276,6 +317,23 @@ export function localSource(configDir, { rescanMs = 60_000, quietMs, maxWaitMs }
276
317
  const project = (await readProjects(configDir)).find((p) => p.id === id);
277
318
  return project && (await shown(project)).specs;
278
319
  },
320
+ move(id, taskId, place, revision) {
321
+ const named = typeof place === 'object' ? [taskId, place.after] : [taskId];
322
+ return writing(id, named, (root) => moveInQueue(root, taskId, place, revision));
323
+ },
324
+ prioritise(id, taskId, priority, revision) {
325
+ return writing(id, [taskId], (root) => setPriority(root, taskId, priority, revision));
326
+ },
327
+ requestPause(id, taskId, revision) {
328
+ return writing(id, [taskId], (root) => requestPause(root, taskId, revision));
329
+ },
330
+ cancelPause(id, taskId, revision) {
331
+ return writing(id, [taskId], (root) => cancelPause(root, taskId, revision));
332
+ },
333
+ fileTask(id, taskId, goal) {
334
+ // A new id names no live task: Jig itself refuses a taken one.
335
+ return writing(id, [], (root) => fileTask(root, taskId, goal));
336
+ },
279
337
  async disconnect(id) {
280
338
  if (!(await removeProject(configDir, id)))
281
339
  return false;
@@ -0,0 +1 @@
1
+ import{$ as e,A as t,B as n,C as r,D as i,E as a,F as o,G as s,H as ee,I as te,J as c,K as l,L as u,M as d,N as f,O as p,P as m,Q as h,R as g,S as ne,T as _,U as v,V as y,W as b,X as x,Y as S,Z as C,_ as re,a as ie,b as w,c as ae,d as oe,et as T,f as E,g as se,h as D,i as O,j as k,k as ce,l as le,m as A,n as j,nt as M,o as N,p as ue,q as de,r as fe,s as pe,t as me,tt as he,u as P,v as ge,w as F,x as I,y as L,z as R}from"./index-DNFgC6Vp.js";var _e=l({__name:`BaseSeparator`,props:{orientation:{type:String,required:!1,default:`horizontal`},decorative:{type:Boolean,required:!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},setup(t){let n=t,r=[`horizontal`,`vertical`];function i(e){return r.includes(e)}let a=R(()=>i(n.orientation)?n.orientation:`horizontal`),o=R(()=>a.value===`vertical`?n.orientation:void 0),s=R(()=>n.decorative?{role:`none`}:{"aria-orientation":o.value,role:`separator`});return(n,r)=>(S(),y(e(d),c({as:t.as,"as-child":t.asChild,"data-orientation":a.value},s.value),{default:h(()=>[C(n.$slots,`default`)]),_:3},16,[`as`,`as-child`,`data-orientation`]))}}),ve=l({__name:`Separator`,props:{orientation:{type:String,required:!1,default:`horizontal`},decorative:{type:Boolean,required:!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},setup(e){let t=e;return(e,n)=>(S(),y(_e,he(de(t)),{default:h(()=>[C(e.$slots,`default`)]),_:3},16))}}),ye=l({__name:`CardContent`,props:{class:{type:[Boolean,null,String,Object,Array]}},setup(t){let n=t;return(t,r)=>(S(),v(`div`,{"data-slot":`card-content`,class:T(e(f)(`px-4 group-data-[size=sm]/card:px-3`,n.class))},[C(t.$slots,`default`)],2))}}),be=l({__name:`CardDescription`,props:{class:{type:[Boolean,null,String,Object,Array]}},setup(t){let n=t;return(t,r)=>(S(),v(`div`,{"data-slot":`card-description`,class:T(e(f)(`text-xs/relaxed text-muted-foreground`,n.class))},[C(t.$slots,`default`)],2))}}),xe=l({__name:`CardHeader`,props:{class:{type:[Boolean,null,String,Object,Array]}},setup(t){let n=t;return(t,r)=>(S(),v(`div`,{"data-slot":`card-header`,class:T(e(f)(`group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-none px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3`,n.class))},[C(t.$slots,`default`)],2))}}),Se=l({__name:`CardTitle`,props:{class:{type:[Boolean,null,String,Object,Array]}},setup(t){let n=t;return(t,r)=>(S(),v(`div`,{"data-slot":`card-title`,class:T(e(f)(`cn-font-heading text-sm font-medium group-data-[size=sm]/card:text-sm`,n.class))},[C(t.$slots,`default`)],2))}}),z=l({__name:`Separator`,props:{orientation:{default:`horizontal`},decorative:{type:Boolean,default:!0},asChild:{type:Boolean},as:{},class:{type:[Boolean,null,String,Object,Array]}},setup(t){let n=t,r=p(n,`class`);return(t,i)=>(S(),y(e(ve),c({"data-slot":`separator`},e(r),{class:e(f)(`shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch`,n.class)}),null,16,[`class`]))}}),Ce=[`aria-label`],we={class:`flex items-baseline gap-3 border-b bg-muted/50 px-4 py-2`},Te={class:`font-semibold tracking-wider uppercase`},Ee={key:0,class:`text-muted-foreground`},B={class:`grid grid-cols-1 divide-y lg:grid-cols-2 lg:divide-x lg:divide-y-0`},V=l({__name:`CanvasSection`,props:{title:{},note:{}},setup(e){return(t,r)=>(S(),v(`section`,{"aria-label":e.title,class:`border-b`},[n(`h2`,we,[n(`span`,Te,M(e.title),1),e.note?(S(),v(`span`,Ee,M(e.note),1)):ee(``,!0)]),n(`div`,B,[(S(),v(g,null,x([`light`,`dark`],e=>n(`div`,{key:e,class:T([e,`flex flex-col gap-4 bg-background p-4 text-foreground`])},[C(t.$slots,`default`)],2)),64))])],8,Ce))}}),H=(e,t)=>({id:e,class:`T2`,status:`active`,goal:null,paused:!1,pauseRequest:null,pauseRequestable:!0,started:!0,gate:null,autopilot:null,pullRequest:null,priority:null,queue:null,...t}),U=(e,t)=>({url:`https://github.com/fapost-lab/jig-ui/pull/18`,state:e,ci:t,fetchedAt:`2026-10-18T09:40:00Z`}),W=[H(`design-system`,{class:`T3`,gate:`waiting`,priority:0,queue:{level:null,position:100},goal:`shadcn-vue on Tailwind v4 with light and dark themes; #/canvas with every component in every variant; the three screens rebuilt on it.`}),H(`registry-schema`,{gate:`changed`,priority:3,queue:{level:null,position:200},goal:`Version the registry file so a newer Jig UI can read an older one.`}),H(`pause-request`,{class:`T3`,autopilot:`stopped`,goal:`A drop on the paused column writes a sticky request through Jig; the card shows it with its age and a cancel.`}),H(`specs-and-epics`,{autopilot:`on`,queue:{level:null,position:300},goal:`Show each spec with its phases, progress and epic branch beside the board, from Jig's spec list.`}),H(`task-details`,{status:`ready`,pullRequest:U(`open`,`green`),goal:`Open a task's details from its card.`}),H(`refusal-fixture`,{class:`T0`,status:`ready`,pullRequest:U(`open`,`red`),goal:`Replace the refusal text in task-list-states.json with one Jig prints.`}),H(`docs-board`,{class:`T1`,status:`ready`,pullRequest:U(`open`,`pending`),goal:`Describe the five columns on the projects page of the docs.`}),H(`live-updates`,{status:`ready`,pullRequest:U(`merged`,`none`),goal:`Follow connected projects without a reload.`}),H(`no-pr-yet`,{class:`T1`,status:`ready`,goal:`Ready, nothing pushed.`}),H(`jig-init-hook`,{class:`T3`,paused:!0,pauseRequestable:!1,goal:`Register a project in an installed Jig UI from jig init.`}),H(`file-backlog-task`,{class:null,started:!1,goal:`File a minimal backlog task from the page through jig task new.`}),H(`a-task-with-a-rather-long-identifier-that-wraps`,{goal:null}),H(`conflict-display`,{pauseRequest:{requestedAt:`2026-10-22T09:00:00Z`},pauseRequestable:!1,goal:`Show what changed when a write was based on a stale read.`})],G=[{id:`needs-you`,title:`Needs you`,cards:W.slice(0,3)},{id:`in-progress`,title:`In progress`,cards:[W[3],W[12],W[11]]},{id:`ready`,title:`Ready`,cards:W.slice(4,9)},{id:`backlog`,title:`Backlog`,cards:[W[10]]},{id:`paused`,title:`Paused`,cards:[W[9]]}],K=G.map(e=>({...e,cards:[]})),De=[{id:`file-backlog-task`,status:`consolidated`,goal:`File a minimal backlog task from the page.`,updatedAt:`2026-10-25`,pullRequest:{url:`https://github.com/fapost-lab/jig-ui/pull/40`,state:`merged`}},{id:`pr-template`,status:`abandoned`,goal:`A pull request template.`,updatedAt:`2026-10-17`,pullRequest:null},{id:`old-spike`,status:`abandoned`,goal:null,updatedAt:`2026-10-12`,pullRequest:null}],Oe=[{id:`needs-you`,title:`Needs you`,count:3},{id:`in-progress`,title:`In progress`,count:1},{id:`ready`,title:`Ready`,count:5},{id:`backlog`,title:`Backlog`,count:1},{id:`paused`,title:`Paused`,count:1},{id:`unknown`,title:`A column this page does not know`,count:0}],q=[{kind:`gate`,subject:{type:`task`,id:`design-system`},tasks:[`design-system`],title:`Design waits at its gate`,detail:null,todo:`Review the design and approve it: jig task gate design-system approved`,url:null},{kind:`pull-request-ci-failed`,subject:{type:`task`,id:`refusal-fixture`},tasks:[`refusal-fixture`],title:`CI failed`,detail:`pull request #19`,todo:`Look at the failing check.`,url:`https://github.com/fapost-lab/jig-ui/pull/19`},{kind:`housekeeping`,subject:{type:`project`,id:null},tasks:[],title:`Housekeeping never ran`,detail:null,todo:`Run jig housekeeping.`,url:`https://example.com/docs`}],J=[{id:`approve-gate`,command:`jig task gate design-system approved`},{id:`answer-stop`,command:`jig task autopilot pause-request resume --answer <text>`},{id:`pause`,command:`jig task pause design-system`},{id:`request-pause`,command:`jig queue request task:design-system pause`},{id:`something-new`,command:`jig task something-new design-system`}],Y={state:`ready`,issue:null,baseBranch:`main`,createdAt:`2026-10-17`,updatedAt:`2026-10-18`,knowledgeConsolidated:!1,worktree:null,gateBy:null,run:null,housekeepingFlags:[],attention:[]},X=[{...Y,...W[2],gate:`approved`,gateBy:`human`,branch:`task/pause-request`,worktree:{uncommitted:4},issue:`#42`,pullRequest:U(`open`,`red`),run:{mode:`attended`,stage:`implement`,stageAt:`2026-10-18T09:00:00Z`,stopReason:`Which column takes a paused task that already has an open pull request?`,stopAt:`2026-10-18T09:12:00Z`,phase:null},housekeepingFlags:[`needs-consolidation`],attention:[q[0]],actions:J,column:{id:`needs-you`,title:`Needs you`}},{...Y,...W[10],branch:null,actions:[{id:`start`,command:`jig task start file-backlog-task`}],column:{id:`backlog`,title:`Backlog`}}],Z=(e,t={})=>({id:e,state:`ready`,jigVersion:`0.29.0`,counts:{active:11,paused:1,ready:3},attention:[],housekeepingStale:!1,...t}),Q=[Z(`jig-ui`,{attention:q,housekeepingStale:!0}),Z(`nextjs-store`,{counts:{active:0,paused:0,ready:0}}),{id:`old-jig`,state:`unsupported`,jigVersion:`0.26.0`,minimum:`0.29.0`},{id:`new-jig`,state:`incompatible`,jigVersion:`1.0.0`},{id:`busy`,state:`unreadable`,code:`locked`},{id:`moved`,state:`unavailable`,reason:`missing`}],$=[{text:"`design-system` — design system and canvas",checked:!0,task:`design-system`,fog:!1},{text:"`specs-and-epics` — specs and epics (after: project board — `jig spec list`)",checked:!1,task:`specs-and-epics`,fog:!1},{text:"`old-task` — a task no longer live",checked:!1,task:`old-task`,fog:!1},{text:`invoices from orders, no task filed yet`,checked:!1,task:null,fog:!1},{text:"fog: registration by `jig init`",checked:!1,task:null,fog:!0}],ke=[{id:`jig-ui`,title:`Jig UI — a local control center for Jig projects`,missingFiles:[],release:null,epic:null,progress:{done:2,total:6,filed:2,fog:1},phases:[{phase:0,title:`Package and release`,done:1,total:1,filed:0,fog:0,items:[{...$[0],text:`package and release`,task:null}]},{phase:1,title:`Read-only UI`,done:1,total:5,filed:2,fog:1,items:$}]},{id:`billing`,title:`Billing in one place`,missingFiles:[],release:`minor`,epic:{branch:`epic/billing`,state:`open`,checkedOut:!1,missing:!1,fetched:!0},progress:{done:0,total:1,filed:0,fog:0},phases:[{phase:null,title:null,done:0,total:1,filed:0,fog:0,items:[$[3]]}]},{id:`lost-epic`,title:`An epic whose branch is gone`,missingFiles:[],release:`major`,epic:{branch:`epic/lost`,state:`open`,checkedOut:!0,missing:!0,fetched:!1},progress:null,phases:[]},{id:`half-written`,title:null,missingFiles:[`spec.md`,`roadmap.md`],release:null,epic:null,progress:null,phases:[]}],Ae={class:`flex gap-4`},je={class:`w-24 text-muted-foreground`},Me={class:`flex items-center gap-2`},Ne={class:`flex flex-wrap gap-2`},Pe={class:`flex max-w-sm flex-col gap-2`},Fe={class:`flex h-5 items-center gap-2`},Ie={class:`flex gap-2`},Le={class:`flex flex-wrap items-center gap-6`},Re={class:`flex items-center gap-1`},ze={class:`grid grid-cols-2 gap-2 xl:grid-cols-3`},Be={class:`flex h-[28rem] flex-col`},Ve={class:`flex h-40 flex-col`},He={class:`flex h-[28rem] flex-col`},Ue={class:`flex h-64 flex-col`},We={class:`flex h-64 flex-col`},Ge=l({__name:`CanvasView`,setup(ee){let c=[`default`,`secondary`,`outline`,`ghost`,`destructive`,`link`],l=[`xs`,`sm`,`default`,`lg`],d=[`icon-xs`,`icon-sm`,`icon`,`icon-lg`],f=[`default`,`secondary`,`outline`,`ghost`,`destructive`,`link`],p=[`attention`,`good`,`bad`,`quiet`];return(ee,C)=>(S(),v(`div`,null,[C[14]||=n(`div`,{class:`border-b px-4 py-3`},[n(`h1`,{class:`font-semibold tracking-wider uppercase`},`Canvas`),n(`p`,{class:`text-muted-foreground`},`Every component of the page in every variant and state; the left panel light, the right dark.`)],-1),s(V,{title:`Tones`,note:`lib/tones.ts — the only colours with a meaning`},{default:h(()=>[(S(),v(g,null,x(p,t=>n(`p`,{key:t,class:T(e(te)[t])},M(t)+` as a rule`,3)),64)),n(`p`,Ae,[(S(),v(g,null,x(p,t=>n(`span`,{key:t,class:T(e(u)[t])},M(t),3)),64))])]),_:1}),C[15]||=n(`h2`,{class:`border-b px-4 py-2 font-bold tracking-widest uppercase`},`components/ui`,-1),s(V,{title:`Button`,note:`variant × size; icon sizes; disabled`},{default:h(()=>[(S(),v(g,null,x(c,t=>n(`div`,{key:t,class:`flex flex-wrap items-center gap-2`},[n(`span`,je,M(t),1),(S(),v(g,null,x(l,n=>s(e(k),{key:n,variant:t,size:n},{default:h(()=>[b(M(n),1)]),_:2},1032,[`variant`,`size`])),64)),s(e(k),{variant:t,disabled:``},{default:h(()=>[...C[0]||=[b(`disabled`,-1)]]),_:1},8,[`variant`])])),64)),n(`div`,Me,[C[2]||=n(`span`,{class:`w-24 text-muted-foreground`},`icon`,-1),(S(),v(g,null,x(d,t=>s(e(k),{key:t,variant:`outline`,size:t,"aria-label":t},{default:h(()=>[s(e(m))]),_:1},8,[`size`,`aria-label`])),64)),s(e(k),{variant:`outline`,size:`sm`},{default:h(()=>[s(e(m),{"data-icon":`inline-start`}),C[1]||=b(`with icon`,-1)]),_:1})])]),_:1}),s(V,{title:`Badge`},{default:h(()=>[n(`div`,Ne,[(S(),v(g,null,x(f,t=>s(e(i),{key:t,variant:t},{default:h(()=>[b(M(t),1)]),_:2},1032,[`variant`])),64))])]),_:1}),s(V,{title:`Card`},{default:h(()=>[s(e(a),{class:`max-w-sm`},{default:h(()=>[s(e(xe),null,{default:h(()=>[s(e(Se),null,{default:h(()=>[...C[3]||=[b(`Card title`,-1)]]),_:1}),s(e(be),null,{default:h(()=>[...C[4]||=[b(`Card description, muted.`,-1)]]),_:1})]),_:1}),s(e(ye),null,{default:h(()=>[...C[5]||=[b(`Card content.`,-1)]]),_:1})]),_:1})]),_:1}),s(V,{title:`Input and Label`,note:`empty, filled, invalid, disabled`},{default:h(()=>[n(`div`,Pe,[s(e(oe),null,{default:h(()=>[...C[6]||=[b(`Project path`,-1)]]),_:1}),s(e(E),{placeholder:`/path/to/project`}),s(e(E),{"model-value":`/Users/me/project`}),s(e(E),{"model-value":`/not/a/project`,"aria-invalid":`true`}),s(e(E),{"model-value":`disabled`,disabled:``})])]),_:1}),s(V,{title:`Separator`},{default:h(()=>[s(e(z)),n(`div`,Fe,[C[7]||=b(`left`,-1),s(e(z),{orientation:`vertical`}),C[8]||=b(`right`,-1)])]),_:1}),s(V,{title:`ToggleGroup`,note:`the Board / List switch`},{default:h(()=>[s(e(ie),{type:`single`,variant:`outline`,size:`sm`,"model-value":`board`,"aria-label":`View`},{default:h(()=>[s(e(O),{value:`board`},{default:h(()=>[...C[9]||=[b(`Board`,-1)]]),_:1}),s(e(O),{value:`list`},{default:h(()=>[...C[10]||=[b(`List`,-1)]]),_:1})]),_:1})]),_:1}),s(V,{title:`Toggle`,note:`the board's finished tasks: off, on`},{default:h(()=>[n(`div`,Ie,[s(e(N),{variant:`outline`,size:`sm`,"model-value":!1},{default:h(()=>[...C[11]||=[b(`3 finished tasks`,-1)]]),_:1}),s(e(N),{variant:`outline`,size:`sm`,"model-value":!0},{default:h(()=>[...C[12]||=[b(`3 finished tasks`,-1)]]),_:1})])]),_:1}),s(V,{title:`Collapsible`,note:`open and folded`},{default:h(()=>[(S(),v(g,null,x([!0,!1],t=>s(e(ge),{key:String(t),"default-open":t},{default:h(()=>[s(e(se),{class:`w-full border-b bg-muted/50 px-3 py-1.5 text-left`},{default:h(()=>[b(`Trigger (`+M(t?`open`:`folded`)+`)`,1)]),_:2},1024),s(e(re),{class:`px-3 py-2`},{default:h(()=>[...C[13]||=[b(`Content`,-1)]]),_:1})]),_:2},1032,[`default-open`])),64))]),_:1}),C[16]||=n(`h2`,{class:`border-b px-4 py-2 font-bold tracking-widest uppercase`},`components`,-1),s(V,{title:`ProjectTabs`,note:`on the workspace; on a project; empty`},{default:h(()=>[s(o,{projects:e(Q),version:`0.1.0`},{default:h(()=>[s(t)]),_:1},8,[`projects`]),s(o,{projects:e(Q),current:`jig-ui`,version:`0.1.0`},null,8,[`projects`]),s(o,{projects:[]})]),_:1}),s(V,{title:`ThemeToggle`,note:`switches the whole page; the icon is the theme it switches to`},{default:h(()=>[n(`div`,null,[s(t)])]),_:1}),s(V,{title:`ProjectCard`,note:`ready with attention and stale housekeeping; nothing needs you; each state it cannot be read in`},{default:h(()=>[(S(!0),v(g,null,x(e(Q),e=>(S(),y(me,{key:e.id,project:e},null,8,[`project`]))),128))]),_:1}),s(V,{title:`NewTaskForm`,note:`empty, on its way, the id taken`},{default:h(()=>[s(P,{busy:!1}),s(P,{busy:!0,task:`fix-login`,goal:`Log in with the token after a restart.`}),s(P,{busy:!1,task:`queue-reorder`,goal:`Order the work.`,refusal:`The project has a task called queue-reorder already, maybe a finished one. Choose another id.`,taken:``})]),_:1}),s(V,{title:`ConnectForm`,note:`idle, busy, refused`},{default:h(()=>[s(j,{busy:!1}),s(j,{busy:!0,"model-value":`/Users/me/project`}),s(j,{busy:!1,"model-value":`/Users/me/project/.claude/worktrees/x`,refusal:`That is a worktree. Connect the main checkout instead.`})]),_:1}),s(V,{title:`AttentionItem`,note:`no link; a pull request; another link`},{default:h(()=>[(S(!0),v(g,null,x(e(q),(e,t)=>(S(),y(fe,{key:t,item:e},null,8,[`item`]))),128))]),_:1}),s(V,{title:`ColumnHeader`,note:`each column, and one this page does not know`},{default:h(()=>[(S(!0),v(g,null,x(e(Oe),e=>(S(),y(ce,{id:e.id,key:e.id,title:e.title,count:e.count},null,8,[`id`,`title`,`count`]))),128))]),_:1}),s(V,{title:`QueueMenu`,note:`press to open: To top, Up, Down, To bottom, Priority, the pause — first queued, in the middle, not queued, last, paused (no pause to ask), a pause asked, while its change is on its way`},{default:h(()=>[n(`div`,Le,[(S(!0),v(g,null,x([e(W)[0],e(W)[1],e(W)[3],e(W)[11],e(W)[9],e(W)[12]],t=>(S(),v(`span`,{key:t.id,class:`flex items-center gap-1`},[b(M(t.id),1),s(_,{task:t,cards:e(W)},null,8,[`task`,`cards`])]))),128)),n(`span`,Re,[b(M(e(W)[1].id),1),s(_,{task:e(W)[1],cards:e(W),disabled:``},null,8,[`task`,`cards`])])])]),_:1}),s(V,{title:`TaskCard`,note:`every note a card carries, a priority among them; with its queue menu; while its change is on its way; changed since a refused change; open with details, while reading, unreadable`},{default:h(()=>[n(`div`,ze,[(S(!0),v(g,null,x(e(W),e=>(S(),y(w,{key:e.id,project:`jig-ui`,task:e,open:!1},null,8,[`task`]))),128)),s(w,{project:`jig-ui`,task:e(W)[1],open:!1,cards:e(W)},null,8,[`task`,`cards`]),s(w,{project:`jig-ui`,task:e(W)[0],open:!1,cards:e(W),busy:``},null,8,[`task`,`cards`]),s(w,{project:`jig-ui`,task:e(W)[3],open:!1,cards:e(W),changed:``},null,8,[`task`,`cards`]),s(w,{project:`jig-ui`,task:e(W)[2],open:!0,details:e(X)[0]},null,8,[`task`,`details`]),s(w,{project:`jig-ui`,task:e(W)[0],open:!0},null,8,[`task`]),s(w,{project:`jig-ui`,task:e(W)[1],open:!0,details:`unavailable`},null,8,[`task`])])]),_:1}),s(V,{title:`TaskRow`,note:`each note and priority; selected; with its queue menu; while its change is on its way; changed since a refused change`},{default:h(()=>[n(`div`,null,[(S(!0),v(g,null,x(e(W),(e,t)=>(S(),y(D,{key:e.id,task:e,selected:t===2},null,8,[`task`,`selected`]))),128)),s(D,{task:e(W)[1],selected:!1,cards:e(W)},null,8,[`task`,`cards`]),s(D,{task:e(W)[0],selected:!1,cards:e(W),busy:``},null,8,[`task`,`cards`]),s(D,{task:e(W)[3],selected:!1,cards:e(W),changed:``},null,8,[`task`,`cards`])])]),_:1}),s(V,{title:`BoardColumns`,note:`cards in every column, one open with its details, two changed since a refused change; no live task`},{default:h(()=>[n(`div`,Be,[s(L,{project:`jig-ui`,columns:e(G),selected:e(W)[2].id,details:e(X)[0],pending:e(W)[0].id,changed:[e(W)[1].id,e(W)[3].id]},null,8,[`columns`,`selected`,`details`,`pending`,`changed`])]),n(`div`,Ve,[s(L,{project:`jig-ui`,columns:e(K)},null,8,[`columns`])])]),_:1}),s(V,{title:`BoardList`,note:`a row picked with its details; nothing picked; no live task`},{default:h(()=>[n(`div`,He,[s(A,{project:`jig-ui`,columns:e(G),selected:e(W)[2].id,details:e(X)[0]},null,8,[`columns`,`selected`,`details`])]),n(`div`,Ue,[s(A,{project:`jig-ui`,columns:e(G)},null,8,[`columns`])]),n(`div`,We,[s(A,{project:`jig-ui`,columns:e(K)},null,8,[`columns`])])]),_:1}),s(V,{title:`FinishedList`,note:`closed with its pull request merged; abandoned; one without a goal`},{default:h(()=>[s(ue,{tasks:e(De),class:`border`},null,8,[`tasks`])]),_:1}),s(V,{title:`TaskFacts`,note:`everything a task can carry; a task not started`},{default:h(()=>[(S(!0),v(g,null,x(e(X),e=>(S(),y(ne,{key:e.id,details:e,class:`border-b pb-3`},null,8,[`details`]))),128))]),_:1}),s(V,{title:`TaskBrief`,note:`facts, actions and the link to the full page`},{default:h(()=>[s(I,{project:`jig-ui`,task:e(X)[1].id,details:e(X)[1]},null,8,[`task`,`details`])]),_:1}),s(V,{title:`ActionList`,note:`Jig's offers, one unknown id; none`},{default:h(()=>[s(r,{actions:e(J)},null,8,[`actions`]),s(r,{actions:[]})]),_:1}),s(V,{title:`CopyCommand`,note:`short; long enough to be cut`},{default:h(()=>[s(F,{command:`jig task pause design-system`}),s(F,{command:`jig task autopilot a-task-with-a-rather-long-identifier-that-wraps resume --answer 'a long answer to the question'`,class:`max-w-xs`})]),_:1}),s(V,{title:`ProgressBar`,note:`none, part, all, an empty roadmap`},{default:h(()=>[(S(),v(g,null,x([[0,4],[3,9],[5,5],[0,0]],([e,t])=>s(le,{key:`${e}/${t}`,done:e,total:t},null,8,[`done`,`total`])),64))]),_:1}),s(V,{title:`SpecItemRow`,note:`done with a live task; open with dependencies; a task no longer live; no task; fog`},{default:h(()=>[n(`ul`,null,[(S(!0),v(g,null,x(e($),(e,t)=>(S(),y(ae,{key:t,item:e,project:`jig-ui`,live:t<2},null,8,[`item`,`live`]))),128))])]),_:1}),s(V,{title:`SpecCard`,note:`no epic, a finished phase folded; an open epic as of the last fetch; a lost epic branch; missing files`},{default:h(()=>[(S(!0),v(g,null,x(e(ke),e=>(S(),y(pe,{key:e.id,spec:e,project:`jig-ui`,live:[`design-system`,`specs-and-epics`]},null,8,[`spec`]))),128))]),_:1})]))}});export{Ge as default};
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-divide-x-reverse:0;--tw-border-style:solid;--tw-divide-y-reverse:0;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-duration:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:"JetBrains Mono Variable", ui-monospace, monospace;--color-red-600:oklch(57.7% .245 27.325);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-700:oklch(55.5% .163 48.998);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-sky-500:oklch(68.5% .169 237.323);--color-slate-400:oklch(70.4% .04 256.788);--color-zinc-400:oklch(70.5% .015 286.067);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-3xl:48rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wider:.05em;--tracking-widest:.1em;--leading-relaxed:1.625;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:"JetBrains Mono Variable", ui-monospace, monospace}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){*{outline-color:color-mix(in oklab, var(--ring) 50%, transparent)}}body{background-color:var(--background);font-family:JetBrains Mono Variable,ui-monospace,monospace;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--foreground)}}@layer components;@layer utilities{.\@container\/card-header{container:card-header/inline-size}.\@container{container-type:inline-size}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-x-0{inset-inline:0}.-top-1\.5{top:calc(var(--spacing) * -1.5)}.top-0{top:0}.right-2{right:calc(var(--spacing) * 2)}.-bottom-1\.5{bottom:calc(var(--spacing) * -1.5)}.bottom-0{bottom:0}.z-10{z-index:10}.z-50{z-index:50}.col-start-2{grid-column-start:2}.row-span-2{grid-row:span 2/span 2}.row-start-1{grid-row-start:1}.-mx-1{margin-inline:calc(var(--spacing) * -1)}.mx-auto{margin-inline:auto}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mb-1{margin-bottom:var(--spacing)}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.h-0\.5{height:calc(var(--spacing) * .5)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-3{height:calc(var(--spacing) * 3)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-40{height:calc(var(--spacing) * 40)}.h-64{height:calc(var(--spacing) * 64)}.h-\[28rem\]{height:28rem}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-\(--reka-dropdown-menu-content-available-height\){max-height:var(--reka-dropdown-menu-content-available-height)}.max-h-48{max-height:calc(var(--spacing) * 48)}.min-h-0{min-height:0}.w-\(--reka-dropdown-menu-trigger-width\){width:var(--reka-dropdown-menu-trigger-width)}.w-1{width:var(--spacing)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-20{width:calc(var(--spacing) * 20)}.w-24{width:calc(var(--spacing) * 24)}.w-40{width:calc(var(--spacing) * 40)}.w-44{width:calc(var(--spacing) * 44)}.w-56{width:calc(var(--spacing) * 56)}.w-96{width:calc(var(--spacing) * 96)}.w-fit{width:fit-content}.w-full{width:100%}.max-w-\(--reka-dropdown-menu-content-available-width\){max-width:var(--reka-dropdown-menu-content-available-width)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-sm{max-width:var(--container-sm)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:0}.min-w-7{min-width:calc(var(--spacing) * 7)}.min-w-8{min-width:calc(var(--spacing) * 8)}.min-w-9{min-width:calc(var(--spacing) * 9)}.min-w-32{min-width:calc(var(--spacing) * 32)}.min-w-64{min-width:calc(var(--spacing) * 64)}.min-w-\[96px\]{min-width:96px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.origin-\(--reka-dropdown-menu-content-transform-origin\){transform-origin:var(--reka-dropdown-menu-content-transform-origin)}.cursor-default{cursor:default}.auto-rows-min{grid-auto-rows:min-content}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[repeat\(5\,minmax\(14rem\,1fr\)\)\]{grid-template-columns:repeat(5,minmax(14rem,1fr))}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-\[--spacing\(var\(--gap\)\)\]{gap:calc(var(--spacing) * var(--gap))}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-1{row-gap:var(--spacing)}:where(.divide-x>:not(:last-child)){--tw-divide-x-reverse:0;border-inline-style:var(--tw-border-style);border-inline-start-width:calc(1px * var(--tw-divide-x-reverse));border-inline-end-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}.self-start{align-self:flex-start}.justify-self-end{justify-self:flex-end}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded-none{border-radius:0}.border{border-style:var(--tw-border-style);border-width:1px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-amber-500{border-color:var(--color-amber-500)}.border-border{border-color:var(--border)}.border-destructive{border-color:var(--destructive)}.border-emerald-500{border-color:var(--color-emerald-500)}.border-input{border-color:var(--input)}.border-transparent{border-color:#0000}.bg-amber-500{background-color:var(--color-amber-500)}.bg-background{background-color:var(--background)}.bg-border{background-color:var(--border)}.bg-card{background-color:var(--card)}.bg-destructive\/10{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.bg-destructive\/10{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-foreground{background-color:var(--foreground)}.bg-muted,.bg-muted\/50{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/50{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-red-600{background-color:var(--color-red-600)}.bg-secondary{background-color:var(--secondary)}.bg-sky-500{background-color:var(--color-sky-500)}.bg-slate-400{background-color:var(--color-slate-400)}.bg-transparent{background-color:#0000}.bg-zinc-400{background-color:var(--color-zinc-400)}.bg-clip-padding{background-clip:padding-box}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-2{padding-left:calc(var(--spacing) * 2)}.text-center{text-align:center}.text-left{text-align:left}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-xs\/relaxed{font-size:var(--text-xs);line-height:var(--leading-relaxed)}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.text-amber-700{color:var(--color-amber-700)}.text-background{color:var(--background)}.text-black{color:var(--color-black)}.text-card-foreground{color:var(--card-foreground)}.text-destructive{color:var(--destructive)}.text-emerald-700{color:var(--color-emerald-700)}.text-foreground{color:var(--foreground)}.text-muted-foreground{color:var(--muted-foreground)}.text-popover-foreground{color:var(--popover-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.underline-offset-4{text-underline-offset:4px}.opacity-60{opacity:.6}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-foreground,.ring-foreground\/10{--tw-ring-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.ring-foreground\/10{--tw-ring-color:color-mix(in oklab, var(--foreground) 10%, transparent)}}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.paused{animation-play-state:paused}.running{animation-play-state:running}.group-focus\/dropdown-menu-item\:text-accent-foreground:is(:where(.group\/dropdown-menu-item):focus *){color:var(--accent-foreground)}.group-data-\[disabled\=true\]\:pointer-events-none:is(:where(.group)[data-disabled=true] *){pointer-events:none}.group-data-\[disabled\=true\]\:opacity-50:is(:where(.group)[data-disabled=true] *){opacity:.5}.group-data-\[size\=sm\]\/card\:p-3:is(:where(.group\/card)[data-size=sm] *){padding:calc(var(--spacing) * 3)}.group-data-\[size\=sm\]\/card\:px-3:is(:where(.group\/card)[data-size=sm] *){padding-inline:calc(var(--spacing) * 3)}.group-data-\[size\=sm\]\/card\:text-sm:is(:where(.group\/card)[data-size=sm] *){font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.group-data-\[spacing\=0\]\/toggle-group\:rounded-none:is(:where(.group\/toggle-group)[data-spacing="0"] *){border-radius:0}.group-data-\[spacing\=0\]\/toggle-group\:px-2:is(:where(.group\/toggle-group)[data-spacing="0"] *){padding-inline:calc(var(--spacing) * 2)}.peer-disabled\:cursor-not-allowed:is(:where(.peer):disabled~*){cursor:not-allowed}.peer-disabled\:opacity-50:is(:where(.peer):disabled~*){opacity:.5}.file\:inline-flex::file-selector-button{display:inline-flex}.file\:h-6::file-selector-button{height:calc(var(--spacing) * 6)}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-xs::file-selector-button{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (hover:hover){.hover\:bg-destructive\/20:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-destructive\/20:hover{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.hover\:bg-muted:hover,.hover\:bg-muted\/50:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted\/50:hover{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:text-muted-foreground:hover{color:var(--muted-foreground)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:z-10:focus{z-index:10}.focus\:bg-accent:focus{background-color:var(--accent)}.focus\:text-accent-foreground:focus,:is(.focus\:\*\*\:text-accent-foreground:focus *),:is(.not-data-\[variant\=destructive\]\:focus\:\*\*\:text-accent-foreground:not([data-variant=destructive]):focus *){color:var(--accent-foreground)}.focus-visible\:z-10:focus-visible{z-index:10}.focus-visible\:border-destructive\/40:focus-visible{border-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:border-destructive\/40:focus-visible{border-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:ring-1:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-3:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}.active\:not-aria-\[haspopup\]\:translate-y-px:active:not([aria-haspopup]){--tw-translate-y:1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-input\/50:disabled{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.disabled\:bg-input\/50:disabled{background-color:color-mix(in oklab, var(--input) 50%, transparent)}}.disabled\:opacity-50:disabled{opacity:.5}.has-data-\[icon\=inline-end\]\:pr-1\.5:has([data-icon=inline-end]){padding-right:calc(var(--spacing) * 1.5)}.has-data-\[icon\=inline-end\]\:pr-2:has([data-icon=inline-end]){padding-right:calc(var(--spacing) * 2)}.group-data-\[spacing\=0\]\/toggle-group\:has-data-\[icon\=inline-end\]\:pr-1\.5:is(:where(.group\/toggle-group)[data-spacing="0"] *):has([data-icon=inline-end]){padding-right:calc(var(--spacing) * 1.5)}.has-data-\[icon\=inline-start\]\:pl-1\.5:has([data-icon=inline-start]){padding-left:calc(var(--spacing) * 1.5)}.has-data-\[icon\=inline-start\]\:pl-2:has([data-icon=inline-start]){padding-left:calc(var(--spacing) * 2)}.group-data-\[spacing\=0\]\/toggle-group\:has-data-\[icon\=inline-start\]\:pl-1\.5:is(:where(.group\/toggle-group)[data-spacing="0"] *):has([data-icon=inline-start]){padding-left:calc(var(--spacing) * 1.5)}.has-data-\[slot\=card-action\]\:grid-cols-\[1fr_auto\]:has([data-slot=card-action]){grid-template-columns:1fr auto}.has-data-\[slot\=card-description\]\:grid-rows-\[auto_auto\]:has([data-slot=card-description]){grid-template-rows:auto auto}.has-data-\[slot\=card-footer\]\:pb-0:has([data-slot=card-footer]){padding-bottom:0}.has-\[\>img\:first-child\]\:pt-0:has(>img:first-child){padding-top:0}.aria-expanded\:bg-muted[aria-expanded=true]{background-color:var(--muted)}.aria-expanded\:bg-secondary[aria-expanded=true]{background-color:var(--secondary)}.aria-expanded\:text-foreground[aria-expanded=true]{color:var(--foreground)}.aria-expanded\:text-secondary-foreground[aria-expanded=true]{color:var(--secondary-foreground)}.aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.aria-invalid\:ring-1[aria-invalid=true]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.aria-pressed\:bg-muted[aria-pressed=true]{background-color:var(--muted)}.data-closed\:animate-out[data-closed]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.data-closed\:fade-out-0[data-closed]{--tw-exit-opacity:0}.data-closed\:zoom-out-95[data-closed]{--tw-exit-scale:.95}.data-disabled\:pointer-events-none[data-disabled]{pointer-events:none}.data-disabled\:opacity-50[data-disabled]{opacity:.5}.data-inset\:pl-7[data-inset]{padding-left:calc(var(--spacing) * 7)}.data-open\:animate-in[data-open]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.data-open\:bg-accent[data-open]{background-color:var(--accent)}.data-open\:text-accent-foreground[data-open]{color:var(--accent-foreground)}.data-open\:fade-in-0[data-open]{--tw-enter-opacity:0}.data-open\:zoom-in-95[data-open]{--tw-enter-scale:.95}.data-vertical\:flex-col[data-vertical]{flex-direction:column}.data-vertical\:items-stretch[data-vertical]{align-items:stretch}.data-\[orientation\=horizontal\]\:h-px[data-orientation=horizontal]{height:1px}.data-\[orientation\=horizontal\]\:w-full[data-orientation=horizontal]{width:100%}.data-\[orientation\=vertical\]\:w-px[data-orientation=vertical]{width:1px}.data-\[orientation\=vertical\]\:self-stretch[data-orientation=vertical]{align-self:stretch}.data-\[side\=bottom\]\:slide-in-from-top-2[data-side=bottom]{--tw-enter-translate-y:calc(2*var(--spacing)*-1)}.data-\[side\=left\]\:slide-in-from-right-2[data-side=left]{--tw-enter-translate-x:calc(2*var(--spacing))}.data-\[side\=right\]\:slide-in-from-left-2[data-side=right]{--tw-enter-translate-x:calc(2*var(--spacing)*-1)}.data-\[side\=top\]\:slide-in-from-bottom-2[data-side=top]{--tw-enter-translate-y:calc(2*var(--spacing))}.data-\[size\=sm\]\:gap-2[data-size=sm]{gap:calc(var(--spacing) * 2)}.data-\[size\=sm\]\:rounded-none[data-size=sm]{border-radius:0}.data-\[size\=sm\]\:py-3[data-size=sm]{padding-block:calc(var(--spacing) * 3)}.data-\[size\=sm\]\:has-data-\[slot\=card-footer\]\:pb-0[data-size=sm]:has([data-slot=card-footer]){padding-bottom:0}.group-data-horizontal\/toggle-group\:data-\[spacing\=0\]\:first\:rounded-none:is(:where(.group\/toggle-group)[data-horizontal] *)[data-spacing="0"]:first-child,.group-data-vertical\/toggle-group\:data-\[spacing\=0\]\:first\:rounded-none:is(:where(.group\/toggle-group)[data-vertical] *)[data-spacing="0"]:first-child,.group-data-horizontal\/toggle-group\:data-\[spacing\=0\]\:last\:rounded-none:is(:where(.group\/toggle-group)[data-horizontal] *)[data-spacing="0"]:last-child,.group-data-vertical\/toggle-group\:data-\[spacing\=0\]\:last\:rounded-none:is(:where(.group\/toggle-group)[data-vertical] *)[data-spacing="0"]:last-child{border-radius:0}.data-\[state\=closed\]\:overflow-hidden[data-state=closed]{overflow:hidden}.data-\[state\=on\]\:bg-muted[data-state=on]{background-color:var(--muted)}.data-\[variant\=destructive\]\:text-destructive[data-variant=destructive]{color:var(--destructive)}.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.data-\[variant\=destructive\]\:focus\:text-destructive[data-variant=destructive]:focus{color:var(--destructive)}.group-data-horizontal\/toggle-group\:data-\[spacing\=0\]\:data-\[variant\=outline\]\:border-l-0:is(:where(.group\/toggle-group)[data-horizontal] *)[data-spacing="0"][data-variant=outline]{border-left-style:var(--tw-border-style);border-left-width:0}.group-data-vertical\/toggle-group\:data-\[spacing\=0\]\:data-\[variant\=outline\]\:border-t-0:is(:where(.group\/toggle-group)[data-vertical] *)[data-spacing="0"][data-variant=outline]{border-top-style:var(--tw-border-style);border-top-width:0}.group-data-horizontal\/toggle-group\:data-\[spacing\=0\]\:data-\[variant\=outline\]\:first\:border-l:is(:where(.group\/toggle-group)[data-horizontal] *)[data-spacing="0"][data-variant=outline]:first-child{border-left-style:var(--tw-border-style);border-left-width:1px}.group-data-vertical\/toggle-group\:data-\[spacing\=0\]\:data-\[variant\=outline\]\:first\:border-t:is(:where(.group\/toggle-group)[data-vertical] *)[data-spacing="0"][data-variant=outline]:first-child{border-top-style:var(--tw-border-style);border-top-width:1px}@media (width>=48rem){.md\:text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}}@media (width>=64rem){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}:where(.lg\:divide-x>:not(:last-child)){--tw-divide-x-reverse:0;border-inline-style:var(--tw-border-style);border-inline-start-width:calc(1px * var(--tw-divide-x-reverse));border-inline-end-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}:where(.lg\:divide-y-0>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(0px * var(--tw-divide-y-reverse));border-bottom-width:calc(0px * calc(1 - var(--tw-divide-y-reverse)))}}@media (width>=80rem){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@container (width>=24rem){.\@sm\:mb-0{margin-bottom:0}.\@sm\:grid-cols-\[max-content_1fr\]{grid-template-columns:max-content 1fr}.\@sm\:gap-x-4{column-gap:calc(var(--spacing) * 4)}.\@sm\:gap-y-1{row-gap:var(--spacing)}}.dark\:border-input:is(.dark *):not(.light *){border-color:var(--input)}.dark\:bg-destructive\/20:is(.dark *):not(.light *){background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-destructive\/20:is(.dark *):not(.light *){background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.dark\:bg-input\/30:is(.dark *):not(.light *){background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-input\/30:is(.dark *):not(.light *){background-color:color-mix(in oklab, var(--input) 30%, transparent)}}.dark\:text-amber-300:is(.dark *):not(.light *){color:var(--color-amber-300)}.dark\:text-emerald-300:is(.dark *):not(.light *){color:var(--color-emerald-300)}@media (hover:hover){.dark\:hover\:bg-destructive\/30:is(.dark *):not(.light *):hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-destructive\/30:is(.dark *):not(.light *):hover{background-color:color-mix(in oklab, var(--destructive) 30%, transparent)}}.dark\:hover\:bg-input\/50:is(.dark *):not(.light *):hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-input\/50:is(.dark *):not(.light *):hover{background-color:color-mix(in oklab, var(--input) 50%, transparent)}}.dark\:hover\:bg-muted\/50:is(.dark *):not(.light *):hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-muted\/50:is(.dark *):not(.light *):hover{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}}.dark\:focus-visible\:ring-destructive\/40:is(.dark *):not(.light *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:focus-visible\:ring-destructive\/40:is(.dark *):not(.light *):focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\:disabled\:bg-input\/80:is(.dark *):not(.light *):disabled{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:disabled\:bg-input\/80:is(.dark *):not(.light *):disabled{background-color:color-mix(in oklab, var(--input) 80%, transparent)}}.dark\:aria-invalid\:border-destructive\/50:is(.dark *):not(.light *)[aria-invalid=true]{border-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:aria-invalid\:border-destructive\/50:is(.dark *):not(.light *)[aria-invalid=true]{border-color:color-mix(in oklab, var(--destructive) 50%, transparent)}}.dark\:aria-invalid\:ring-destructive\/40:is(.dark *):not(.light *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:aria-invalid\:ring-destructive\/40:is(.dark *):not(.light *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:is(.dark *):not(.light *)[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:is(.dark *):not(.light *)[data-variant=destructive]:focus{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\:not\(\[class\*\=size-\]\)\]\:size-3 svg:not([class*=size-]){width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.\[\&_svg\:not\(\[class\*\=size-\]\)\]\:size-3\.5 svg:not([class*=size-]){width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.\[\&_svg\:not\(\[class\*\=size-\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\.border-b\]\:pb-4.border-b{padding-bottom:calc(var(--spacing) * 4)}.group-data-\[size\=sm\]\/card\:\[\.border-b\]\:pb-3:is(:where(.group\/card)[data-size=sm] *).border-b{padding-bottom:calc(var(--spacing) * 3)}@media (hover:hover){.\[a\]\:hover\:bg-destructive\/20:is(a):hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.\[a\]\:hover\:bg-destructive\/20:is(a):hover{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.\[a\]\:hover\:bg-muted:is(a):hover{background-color:var(--muted)}.\[a\]\:hover\:bg-primary\/80:is(a):hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.\[a\]\:hover\:bg-primary\/80:is(a):hover{background-color:color-mix(in oklab, var(--primary) 80%, transparent)}}.\[a\]\:hover\:bg-secondary\/80:is(a):hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.\[a\]\:hover\:bg-secondary\/80:is(a):hover{background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}.\[a\]\:hover\:text-muted-foreground:is(a):hover{color:var(--muted-foreground)}}:is(.\*\:\[img\:first-child\]\:rounded-none>*):is(img:first-child),:is(.\*\:\[img\:last-child\]\:rounded-none>*):is(img:last-child){border-radius:0}:is(.data-\[variant\=destructive\]\:\*\:\[svg\]\:text-destructive[data-variant=destructive]>*):is(svg){color:var(--destructive)}.\[\&\>svg\]\:pointer-events-none>svg{pointer-events:none}.\[\&\>svg\]\:size-3\!>svg{width:calc(var(--spacing) * 3)!important;height:calc(var(--spacing) * 3)!important}}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(data:font/woff2;base64,d09GMgABAAAAAAfsABQAAAAAEAwAAAeCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhwbHhwoP0hWQVJbBmA/U1RBVIFiJyYAdC9qEQgKhGSEAAsgADCGCAE2AiQDOgQgBYlMB4EUDAcbLQ4onoexrSC/2ZyLAa8p8VHB8/x3Vue+V0hVJalMJg2nx/TCrQXxBeqLjQG7FyM1WEa/X1tEXN7cFz9EJEMmMUz3RihWSSKeQCbcIou0izz/C8v+fq3VfajEa9gDD11CImXS7qL/RJFVzC1qiB6KmKeD6TZdQ6IRGv78dL6uSVVCfgni5mzu7kcgQBgAEAQTQRCoL++STTYybkJxNfQxAAIAGu8OdEB9teW2jh4BpgDqFjAeSEByW3zFP0CBBgNMsMCGEDjgggdhiEAUAeIIED7ABTDUEnkIE9Q9ahFgKttcVhApo4ACB4qobHaccgDfEjFO6aaWUhjMLt2SyIvHKoDqoA4CSUwEIYQCEjhAO9R1G6keDeDZGjNo+AhxOjCEGTr1WeIF3kYBiLAOKvkJSMiKX0VdAyQt3SDJClCkxJCHkCzfqyVTriJZLcolS32JZHUekq2TYNkYtCtjYHMQXSxGjXDz2t/yLWXzDzxz+o3zFwDEaN23F+13pyMdQAEaSKAR9vcGq4A4MTSKCElGW+M7UcY7xqkggITb28ZJhlqc9q2twYKTt0NjixBgYvO9BIihEBLYuOFXQzfIQ7dXGUEEEgFDooBfAzqiQbpJrhiWSuKJCRFKYbHCyJKI2G5GiZbNAvgAu5pc3vwx4G+g3aDkhklABiSz0BICXrYghtYhx/cdJ+44rY2oZ0aMNRFz3VZjb6W33F3gzltqtOCV8tTHSpOeXuItfvr5lCdfzFpqtEitvqdcdGGFd28ZqqC0tPbeChGXgrIlnhSWu/eUso4uKWFLugyDzQJhflY4659+WjQ++6x72WUMv9G8mw6QJl7BVxX5fe/kpUsOvnZwee9uQ0cGXYd0o89XB2748sDSnt8d2VphdOTTgceDVvOds0v9P/s7HPq15aGun/6Vllb56f1dl0t1LejqrNkpdRZsG8TOnM5vkBG5oiVyVGnS8LHps5cfNWJs6qKPfaNSxiQNBUm3cKNWROr0GSur7Za31k1vieq7LH11VF+jXdRIasRKflc7jkobm1Z9te1IyZA0pDkhLR98+H37Zf1c/8at+dB7x+7GfVyTfJMPiYztsnl59Y5l4j+0n1RXlpHnF3Tq7HecmNF/CJodEMAikruxiyJaGLvHOdAfoA+oDvpjBm2b91cHGRZMU9n25xEU0A8fgEEAdKI3Q1iDtc034sug5YVMkE2jsE+BIkwSoQ3gxXMqz9tELp48bd0cFKOKS7xYjEuXBnZP5ia7DyiO/X/YI+PQSbt2uSdqAkWL9nQbV1XB94/+uPfdZz8dnXYFBYrcTl2SIR/ybxJNJPz/Gupb0JaZeens2ekC7EKr8t+Ls/P5VJPYJdHKyqfg2nqU6bhlidzcddQV/7MmecTzJ5VPcKXkNKSEogHjYFx6QZ7rQ+FSe8njaiNuOnXS8H2ScQ619c2mC3VTtauL0rRbXd/CkSOP37FY9Zkjz8+GibYUMOEWF+RdrFS8Ecv1SHOpPUPZGEIpjPvFyU5cXKjd6OXqorTqy9GwRd++HVufPGnVsW+aO3vggKZ18jR9sXaTC1PWTEsVUaK0FkNySbTQDqlm2PfDjZcu4aalnSLKjnOoYQ0nUlqqXcGpPu/4VgV/xU2pAqW4BW3qzhQ8/hFKhV2qE3+BKAtDqBXjfgnVdH4y0wg5tbVNRenNdTWOrenWLcupQdmsbq5b+18piTe/xRdp1xbILxNPJGInm2z6hoB21Lal0i+ePTtd7B45+3XhFJ329evskXm7qurUVREotqSluSo/L29d3qDhI4YOQqWhI4YNvBNfsMHeXKemXrxQfKeuPOGRVayA3JtkJKEgbPp+dXUDluddutRYLFoXGXWX6N3WFaGLbQtRSitVYNacTNSdy7AaG/HSaUEANcBoGXNdcZvZsOqQ1icBDv21/gzAoYPHH/WDW0qNR3QTYKEAEHig6o13NXbND06CQPlRtYjGNnSktRc09k1mAMDvAlDKfQjgy6fssInlfzmNAjKkDxoxHOBLdVRAIVt9j4qo+hA1w9T1aNBNTUOTTNUHLbqokE+UAfJXCIGw/IxCSL5GRUJeR40rL/UxTm4Q08H6MbCs70ObuNyIIXrINHQYInF06UUlevTjbQzTh5upiDMzMMogUtEnjPs/Y7jAHCJeB0GBHh04tC6FiB6ZFB1oArUSIoFoqhzCeAN6lHwm0T4C3VVPWvjpSMXReuWesMEcoqrmgtNBGd2noWeV0hNAz9rFeShNJxHGsPa3HXeKTk8b55hahySYHaYKKFFLpCfN8rsoaJn01CR04Gkc+5k7KVTCmClX8Q10HCrUEkVlSX+XO33oQR9609tJ516H497WSobWs5Up6TLaS10/dessIskgJSLiDlWvHVUywpkQ7hdPZqGyiEF0uVQerVcPamT1A3eKXdyI1vG9OoflrSXihZ1qqGE3nhmAgiIbRCQgPLEPtOM3UQwTLYaYYomNlpA44opnjV6jkD6id80OOrzf6BzmMD6eEa1zKyeYG1fzfEf16V6jw9XYOaar1/b2kP/IYX8oR2mcFvv2GtBV3JXgd437AQAA)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root,.light{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--radius:.625rem;--background:oklch(100% 0 0);--foreground:oklch(14.5% 0 0);--card:oklch(100% 0 0);--card-foreground:oklch(14.5% 0 0);--popover:oklch(100% 0 0);--popover-foreground:oklch(14.5% 0 0);--primary:oklch(20.5% 0 0);--primary-foreground:oklch(98.5% 0 0);--secondary:oklch(97% 0 0);--secondary-foreground:oklch(20.5% 0 0);--muted:oklch(97% 0 0);--muted-foreground:oklch(55.6% 0 0);--accent:oklch(97% 0 0);--accent-foreground:oklch(20.5% 0 0);--destructive:oklch(57.7% .245 27.325);--border:oklch(92.2% 0 0);--input:oklch(92.2% 0 0);--ring:oklch(70.8% 0 0);--chart-1:oklch(64.6% .222 41.116);--chart-2:oklch(60% .118 184.704);--chart-3:oklch(39.8% .07 227.392);--chart-4:oklch(82.8% .189 84.429);--chart-5:oklch(76.9% .188 70.08);--sidebar:oklch(98.5% 0 0);--sidebar-foreground:oklch(14.5% 0 0);--sidebar-primary:oklch(20.5% 0 0);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(97% 0 0);--sidebar-accent-foreground:oklch(20.5% 0 0);--sidebar-border:oklch(92.2% 0 0);--sidebar-ring:oklch(70.8% 0 0)}.dark{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;--background:oklch(14.5% 0 0);--foreground:oklch(98.5% 0 0);--card:oklch(20.5% 0 0);--card-foreground:oklch(98.5% 0 0);--popover:oklch(20.5% 0 0);--popover-foreground:oklch(98.5% 0 0);--primary:oklch(92.2% 0 0);--primary-foreground:oklch(20.5% 0 0);--secondary:oklch(26.9% 0 0);--secondary-foreground:oklch(98.5% 0 0);--muted:oklch(26.9% 0 0);--muted-foreground:oklch(70.8% 0 0);--accent:oklch(26.9% 0 0);--accent-foreground:oklch(98.5% 0 0);--destructive:oklch(70.4% .191 22.216);--border:oklch(100% 0 0/.1);--input:oklch(100% 0 0/.15);--ring:oklch(55.6% 0 0);--chart-1:oklch(48.8% .243 264.376);--chart-2:oklch(69.6% .17 162.48);--chart-3:oklch(76.9% .188 70.08);--chart-4:oklch(62.7% .265 303.9);--chart-5:oklch(64.5% .246 16.439);--sidebar:oklch(20.5% 0 0);--sidebar-foreground:oklch(98.5% 0 0);--sidebar-primary:oklch(48.8% .243 264.376);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(26.9% 0 0);--sidebar-accent-foreground:oklch(98.5% 0 0);--sidebar-border:oklch(100% 0 0/.1);--sidebar-ring:oklch(55.6% 0 0)}@property --tw-divide-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-duration{syntax:"*";inherits:false}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@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));filter:blur(var(--tw-enter-blur,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));filter:blur(var(--tw-exit-blur,0))}}