@exellix/jobs-ui 1.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,64 +1,69 @@
1
1
  # @exellix/jobs-ui
2
2
 
3
- Read-only **query + HTTP** layer over the Exellix job queue. Lists, groups, and counts **job runs** from [`@exellix/exellix-db`](../exellix-db/README.md). No execution rights no `enqueue` / `claim` / `complete` / `fail`.
3
+ **Jobs dashboard** React operator SPA for the Exellix job queue. Queue overview, run detail, record-centric views, Source→Records workflow, and work-factory wizards (continuous work, batches, on-demand).
4
4
 
5
- > A **JobRun** is one graph run on one input. See [`temp/jobs/`](../temp/jobs/README.md) for the design. This package replaces the old `@exellix/exellix-matrix-read`.
5
+ | Package | Role |
6
+ |---------|------|
7
+ | [`@exellix/jobs`](../jobs/README.md) | Jobs **manager** — queue runtime, worker loop, CLI |
8
+ | [`@exellix/jobs-api`](../jobs-api/README.md) | Jobs **HTTP API** — REST server this UI talks to |
9
+ | **`@exellix/jobs-ui`** (this) | Jobs **dashboard** — React SPA only |
10
+ | [`@exellix/jobs-db`](../jobs-db/README.md) | Jobs **data tier** — Mongo persistence |
11
+
12
+ > A **JobRun** is one graph run on one input. See [`temp/jobs/`](../temp/jobs/README.md) for the design.
6
13
 
7
14
  ## Install
8
15
 
9
16
  ```bash
10
- npm install @exellix/jobs-ui @exellix/exellix-db
17
+ npm install @exellix/jobs-ui
11
18
  ```
12
19
 
13
- ## Queries
20
+ The dashboard requires a running `@exellix/jobs-api` instance (or any host serving the same `/api/*` contract).
14
21
 
15
- ```ts
16
- import { createJobRunStore } from '@exellix/exellix-db';
17
- import { listRuns, getRun, groupByItem, countByStatus, countRuns } from '@exellix/jobs-ui';
22
+ ## Quick start
18
23
 
19
- const { store } = await createJobRunStore({ mongoUri: process.env.MONGO_URI });
24
+ ```bash
25
+ # terminal 1 — API backend (needs MONGO_URI)
26
+ cd ../jobs-api && npm run serve
20
27
 
21
- await listRuns(store, { jobDefId, status: 'pending', page: 1, pageSize: 50 });
22
- await getRun(store, jobRunId);
23
- await groupByItem(store, itemId); // all runs for one source item
24
- await countByStatus(store, jobDefId); // { blocked, pending, running, done, failed }
25
- await countRuns(store, { graphId, status });
28
+ # terminal 2 UI with HMR
29
+ npm run dev # Vite on :5190, proxies /api → http://localhost:3099
26
30
  ```
27
31
 
28
- ## HTTP server
32
+ Set `VITE_API_PROXY` to point at a remote API during dev. Set `VITE_DEV_PORT` to change the dev server port.
29
33
 
30
- ```bash
31
- # MONGO_URI must be set (or available in ../graph-engine/.env via the workspace)
32
- npm run ui:serve # → jobs-ui listening on http://0.0.0.0:3099
33
- # or, after install:
34
- npx exellix-jobs-ui serve
35
- ```
34
+ ### Combined deploy (single port)
36
35
 
37
- Set `PORT` to override the default `3099`.
38
-
39
- | Route | Returns |
40
- |-------|---------|
41
- | `GET /health` | liveness |
42
- | `GET /runs` | paged list (query: `jobDefId`, `status`, `itemId`, `graphId`, `page`, `pageSize`) |
43
- | `GET /runs/:id` | a single job run (404 if missing) |
44
- | `GET /items/:itemId/runs` | all job runs for one source item |
45
- | `GET /stats/by-status` | counts by status (optional `?jobDefId=`) |
36
+ Build the UI, then let the API serve it:
46
37
 
47
38
  ```bash
48
- curl http://localhost:3099/health
49
- curl "http://localhost:3099/runs?status=pending&pageSize=20"
50
- curl http://localhost:3099/stats/by-status
39
+ npm run build
40
+ cd ../jobs-api && JOBS_UI_STATIC_DIR=../jobs-ui/dist npm run serve
51
41
  ```
52
42
 
53
- There is no bundled HTML dashboard; this package is the read API a frontend builds on.
43
+ ## Browser routes
44
+
45
+ | Route | Page |
46
+ |-------|------|
47
+ | `/` | Queue Overview |
48
+ | `/runs` | Runs list |
49
+ | `/runs/:id` | Run detail |
50
+ | `/sources` | Source picker |
51
+ | `/records` | Records list |
52
+ | `/records/:recordId` | Record detail |
53
+ | `/items/:itemId` | Item timeline + DAG |
54
+ | `/jobs/new` | Create / enqueue job |
55
+ | `/job-defs` | Job definition list |
56
+ | `/job-defs/:id` | Job definition detail |
57
+ | `/settings` | App-wide queue execution settings |
58
+
59
+ Work-factory routes: `/work`, `/work/:id`, `/batches/:id`, on-demand flows — see [`jobs-api` HTTP docs](../jobs-api/README.md).
54
60
 
55
61
  ## Scripts
56
62
 
57
63
  ```bash
58
- npm run build # tsc → dist/
59
- npm test # unit + live (live runs only when MONGO_URI is set)
60
- npm run test:live # live Mongo integration tests only
61
- npm run ui:serve # start the HTTP server
64
+ npm run build # vite build → dist/
65
+ npm run dev # Vite dev server + API proxy
66
+ npm test # build smoke test + graph-picker unit tests
62
67
  ```
63
68
 
64
69
  ## License
@@ -0,0 +1 @@
1
+ .memorix-agents-scope{display:flex;align-items:center;gap:6px;padding:3px 6px 3px 8px;border-radius:7px;border:1px solid var(--memorix-agents-border, #252a3d);background:var(--memorix-agents-surface-raised, #1c2030)}.memorix-agents-scope-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--memorix-agents-text-muted, #8892a4)}.memorix-agents-scope-select{border:none;background:transparent;color:var(--memorix-agents-text, #e2e8f0);font-family:var(--memorix-agents-mono, monospace);font-size:12px;padding:2px 18px 2px 4px;max-width:220px;cursor:pointer;outline:none;-moz-appearance:auto;appearance:auto;-webkit-appearance:menulist}.memorix-agents-scope-control{position:relative;display:flex;align-items:center}.memorix-agents-scope-chevron{position:absolute;right:2px;pointer-events:none;font-size:10px;color:var(--memorix-agents-text-muted, #8892a4);line-height:1}.memorix-agents-scope-clear{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;padding:0;border:none;border-radius:99px;background:transparent;color:var(--memorix-agents-text-muted, #8892a4);font-size:14px;line-height:1;cursor:pointer}.memorix-agents-scope-clear:hover{color:var(--memorix-agents-text, #e2e8f0);background:#ffffff0f}.memorix-agents-scope-select.scoped{color:var(--memorix-agents-accent, #7b93ff);font-weight:600}.memorix-agents-scope.scoped{border-color:var(--memorix-agents-accent-border, rgba(123, 147, 255, .35));background:var(--memorix-agents-accent-subtle, rgba(123, 147, 255, .08))}.memorix-agents-manager,.memorix-agents-bindings{color:var(--memorix-agents-text, #e2e8f0);font-size:14px}.memorix-agents-form-card{background:linear-gradient(180deg,rgba(123,147,255,.1) 0%,rgba(123,147,255,.03) 42%,var(--memorix-agents-surface-raised, #1c2030) 100%);border:1px solid var(--memorix-agents-accent-border, rgba(123, 147, 255, .45));border-left:4px solid var(--memorix-agents-accent, #7b93ff);border-radius:14px;padding:24px;margin-bottom:16px;box-shadow:0 8px 32px #00000059,inset 0 1px #ffffff0a}.memorix-agents-form-header{margin-bottom:20px;padding-bottom:16px;border-bottom:1px solid rgba(123,147,255,.18)}.memorix-agents-form-title{font-size:20px;font-weight:700;letter-spacing:-.02em;color:var(--memorix-agents-text, #f1f5f9);margin:0 0 6px;text-transform:none}.memorix-agents-form-subtitle{margin:0;font-size:13px;line-height:1.55;color:var(--memorix-agents-text-muted, #a8b4c8);max-width:62ch}.memorix-agents-section-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px}.memorix-agents-section-header .memorix-agents-section-title{margin:0}.memorix-agents-link-btn{border:none;padding:0;background:none;color:var(--memorix-agents-accent, #7b93ff);font:inherit;cursor:pointer;text-decoration:underline;text-underline-offset:2px}.memorix-agents-link-btn:hover{color:var(--memorix-agents-text, #e2e8f0)}.memorix-agents-section-title{font-size:15px;font-weight:700;color:var(--memorix-agents-text, #e2e8f0);margin:0 0 12px;letter-spacing:-.01em}.memorix-agents-form-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px 20px;margin-bottom:18px}.memorix-agents-form-full{grid-column:1 / -1}.memorix-agents-field{display:flex;flex-direction:column;gap:8px}.memorix-agents-field-label{font-size:13px;font-weight:700;color:var(--memorix-agents-text, #f1f5f9);letter-spacing:.01em}.memorix-agents-field-label-required:after{content:" *";color:#fca5a5;font-weight:700}.memorix-agents-field-hint{font-size:12px;color:var(--memorix-agents-text-muted, #94a3b8);line-height:1.45}.memorix-agents-input,.memorix-agents-textarea{background:#252b3d;border:1px solid #4a5575;border-radius:8px;color:var(--memorix-agents-text, #f8fafc);padding:11px 12px;font-size:14px;font-family:inherit;outline:none;width:100%;box-shadow:inset 0 1px 2px #00000040;transition:border-color .15s ease,box-shadow .15s ease,background .15s ease}.memorix-agents-input::placeholder,.memorix-agents-textarea::placeholder{color:#7c879c;opacity:1}.memorix-agents-input:hover:not(:disabled),.memorix-agents-textarea:hover:not(:disabled){border-color:#667089;background:#2a3147}.memorix-agents-input.mono{font-family:var(--memorix-agents-mono, monospace);font-size:12px}.memorix-agents-textarea{resize:vertical;min-height:72px;line-height:1.45}.memorix-agents-input:focus,.memorix-agents-textarea:focus{border-color:var(--memorix-agents-accent, #96aaff);background:#2d3550;box-shadow:0 0 0 3px #7b93ff59,inset 0 1px 2px #0003}.memorix-agents-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.memorix-agents-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;border-radius:7px;border:1px solid var(--memorix-agents-border, #252a3d);background:var(--memorix-agents-surface-raised, #1c2030);color:var(--memorix-agents-text, #e2e8f0);font-size:13px;font-family:inherit;cursor:pointer}.memorix-agents-btn:hover:not(:disabled){border-color:var(--memorix-agents-accent, #7b93ff)}.memorix-agents-btn:disabled{opacity:.45;cursor:not-allowed}.memorix-agents-btn-primary{background:var(--memorix-agents-accent, #7b93ff);border-color:var(--memorix-agents-accent, #7b93ff);color:#fff;font-weight:600}.memorix-agents-btn-primary:hover:not(:disabled){background:#96aaff;border-color:#96aaff}.memorix-agents-btn-create{padding:10px 22px;font-size:14px;min-width:140px;justify-content:center;box-shadow:0 4px 14px #7b93ff59}.memorix-agents-btn-sm{padding:3px 10px;font-size:12px}.memorix-agents-btn-danger{border-color:#f87171;color:#f87171}.memorix-agents-btn.active{border-color:var(--memorix-agents-accent, #7b93ff);color:var(--memorix-agents-accent, #7b93ff);background:var(--memorix-agents-accent-subtle, rgba(123, 147, 255, .08))}.memorix-agents-table-wrap{overflow-x:auto;background:var(--memorix-agents-surface, #13161f);border:1px solid var(--memorix-agents-border, #252a3d);border-radius:12px}.memorix-agents-table{width:100%;border-collapse:collapse;font-size:13px}.memorix-agents-table th{padding:11px 14px;text-align:left;border-bottom:1px solid var(--memorix-agents-border, #252a3d);background:var(--memorix-agents-surface-raised, #1c2030);color:var(--memorix-agents-text-muted, #8892a4);font-weight:700;font-size:11px;text-transform:uppercase;letter-spacing:.07em}.memorix-agents-table td{padding:12px 14px;border-bottom:1px solid var(--memorix-agents-border, #252a3d);vertical-align:top}.memorix-agents-table tbody tr:last-child td{border-bottom:none}.memorix-agents-name{font-weight:600}.memorix-agents-id{font-family:var(--memorix-agents-mono, monospace);font-size:11px;color:var(--memorix-agents-text-dim, #5a6478);margin-top:2px}.memorix-agents-desc{font-size:12px;color:var(--memorix-agents-text-muted, #8892a4);line-height:1.45;max-width:360px}.memorix-agents-desc-empty{color:var(--memorix-agents-text-dim, #5a6478);font-size:12px}.memorix-agents-row-actions{display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap}.memorix-agents-notice{background:var(--memorix-agents-accent-subtle, rgba(123, 147, 255, .08));border:1px solid var(--memorix-agents-accent-border, rgba(123, 147, 255, .35));border-radius:12px;padding:14px 16px;margin-bottom:16px;font-size:13px}.memorix-agents-notice-warn{background:#6c83f514;border-color:#6c83f54d}.memorix-agents-empty,.memorix-agents-loading{padding:40px 24px;text-align:center;color:var(--memorix-agents-text-muted, #8892a4);font-size:13px}.memorix-agents-error{font-size:12px;color:#f87171}.memorix-agents-chip-row{display:flex;flex-wrap:wrap;gap:6px}.memorix-agents-chip{display:inline-flex;align-items:center;padding:2px 9px;border-radius:99px;font-size:11px;font-weight:500;background:var(--memorix-agents-surface-raised, #1c2030);border:1px solid var(--memorix-agents-border, #252a3d);color:var(--memorix-agents-text-muted, #8892a4)}.memorix-agents-chip.selected{background:var(--memorix-agents-accent, #7b93ff);border-color:var(--memorix-agents-accent, #7b93ff);color:#fff}.memorix-agents-badge{display:inline-block;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:600;background:var(--memorix-agents-surface-raised, #1c2030);color:var(--memorix-agents-text-muted, #8892a4)}.memorix-agents-badge-entity{background:#60a5fa1f;color:#60a5fa}.memorix-agents-badge-event{background:#f59e0b1f;color:#f59e0b}.memorix-agents-badge-knowledge{background:#a78bfa1f;color:#a78bfa}.memorix-agents-multiselect{position:relative;min-width:200px;max-width:320px}.memorix-agents-multiselect-trigger{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;padding:7px 10px;border-radius:7px;border:1px solid var(--memorix-agents-border, #252a3d);background:var(--memorix-agents-bg, #0b0d14);color:var(--memorix-agents-text, #e2e8f0);font-size:13px;font-family:inherit;cursor:pointer;text-align:left}.memorix-agents-multiselect-trigger.any{color:var(--memorix-agents-text-muted, #8892a4)}.memorix-agents-multiselect-trigger:hover:not(:disabled){border-color:var(--memorix-agents-accent, #7b93ff)}.memorix-agents-multiselect-trigger:disabled{opacity:.55;cursor:not-allowed}.memorix-agents-multiselect.open .memorix-agents-multiselect-trigger{border-color:var(--memorix-agents-accent, #7b93ff);box-shadow:0 0 0 2px #7b93ff59}.memorix-agents-multiselect-trigger-text{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.memorix-agents-multiselect-chevron{font-size:10px;color:var(--memorix-agents-text-dim, #5a6478);flex-shrink:0}.memorix-agents-multiselect-menu{position:absolute;z-index:50;top:calc(100% + 4px);left:0;right:0;min-width:240px;max-height:280px;overflow-y:auto;background:var(--memorix-agents-surface, #13161f);border:1px solid var(--memorix-agents-border, #252a3d);border-radius:8px;box-shadow:0 8px 24px #00000073;padding:4px}.memorix-agents-multiselect-option{display:flex;align-items:flex-start;gap:8px;width:100%;padding:8px 10px;border:none;border-radius:6px;background:transparent;color:var(--memorix-agents-text, #e2e8f0);font-size:13px;font-family:inherit;text-align:left;cursor:pointer}.memorix-agents-multiselect-option:hover{background:var(--memorix-agents-surface-raised, #1c2030)}.memorix-agents-multiselect-option.selected{background:var(--memorix-agents-accent-subtle, rgba(123, 147, 255, .08))}.memorix-agents-multiselect-option.highlighted strong{color:var(--memorix-agents-accent, #7b93ff)}.memorix-agents-multiselect-option.any{border-bottom:1px solid var(--memorix-agents-border, #252a3d);margin-bottom:2px}.memorix-agents-multiselect-check{width:14px;flex-shrink:0;color:var(--memorix-agents-accent, #7b93ff);font-size:12px;line-height:1.4}.memorix-agents-multiselect-option-hint{display:block;font-size:11px;color:var(--memorix-agents-text-dim, #5a6478);margin-top:1px}.memorix-agents-multiselect-option-hint.mono{font-family:var(--memorix-agents-mono, monospace)}.memorix-agents-multiselect-empty{padding:12px 10px;font-size:12px;color:var(--memorix-agents-text-muted, #8892a4)}@media(max-width:720px){.memorix-agents-form-grid{grid-template-columns:1fr}}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}:root{--color-bg: #0b0d14;--color-surface: #13161f;--color-surface-raised: #1c2030;--color-surface-hover: #222640;--color-border: #252a3d;--color-border-subtle: #1e2235;--color-text: #e2e8f0;--color-text-muted: #8892a4;--color-text-dim: #5a6478;--color-accent: #7b93ff;--color-accent-hover: #96aaff;--color-accent-subtle: rgba(123, 147, 255, .08);--color-accent-border: rgba(123, 147, 255, .35);--status-blocked: #f59e0b;--status-blocked-bg: rgba(245, 158, 11, .1);--status-pending: #60a5fa;--status-pending-bg: rgba(96, 165, 250, .1);--status-running: #34d399;--status-running-bg: rgba(52, 211, 153, .1);--status-done: #4ade80;--status-done-bg: rgba(74, 222, 128, .08);--status-failed: #f87171;--status-failed-bg: rgba(248, 113, 113, .1);--status-cancelled: #a78bfa;--status-cancelled-bg: rgba(167, 139, 250, .1);--radius: 7px;--radius-lg: 12px;--radius-xl: 16px;--font-mono: "Cascadia Code", "Fira Code", "Consolas", monospace;--shadow-card: 0 1px 4px rgba(0, 0, 0, .4), 0 0 0 0 transparent;--shadow-focus: 0 0 0 2px rgba(123, 147, 255, .4);--transition: .15s ease}html,body{background:var(--color-bg);color:var(--color-text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,sans-serif;font-size:14px;line-height:1.5;min-height:100vh}a{color:var(--color-accent);text-decoration:none}a:hover{color:var(--color-accent-hover);text-decoration:underline}.layout{display:flex;flex-direction:column;min-height:100vh}.topbar{display:flex;align-items:center;gap:24px;padding:0 24px;height:56px;background:var(--color-surface);border-bottom:1px solid var(--color-border);box-shadow:0 1px 0 var(--color-border-subtle);position:sticky;top:0;z-index:100}.topbar-brand{display:flex;align-items:center;gap:9px;font-weight:700;font-size:14px;color:var(--color-text);letter-spacing:-.2px;white-space:nowrap}.topbar-brand-icon{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:7px;background:var(--color-accent-subtle);border:1px solid var(--color-accent-border);color:var(--color-accent);font-size:14px;line-height:1;flex-shrink:0}.topbar-brand span{color:var(--color-accent)}.topbar-nav{display:flex;gap:2px;flex:1;height:100%;align-items:center}.topbar-nav a{display:flex;align-items:center;height:56px;padding:0 14px;color:var(--color-text-muted);font-size:13px;font-weight:500;border-bottom:2px solid transparent;transition:color var(--transition),border-color var(--transition);white-space:nowrap}.topbar-nav a:hover{color:var(--color-text);text-decoration:none;border-bottom-color:var(--color-border)}.topbar-nav a.active{color:var(--color-text);border-bottom-color:var(--color-accent)}.topbar-meta{font-size:11px;color:var(--color-text-dim);white-space:nowrap}.app-pkg-version{font-size:9px;font-weight:500;color:var(--color-text-dim);letter-spacing:.03em;margin-left:6px;align-self:center;opacity:.7}.page{padding:28px 24px;max-width:1400px;width:100%;margin:0 auto}.page-header{margin-bottom:24px;display:flex;align-items:flex-start;gap:12px}.page-title{font-size:20px;font-weight:700;letter-spacing:-.3px}.page-subtitle{color:var(--color-text-muted);font-size:13px;margin-top:2px}.card{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:20px;box-shadow:var(--shadow-card)}.card-title{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--color-text-muted);margin-bottom:14px}.live-console{background:#07090f;border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;margin-bottom:16px}.live-console-head{display:flex;align-items:center;justify-content:space-between;padding:8px 14px;background:var(--color-surface);border-bottom:1px solid var(--color-border)}.live-console-title{display:inline-flex;align-items:center;gap:8px;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--color-text-muted)}.live-console-meta{font-size:11px;color:var(--color-text-dim)}.live-dot{width:8px;height:8px;border-radius:50%;background:var(--color-text-dim)}.live-dot.live{background:var(--status-running);box-shadow:0 0 #34d39999;animation:live-pulse 1.4s ease-out infinite}@keyframes live-pulse{0%{box-shadow:0 0 #34d39980}70%{box-shadow:0 0 0 6px #34d39900}to{box-shadow:0 0 #34d39900}}.live-console-body{max-height:420px;overflow-y:auto;padding:10px 14px;font-family:var(--font-mono);font-size:12px;line-height:1.7}.live-console-entry{margin-bottom:2px}.live-console-line{display:flex;gap:10px;align-items:baseline;white-space:pre-wrap;word-break:break-word;border-radius:var(--radius);padding:1px 4px;margin:0 -4px}.live-console-line.expandable{cursor:pointer;-webkit-user-select:none;user-select:none}.live-console-line.expandable:hover{background:#ffffff0a}.live-console-chevron{flex-shrink:0;width:10px;font-size:9px;color:var(--color-text-dim);transition:transform var(--transition)}.live-console-chevron.open{transform:rotate(90deg)}.live-console-expand{padding:4px 0 10px 20px}.live-console-expand .json-section{margin-bottom:6px}.live-console-expand .json-section-header{font-size:11px;padding:6px 10px}.live-console-expand .json-body{max-height:240px;overflow:auto}.live-console-expand .json-body pre{font-size:11px}.live-console-line.muted{color:var(--color-text-dim)}.live-console-time{color:var(--color-text-dim);flex-shrink:0}.live-console-detail{color:var(--color-text-muted)}.live-console-foot{padding:7px 14px;font-size:11px;color:var(--color-text-muted);background:var(--color-surface);border-top:1px solid var(--color-border)}.run-io-panel .json-section{margin-bottom:8px}.run-io-hint{margin:0 0 12px;font-size:12px;color:var(--color-text-muted)}.run-io-pending{padding:10px 12px;margin-bottom:8px;font-size:12px;color:var(--color-text-muted);background:var(--color-bg);border:1px dashed var(--color-border);border-radius:var(--radius)}.status-cards{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:24px}@media(max-width:900px){.status-cards{grid-template-columns:repeat(3,1fr)}}.status-card{background:var(--color-surface);border:1px solid var(--color-border);border-left:3px solid var(--color-border);border-radius:var(--radius-lg);padding:16px 18px;cursor:pointer;transition:border-color var(--transition),background var(--transition);box-shadow:var(--shadow-card)}.status-card:hover,.status-card.active{background:var(--color-surface-raised)}.status-card-label{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;margin-bottom:8px}.status-card-count{font-size:30px;font-weight:800;line-height:1;font-variant-numeric:tabular-nums}.badge{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:99px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;white-space:nowrap}.badge:before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex-shrink:0}.badge-blocked{color:var(--status-blocked);background:var(--status-blocked-bg)}.badge-pending{color:var(--status-pending);background:var(--status-pending-bg)}.badge-running{color:var(--status-running);background:var(--status-running-bg);animation:pulse-running 2s ease-in-out infinite}.badge-done{color:var(--status-done);background:var(--status-done-bg)}.badge-failed{color:var(--status-failed);background:var(--status-failed-bg)}.badge-cancelled{color:var(--status-cancelled);background:var(--status-cancelled-bg)}@keyframes pulse-running{0%,to{opacity:1}50%{opacity:.65}}.mock-chip{display:inline-flex;align-items:center;padding:2px 8px;border-radius:99px;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;background:#f59e0b1f;border:1px solid rgba(245,158,11,.3);color:#f59e0b;margin-right:8px}.table-wrap{overflow-x:auto;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);box-shadow:var(--shadow-card)}table{width:100%;border-collapse:collapse;font-size:13px}thead th{text-align:left;padding:11px 14px;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--color-text-muted);border-bottom:1px solid var(--color-border);background:var(--color-surface-raised);white-space:nowrap}tbody tr{border-bottom:1px solid var(--color-border);transition:background var(--transition);cursor:pointer}tbody tr:last-child{border-bottom:none}tbody tr:hover{background:var(--color-surface-hover)}tbody td{padding:10px 14px;color:var(--color-text);white-space:nowrap;max-width:200px;overflow:hidden;text-overflow:ellipsis}.td-mono{font-family:var(--font-mono);font-size:12px;color:var(--color-text-muted)}.filters{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:16px;padding:14px 16px;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);box-shadow:var(--shadow-card)}.filter-group{display:flex;align-items:center;gap:8px}.filter-divider{width:1px;height:28px;background:var(--color-border);margin:0 4px}select:not(.memorix-agents-scope-select),input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=range]):not([type=submit]):not([type=button]){background:var(--color-surface-raised);border:1px solid var(--color-border);border-radius:var(--radius);color:var(--color-text);padding:6px 10px;font-size:13px;font-family:inherit;outline:none;transition:border-color var(--transition),box-shadow var(--transition)}select:not(.memorix-agents-scope-select):focus,input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=range]):not([type=submit]):not([type=button]):focus{border-color:var(--color-accent);box-shadow:var(--shadow-focus)}select option{background:var(--color-surface-raised)}select:disabled,input:disabled{opacity:.45;cursor:not-allowed}label{font-size:12px;color:var(--color-text-muted)}textarea{background:var(--color-surface-raised);border:1px solid var(--color-border);border-radius:var(--radius);color:var(--color-text);padding:8px 10px;font-size:13px;font-family:inherit;outline:none;resize:vertical;transition:border-color var(--transition),box-shadow var(--transition);width:100%}textarea:focus{border-color:var(--color-accent);box-shadow:var(--shadow-focus)}button,.btn{display:inline-flex;align-items:center;gap:6px;background:var(--color-surface-raised);border:1px solid var(--color-border);border-radius:var(--radius);color:var(--color-text);padding:6px 14px;font-size:13px;font-family:inherit;cursor:pointer;transition:border-color var(--transition),background var(--transition),box-shadow var(--transition);white-space:nowrap}button:hover,.btn:hover{border-color:var(--color-accent);background:var(--color-surface-hover)}button:focus-visible,.btn:focus-visible{outline:none;box-shadow:var(--shadow-focus)}button:disabled,.btn:disabled{opacity:.45;cursor:not-allowed}button:disabled:hover,.btn:disabled:hover{border-color:var(--color-border);background:var(--color-surface-raised)}button.primary,.btn-primary{background:var(--color-accent);border-color:var(--color-accent);color:#fff;font-weight:600}button.primary:hover,.btn-primary:hover{background:var(--color-accent-hover);border-color:var(--color-accent-hover)}.btn-danger{border-color:var(--status-failed);color:var(--status-failed)}.btn-danger:hover{background:var(--status-failed-bg);border-color:var(--status-failed)}.btn-ghost{background:transparent;border-color:transparent;color:var(--color-text-muted)}.btn-ghost:hover{background:var(--color-surface-raised);border-color:var(--color-border);color:var(--color-text)}button.active,.btn.active{border-color:var(--color-accent);color:var(--color-accent);background:var(--color-accent-subtle)}.btn-sm{padding:3px 10px;font-size:12px}.btn-xs{padding:2px 8px;font-size:11px}.pagination{display:flex;align-items:center;gap:8px;justify-content:flex-end;padding:12px 16px;font-size:13px;color:var(--color-text-muted);border-top:1px solid var(--color-border)}.refresh-control{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--color-text-muted);margin-left:auto}.refresh-dot{width:7px;height:7px;border-radius:50%;background:var(--status-running);display:inline-block}.refresh-dot.paused{background:var(--color-text-dim)}.json-section{margin-bottom:16px}.json-section-header{display:flex;align-items:center;gap:8px;cursor:pointer;padding:8px 12px;background:var(--color-surface-raised);border:1px solid var(--color-border);border-radius:var(--radius);font-size:12px;font-weight:600;color:var(--color-text-muted);-webkit-user-select:none;user-select:none;transition:border-color var(--transition)}.json-section-header:hover{border-color:var(--color-accent);color:var(--color-text)}.json-section-header.open{border-bottom-left-radius:0;border-bottom-right-radius:0}.json-chevron{font-size:10px;transition:transform var(--transition);color:var(--color-text-dim)}.json-chevron.open{transform:rotate(90deg)}.json-body{background:var(--color-bg);border:1px solid var(--color-border);border-top:none;border-bottom-left-radius:var(--radius);border-bottom-right-radius:var(--radius);padding:14px 16px;overflow-x:auto}.json-body pre{font-family:var(--font-mono);font-size:12px;line-height:1.6;color:var(--color-text);white-space:pre}.detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}@media(max-width:800px){.detail-grid{grid-template-columns:1fr}}.detail-row{display:flex;gap:8px;padding:7px 0;border-bottom:1px solid var(--color-border-subtle);font-size:13px;align-items:baseline}.detail-row:last-child{border-bottom:none}.detail-key{color:var(--color-text-muted);min-width:130px;font-size:12px;flex-shrink:0}.detail-val{color:var(--color-text);word-break:break-all;font-family:var(--font-mono);font-size:12px}.overview-cols{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-bottom:24px}@media(max-width:1000px){.overview-cols{grid-template-columns:1fr 1fr}}@media(max-width:640px){.overview-cols{grid-template-columns:1fr}}.timeline{position:relative;padding-left:28px}.timeline:before{content:"";position:absolute;left:9px;top:8px;bottom:8px;width:2px;background:var(--color-border)}.timeline-item{position:relative;margin-bottom:12px}.timeline-dot{position:absolute;left:-23px;top:14px;width:10px;height:10px;border-radius:50%;border:2px solid var(--color-bg)}.timeline-dot-blocked{background:var(--status-blocked)}.timeline-dot-pending{background:var(--status-pending)}.timeline-dot-running{background:var(--status-running)}.timeline-dot-done{background:var(--status-done)}.timeline-dot-failed{background:var(--status-failed)}.timeline-dot-cancelled{background:var(--status-cancelled)}.mono{font-family:var(--font-mono);font-size:12px}.text-muted{color:var(--color-text-muted)}.text-dim{color:var(--color-text-dim)}.empty-state{padding:52px 24px;text-align:center;color:var(--color-text-muted)}.error-state{padding:16px;color:var(--status-failed);background:var(--status-failed-bg);border:1px solid rgba(248,113,113,.3);border-radius:var(--radius);font-size:13px}.spinner{display:inline-block;width:16px;height:16px;border:2px solid var(--color-border);border-top-color:var(--color-accent);border-radius:50%;animation:spin .7s linear infinite;flex-shrink:0}@keyframes spin{to{transform:rotate(360deg)}}.loading-row{display:flex;align-items:center;gap:10px;padding:40px 24px;color:var(--color-text-muted);font-size:13px}.breadcrumb{font-size:13px;color:var(--color-text-muted);margin-bottom:18px;display:flex;align-items:center;gap:6px}.breadcrumb a{color:var(--color-text-muted)}.breadcrumb a:hover{color:var(--color-text);text-decoration:none}.breadcrumb-sep{color:var(--color-text-dim)}.memorix-panel{background:var(--color-accent-subtle);border:1px solid var(--color-accent-border);border-radius:var(--radius);padding:14px 16px;margin-bottom:16px}.memorix-panel-title{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--color-accent);margin-bottom:8px}.wizard-steps{display:flex;margin-bottom:24px;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-card)}.wizard-step{flex:1;display:flex;align-items:center;gap:10px;padding:14px 16px;border:none;border-right:1px solid var(--color-border);background:transparent;color:var(--color-text-dim);text-align:left;cursor:default;font:inherit;position:relative;transition:background var(--transition),color var(--transition)}.wizard-step:last-child{border-right:none}.wizard-step.is-clickable{cursor:pointer}.wizard-step.is-clickable:hover{background:var(--color-surface-raised);color:var(--color-text-muted)}.wizard-step.is-active{background:var(--color-surface-raised);color:var(--color-text)}.wizard-step.is-active:after{content:"";position:absolute;bottom:0;left:0;right:0;height:2px;background:var(--color-accent);border-radius:1px 1px 0 0}.wizard-step.is-done{color:var(--color-text-muted)}.wizard-step-num{flex-shrink:0;width:26px;height:26px;border-radius:50%;border:1.5px solid var(--color-border);display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;transition:background var(--transition),border-color var(--transition),color var(--transition)}.wizard-step.is-active .wizard-step-num{background:var(--color-accent);border-color:var(--color-accent);color:#fff}.wizard-step.is-done .wizard-step-num{background:var(--status-done-bg);border-color:var(--status-done);color:var(--status-done)}.wizard-step-label{display:flex;flex-direction:column;gap:1px;min-width:0}.wizard-step-title{font-size:12px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.wizard-step-summary{font-size:11px;color:var(--color-text-dim);white-space:nowrap}.wizard-step.is-active .wizard-step-summary{color:var(--color-text-muted)}.wizard-lead{font-size:13px;color:var(--color-text-muted);margin-bottom:18px;line-height:1.6}.wizard-nav{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:24px;padding-top:18px;border-top:1px solid var(--color-border)}.review-grid{display:grid;gap:10px;font-size:13px}.review-row{display:grid;grid-template-columns:150px 1fr;gap:12px;align-items:start;padding:5px 0;border-bottom:1px solid var(--color-border-subtle)}.review-row:last-child{border-bottom:none}.review-label{color:var(--color-text-muted);font-size:12px}.tabs{display:flex;gap:0;border-bottom:1px solid var(--color-border);margin-bottom:22px;overflow-x:auto}.tab{padding:10px 16px;border:none;border-bottom:2px solid transparent;background:transparent;color:var(--color-text-muted);font-size:13px;font-weight:500;cursor:pointer;white-space:nowrap;border-radius:0;transition:color var(--transition),border-color var(--transition)}.tab:hover{color:var(--color-text);background:transparent;border-color:transparent}.tab.active{color:var(--color-text);border-bottom-color:var(--color-accent)}.chip{display:inline-flex;align-items:center;gap:5px;padding:2px 9px;border-radius:99px;font-size:11px;font-weight:500;background:var(--color-surface-raised);border:1px solid var(--color-border);color:var(--color-text-muted);white-space:nowrap}.chip.narrative{background:var(--color-accent-subtle);border-color:var(--color-accent-border);color:var(--color-accent)}.chip.selectable{cursor:pointer;-webkit-user-select:none;user-select:none}.chip.selectable:hover{border-color:var(--color-accent);color:var(--color-text)}.chip.selected{background:var(--color-accent);border-color:var(--color-accent);color:#fff}.chip-row{display:flex;flex-wrap:wrap;gap:6px}.chip-condition{background:#f59e0b1a;border-color:#f59e0b59;color:#f59e0b}.chip-query{background:var(--color-accent-subtle);border-color:var(--color-accent-border);color:var(--color-accent)}.chip-code{background:#a78bfa1a;border-color:#a78bfa59;color:#a78bfa}.chip-manual{background:#4ade8014;border-color:#4ade804d;color:#4ade80}.metric-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:24px}@media(max-width:1000px){.metric-grid{grid-template-columns:repeat(2,1fr)}}.metric-card{background:var(--color-surface);border:1px solid var(--color-border);border-top:2px solid var(--color-border);border-radius:var(--radius-lg);padding:16px 18px;box-shadow:var(--shadow-card);transition:border-color var(--transition),background var(--transition)}.metric-card.clickable{cursor:pointer}.metric-card.clickable:hover{border-color:var(--color-accent);border-top-color:var(--color-accent);background:var(--color-surface-raised)}.metric-card .metric-value{font-size:28px;font-weight:800;font-variant-numeric:tabular-nums;line-height:1.1;letter-spacing:-.5px}.metric-card .metric-label{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--color-text-muted);margin-top:5px;font-weight:600}.metric-card .metric-sub{font-size:12px;color:var(--color-text-dim);margin-top:3px}.mode-cards{display:grid;grid-template-columns:1fr 1fr;gap:16px;max-width:760px}@media(max-width:700px){.mode-cards{grid-template-columns:1fr}}.mode-card{display:flex;flex-direction:column;gap:14px;text-align:left;padding:24px;min-height:160px;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-xl);cursor:pointer;transition:border-color var(--transition),background var(--transition),box-shadow var(--transition);box-shadow:var(--shadow-card);position:relative}.mode-card:hover{border-color:var(--color-accent);background:var(--color-surface-raised);box-shadow:0 0 0 1px var(--color-accent)}.mode-card-icon{width:44px;height:44px;border-radius:10px;background:var(--color-accent-subtle);border:1px solid var(--color-accent-border);display:flex;align-items:center;justify-content:center;font-size:20px;color:var(--color-accent);flex-shrink:0}.mode-card-title{font-size:15px;font-weight:700;color:var(--color-text);display:flex;align-items:center;gap:8px}.mode-card-desc{font-size:13px;color:var(--color-text-muted);line-height:1.55}.mode-card-arrow{position:absolute;right:20px;top:50%;transform:translateY(-50%);color:var(--color-text-dim);font-size:18px;opacity:0;transition:opacity var(--transition),color var(--transition)}.mode-card:hover .mode-card-arrow{opacity:1;color:var(--color-accent)}.selector-card{display:flex;align-items:flex-start;gap:14px;padding:14px 16px;background:var(--color-surface);border:1px solid var(--color-border);border-left:3px solid transparent;border-radius:var(--radius-lg);cursor:pointer;transition:background var(--transition),border-color var(--transition);-webkit-user-select:none;user-select:none}.selector-card:hover{background:var(--color-surface-raised);border-color:var(--color-border);border-left-color:var(--color-border)}.selector-card.selected{background:var(--color-accent-subtle);border-color:var(--color-accent-border);border-left-color:var(--color-accent)}.selector-card-indicator{flex-shrink:0;margin-top:2px;width:18px;height:18px;border-radius:50%;border:2px solid var(--color-border);display:flex;align-items:center;justify-content:center;transition:border-color var(--transition),background var(--transition)}.selector-card.selected .selector-card-indicator{border-color:var(--color-accent);background:var(--color-accent)}.selector-card.selected .selector-card-indicator:after{content:"";width:6px;height:6px;border-radius:50%;background:#fff}.selector-card-check-indicator{flex-shrink:0;margin-top:2px;width:18px;height:18px;border-radius:5px;border:2px solid var(--color-border);display:flex;align-items:center;justify-content:center;transition:border-color var(--transition),background var(--transition)}.selector-card.selected .selector-card-check-indicator{border-color:var(--color-accent);background:var(--color-accent)}.selector-card.selected .selector-card-check-indicator:after{content:"✓";font-size:11px;color:#fff;font-weight:700;line-height:1}.selector-card-body{flex:1;min-width:0}.selector-card-meta{display:flex;align-items:center;gap:8px;margin-bottom:3px;flex-wrap:wrap}.selector-card-title{font-weight:600;font-size:13px}.selector-card-id{font-family:var(--font-mono);font-size:11px;color:var(--color-text-dim)}.selector-card-desc{font-size:12px;color:var(--color-text-muted);margin-top:2px;line-height:1.45}.selector-card-sub{font-size:11px;color:var(--color-text-dim);margin-top:3px}.selector-card-count{margin-left:auto;flex-shrink:0;text-align:right}.selector-card-count-num{font-size:20px;font-weight:700;font-variant-numeric:tabular-nums;color:var(--color-text);line-height:1}.selector-card-count-label{font-size:10px;color:var(--color-text-dim);text-transform:uppercase;letter-spacing:.05em}.graph-picker{display:flex;flex-direction:column;gap:10px}.graph-picker-toolbar{display:flex;flex-direction:column;gap:8px}.graph-picker-search{width:100%;padding:8px 10px;border:1px solid var(--color-border);border-radius:var(--radius);background:var(--color-surface);color:var(--color-text);font-size:13px}.graph-picker-list{display:flex;flex-direction:column;gap:4px;overflow-y:auto;border:1px solid var(--color-border);border-radius:var(--radius);background:var(--color-surface-raised);padding:4px}.graph-picker-row{display:flex;flex-direction:column;align-items:flex-start;gap:2px;width:100%;min-height:48px;padding:8px 10px;border:1px solid transparent;border-radius:calc(var(--radius) - 2px);background:transparent;color:var(--color-text);text-align:left;cursor:pointer}.graph-picker-row:hover{background:var(--color-surface);border-color:var(--color-border)}.graph-picker-row.selected{background:var(--color-accent-bg, rgba(59, 130, 246, .12));border-color:var(--color-accent, #3b82f6)}.graph-picker-row-main{display:flex;align-items:center;gap:8px}.graph-picker-row-title{font-weight:600;font-size:13px}.graph-picker-row-id{font-size:11px;color:var(--color-text-dim)}.graph-picker-row-desc{font-size:11px;color:var(--color-text-muted);line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.graph-picker-empty{padding:16px;text-align:center;font-size:13px;color:var(--color-text-dim)}.selector-summary{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px;padding:8px 12px;background:var(--color-surface-raised);border:1px solid var(--color-border);border-radius:var(--radius);font-size:12px;color:var(--color-text-muted)}.drawer-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000008c;z-index:200;display:flex;justify-content:flex-end;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}.drawer{width:min(580px,92vw);height:100%;background:var(--color-surface);border-left:1px solid var(--color-border);overflow-y:auto;padding:22px 24px;box-shadow:-4px 0 24px #0006}.drawer-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:18px}.section{margin-bottom:24px}.section-title{font-size:13px;font-weight:700;margin-bottom:12px;color:var(--color-text)}.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}@media(max-width:640px){.form-grid{grid-template-columns:1fr}}.field{display:flex;flex-direction:column;gap:5px}.field>label{margin:0}.field .hint{font-size:11px;color:var(--color-text-dim);line-height:1.4}.field input,.field select,.field textarea{width:100%}.prereq-section{border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;margin-bottom:12px}.prereq-section-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:var(--color-surface-raised);cursor:pointer;-webkit-user-select:none;user-select:none;transition:background var(--transition)}.prereq-section-header:hover{background:var(--color-surface-hover)}.prereq-section-body{padding:14px 16px;border-top:1px solid var(--color-border)}.prereq-tag{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;background:var(--color-surface-raised);border:1px solid var(--color-border);border-radius:var(--radius);font-size:12px;color:var(--color-text)}.prereq-tag-remove{background:none;border:none;padding:0;color:var(--color-text-dim);cursor:pointer;font-size:14px;line-height:1;display:flex;align-items:center}.prereq-tag-remove:hover{color:var(--status-failed);background:none;border:none}