@ra3orblade/swarm 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -150,6 +150,7 @@ var AUDIT_TYPES = new Set([
150
150
  "claim.orphaned",
151
151
  "claim.denied",
152
152
  "rules.changed",
153
+ "worktree.reclaimed",
153
154
  "worktree.created",
154
155
  "worktree.removed",
155
156
  "worktree.bootstrapped",
@@ -325,7 +326,7 @@ function guardWrite(target, current, claims, modes = DEFAULT_MODES, kind = "file
325
326
  }
326
327
  // packages/core/src/hygiene.ts
327
328
  var HYGIENE_DEFAULTS = {
328
- staleDays: 7,
329
+ staleDays: 2,
329
330
  abandonedDays: 30,
330
331
  hungryRssKb: 1024 * 1024,
331
332
  heavyKb: 2 * 1024 * 1024
package/dist/swarm.js CHANGED
@@ -269,6 +269,7 @@ var AUDIT_TYPES = new Set([
269
269
  "claim.orphaned",
270
270
  "claim.denied",
271
271
  "rules.changed",
272
+ "worktree.reclaimed",
272
273
  "worktree.created",
273
274
  "worktree.removed",
274
275
  "worktree.bootstrapped",
@@ -624,7 +625,7 @@ var LIVE_WINDOW_MS = 10 * 60000;
624
625
  var WRITE_TOOLS = new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
625
626
  // packages/core/src/hygiene.ts
626
627
  var HYGIENE_DEFAULTS = {
627
- staleDays: 7,
628
+ staleDays: 2,
628
629
  abandonedDays: 30,
629
630
  hungryRssKb: 1024 * 1024,
630
631
  heavyKb: 2 * 1024 * 1024
package/dist/swarmd.js CHANGED
@@ -832,6 +832,7 @@ var AUDIT_TYPES = new Set([
832
832
  "claim.orphaned",
833
833
  "claim.denied",
834
834
  "rules.changed",
835
+ "worktree.reclaimed",
835
836
  "worktree.created",
836
837
  "worktree.removed",
837
838
  "worktree.bootstrapped",
@@ -2356,7 +2357,7 @@ function planGc(worktrees, claims) {
2356
2357
 
2357
2358
  // packages/core/src/hygiene.ts
2358
2359
  var HYGIENE_DEFAULTS = {
2359
- staleDays: 7,
2360
+ staleDays: 2,
2360
2361
  abandonedDays: 30,
2361
2362
  hungryRssKb: 1024 * 1024,
2362
2363
  heavyKb: 2 * 1024 * 1024
@@ -2387,6 +2388,30 @@ function classifyProcess(p, opts = {}) {
2387
2388
  };
2388
2389
  return { ...p, issue: null, note: null, reclaimable: false };
2389
2390
  }
2391
+ var BUILD_DIRS = ["node_modules", "target", "dist", ".next", ".turbo"];
2392
+ function reclaimPlan(w, dirs, others = []) {
2393
+ const refusals = [];
2394
+ if (w.main)
2395
+ refusals.push("this is the main checkout");
2396
+ if (w.liveSessions > 0)
2397
+ refusals.push(`${w.liveSessions} live session${w.liveSessions === 1 ? "" : "s"} in it`);
2398
+ if (w.heldByClaim)
2399
+ refusals.push(`claimed by ${w.heldByClaim}`);
2400
+ const inside = dirs.filter((d) => d.path.startsWith(`${w.path}/`));
2401
+ if (inside.length !== dirs.length)
2402
+ refusals.push("a candidate lay outside the worktree");
2403
+ const named = inside.filter((d) => BUILD_DIRS.includes(d.path.split("/").pop() ?? ""));
2404
+ if (named.length !== inside.length)
2405
+ refusals.push("a candidate was not a build directory");
2406
+ const nested = others.filter((o) => o !== w.path && o.startsWith(`${w.path}/`));
2407
+ const mine = named.filter((d) => !nested.some((n) => d.path.startsWith(`${n}/`)));
2408
+ return {
2409
+ path: w.path,
2410
+ dirs: mine.map((d) => d.path),
2411
+ kb: mine.reduce((n, d) => n + d.kb, 0),
2412
+ refusals
2413
+ };
2414
+ }
2390
2415
  function classifyWorktree(w, opts = {}) {
2391
2416
  const o = { ...HYGIENE_DEFAULTS, ...opts };
2392
2417
  const kb = w.diskKb ?? 0;
@@ -6467,12 +6492,19 @@ function applyStatus(w, st, ah) {
6467
6492
  const a = ah?.trim();
6468
6493
  w.ahead = a === undefined || a === "" ? -1 : Number(a);
6469
6494
  }
6470
- function applyDrift(w, behind, ancestor, firstParents) {
6495
+ function applyDrift(w, behind, ancestor, firstParents, cherry = null) {
6471
6496
  const b = behind?.trim();
6472
6497
  w.behind = b === undefined || b === "" ? -1 : Number(b);
6473
6498
  const onLine = firstParents?.split(`
6474
6499
  `).some((sha) => sha.startsWith(w.head)) ?? true;
6475
- w.merged = ancestor && !onLine;
6500
+ w.merged = (ancestor || squashed(cherry)) && !onLine;
6501
+ }
6502
+ function squashed(cherry) {
6503
+ if (!cherry)
6504
+ return false;
6505
+ const lines = cherry.split(`
6506
+ `).filter((l) => l.trim());
6507
+ return lines.length > 0 && lines.every((l) => l.startsWith("-"));
6476
6508
  }
6477
6509
  var FIRST_PARENT_DEPTH = "5000";
6478
6510
  var baseOf = (wts) => wts[0]?.main ? wts[0].branch : null;
@@ -6494,15 +6526,16 @@ async function listWorktreesAsync(root) {
6494
6526
  const line = base ? await gitAsync(root, ["rev-list", "--first-parent", "-n", FIRST_PARENT_DEPTH, base]) : null;
6495
6527
  await Promise.all(wts.map(async (w) => {
6496
6528
  const drift = base && !w.main;
6497
- const [st, ah, be, mg] = await Promise.all([
6529
+ const [st, ah, be, mg, ch] = await Promise.all([
6498
6530
  gitAsync(w.path, ["status", "--porcelain", "--untracked-files=no"]),
6499
6531
  gitAsync(w.path, ["rev-list", "--count", "@{upstream}..HEAD"]),
6500
6532
  drift ? gitAsync(w.path, ["rev-list", "--count", `HEAD..${base}`]) : null,
6501
- drift ? gitAsync(w.path, ["merge-base", "--is-ancestor", "HEAD", base]) : null
6533
+ drift ? gitAsync(w.path, ["merge-base", "--is-ancestor", "HEAD", base]) : null,
6534
+ drift ? gitAsync(w.path, ["cherry", base, "HEAD"]) : null
6502
6535
  ]);
6503
6536
  applyStatus(w, st, ah);
6504
6537
  if (drift)
6505
- applyDrift(w, be, mg !== null, line);
6538
+ applyDrift(w, be, mg !== null, line, ch);
6506
6539
  }));
6507
6540
  return wts;
6508
6541
  }
@@ -6972,6 +7005,7 @@ import {
6972
7005
  readSync,
6973
7006
  realpathSync as realpathSync2,
6974
7007
  renameSync,
7008
+ rmSync as rmSync2,
6975
7009
  statSync,
6976
7010
  unlinkSync,
6977
7011
  writeFileSync as writeFileSync2
@@ -7028,6 +7062,8 @@ function runBootstrap(plan, opts) {
7028
7062
  }
7029
7063
 
7030
7064
  // packages/daemon/src/task-sources.ts
7065
+ var PENDING = Object.freeze({ at: 0, tasks: [], error: null });
7066
+
7031
7067
  class TaskSources {
7032
7068
  env;
7033
7069
  cache = new Map;
@@ -7039,11 +7075,11 @@ class TaskSources {
7039
7075
  const hit = this.cache.get(projectId);
7040
7076
  if (!hit || Date.now() - hit.at >= ttlMs)
7041
7077
  this.refresh(projectId, kind, root, opts);
7042
- return hit ?? { at: 0, tasks: [], error: null };
7078
+ return hit ?? PENDING;
7043
7079
  }
7044
7080
  async refresh(projectId, kind, root, opts) {
7045
7081
  if (this.inflight.has(projectId))
7046
- return this.cache.get(projectId) ?? { at: 0, tasks: [], error: null };
7082
+ return this.cache.get(projectId) ?? PENDING;
7047
7083
  this.inflight.add(projectId);
7048
7084
  const prev = this.cache.get(projectId);
7049
7085
  let entry;
@@ -8277,6 +8313,7 @@ ${err}
8277
8313
  return null;
8278
8314
  let hit;
8279
8315
  let error = null;
8316
+ let loading = false;
8280
8317
  const kind = taskSourceKind(source);
8281
8318
  if (kind === "github" || kind === "linear") {
8282
8319
  const e = this.taskSources.get(projectId, kind, p.root, {
@@ -8285,10 +8322,17 @@ ${err}
8285
8322
  });
8286
8323
  hit = { tasks: e.tasks };
8287
8324
  error = e.error;
8325
+ loading = e.at === 0 && e.error === null;
8288
8326
  } else {
8289
8327
  const path = join8(p.root, source);
8290
8328
  if (!existsSync6(path))
8291
- return { source, required: this.requiredGates(projectId), tasks: [] };
8329
+ return {
8330
+ source,
8331
+ required: this.requiredGates(projectId),
8332
+ tasks: [],
8333
+ error: `${source} not found in this repository`,
8334
+ loading: false
8335
+ };
8292
8336
  const mtime = statSync(path).mtimeMs;
8293
8337
  let md = this.taskCache.get(projectId);
8294
8338
  if (!md || md.path !== path || md.mtime !== mtime) {
@@ -8317,7 +8361,7 @@ ${err}
8317
8361
  gated: gatesSatisfied(tr, required)
8318
8362
  };
8319
8363
  });
8320
- return { source, required, tasks: board, error };
8364
+ return { source, required, tasks: board, error, loading };
8321
8365
  }
8322
8366
  rulesFor(repoRoot) {
8323
8367
  return this.policyFor(repoRoot).config.rules;
@@ -9622,7 +9666,34 @@ ${p2.reason ?? ""}`.trim(),
9622
9666
  return newest ? Math.max(0, Date.now() - newest) : null;
9623
9667
  }
9624
9668
  duCache = new Map;
9669
+ buildCache = new Map;
9625
9670
  duInflight = null;
9671
+ async measureBuild(path) {
9672
+ const args = ["-maxdepth", "4", "("];
9673
+ BUILD_DIRS.forEach((d, i) => {
9674
+ if (i)
9675
+ args.push("-o");
9676
+ args.push("-name", d);
9677
+ });
9678
+ args.push(")", "-type", "d", "-prune");
9679
+ const out = [];
9680
+ try {
9681
+ const find = Bun.spawn(["find", path, ...args], { stdout: "pipe", stderr: "ignore" });
9682
+ const found = (await new Response(find.stdout).text()).split(`
9683
+ `).filter(Boolean);
9684
+ await find.exited;
9685
+ for (const dir of found) {
9686
+ const du = Bun.spawn(["du", "-sk", "-x", dir], { stdout: "pipe", stderr: "ignore" });
9687
+ const text = await new Response(du.stdout).text();
9688
+ if (await du.exited === 0) {
9689
+ const kb = Number.parseInt(text.trim().split(/\s+/)[0] ?? "", 10);
9690
+ if (Number.isFinite(kb))
9691
+ out.push({ path: dir, kb });
9692
+ }
9693
+ }
9694
+ } catch {}
9695
+ return out;
9696
+ }
9626
9697
  refreshDisk(paths, ttlMs) {
9627
9698
  if (this.duInflight)
9628
9699
  return;
@@ -9645,6 +9716,7 @@ ${p2.reason ?? ""}`.trim(),
9645
9716
  }
9646
9717
  } catch {}
9647
9718
  this.duCache.set(path, { v, t: Date.now() });
9719
+ this.buildCache.set(path, { dirs: await this.measureBuild(path), t: Date.now() });
9648
9720
  }
9649
9721
  })().finally(() => {
9650
9722
  this.duInflight = null;
@@ -9704,6 +9776,7 @@ ${p2.reason ?? ""}`.trim(),
9704
9776
  merged: w.merged,
9705
9777
  idleMs: Store.worktreeIdleMs(w.path),
9706
9778
  diskKb: this.duCache.get(w.path)?.v ?? null,
9779
+ buildKb: this.buildCache.has(w.path) ? this.buildCache.get(w.path).dirs.reduce((n, d) => n + d.kb, 0) : null,
9707
9780
  heldByClaim: held?.task ?? null,
9708
9781
  liveSessions: this.sessions().filter((s) => s.cwd?.startsWith(w.path) && !s.endedAt && s.state !== "ended").length
9709
9782
  });
@@ -10088,6 +10161,47 @@ ${p2.reason ?? ""}`.trim(),
10088
10161
  acked: Boolean(r.acked)
10089
10162
  })), changes.map((c) => ({ at: c.ts, added: JSON.parse(c.added) })), Date.now(), days3);
10090
10163
  }
10164
+ reclaimBuild(path, { dryRun = false } = {}) {
10165
+ const report = this.hygiene();
10166
+ const w = report.worktrees.find((x) => x.path === path);
10167
+ if (!w)
10168
+ return { ok: false, error: `not a tracked worktree: ${path}` };
10169
+ const cached = this.buildCache.get(path);
10170
+ if (!cached)
10171
+ return { ok: false, error: "not measured yet \u2014 try again in a moment" };
10172
+ const plan = reclaimPlan(w, cached.dirs, report.worktrees.map((x) => x.path));
10173
+ if (plan.refusals.length)
10174
+ return { ok: false, error: plan.refusals.join("; "), plan };
10175
+ if (dryRun)
10176
+ return { ok: true, plan, removed: 0, freedKb: 0 };
10177
+ let removed = 0;
10178
+ let freedKb = 0;
10179
+ for (const dir of plan.dirs) {
10180
+ if (!dir.startsWith(`${path}/`))
10181
+ continue;
10182
+ try {
10183
+ rmSync2(dir, { recursive: true, force: true });
10184
+ removed++;
10185
+ freedKb += cached.dirs.find((d) => d.path === dir)?.kb ?? 0;
10186
+ } catch {}
10187
+ }
10188
+ this.duCache.delete(path);
10189
+ this.buildCache.delete(path);
10190
+ this.append({
10191
+ ts: new Date().toISOString(),
10192
+ type: "worktree.reclaimed",
10193
+ projectId: w.projectId,
10194
+ sessionId: null,
10195
+ payload: {
10196
+ path,
10197
+ branch: w.branch,
10198
+ dirs: removed,
10199
+ freedKb,
10200
+ summary: `reclaimed ${Math.round(freedKb / 1024)} MB of build output from ${w.branch ?? path}`
10201
+ }
10202
+ });
10203
+ return { ok: true, plan, removed, freedKb };
10204
+ }
10091
10205
  stalls = new Map;
10092
10206
  checkStalls() {
10093
10207
  const live = this.db.query("SELECT id, project_id FROM sessions WHERE state IN ('active','waiting') AND ended_at IS NULL AND last_seen_at >= ?").all(new Date(Date.now() - IDLE_MS).toISOString());
@@ -11717,7 +11831,7 @@ class WorkflowEngine {
11717
11831
  }
11718
11832
 
11719
11833
  // packages/daemon/src/app.ts
11720
- var VERSION = "0.12.0";
11834
+ var VERSION = "0.13.0";
11721
11835
  var WEB_DIR = (() => {
11722
11836
  if (process.env.SWARM_WEB_DIR)
11723
11837
  return process.env.SWARM_WEB_DIR;
@@ -11845,6 +11959,13 @@ function createApp(store = new Store, hooks2 = {}) {
11845
11959
  app.get("/v1/graphs/collisions", (c) => c.json(store.collisions(c.req.query("project") || undefined)));
11846
11960
  app.get("/v1/graphs/lineage", (c) => c.json(store.lineage(c.req.query("project") || undefined, Math.max(1, Math.min(90, Number(c.req.query("days") ?? 14) || 14)), c.req.queries("expand") ?? [])));
11847
11961
  app.get("/v1/rules/effect", (c) => c.json(store.ruleEffect(c.req.query("project") || undefined, Math.max(1, Math.min(365, Number(c.req.query("days") ?? 30) || 30)))));
11962
+ app.post("/v1/hygiene/reclaim", async (c) => {
11963
+ const body = await c.req.json().catch(() => ({}));
11964
+ if (!body.path)
11965
+ return c.json({ ok: false, error: "path required" }, 400);
11966
+ const r = store.reclaimBuild(body.path, { dryRun: Boolean(body.dry) });
11967
+ return c.json(r, r.ok ? 200 : 409);
11968
+ });
11848
11969
  app.get("/v1/security", (c) => c.json(store.security(c.req.query("project") || undefined, Math.max(1, Math.min(90, Number(c.req.query("days") ?? 14) || 14)))));
11849
11970
  app.get("/v1/heat", (c) => c.json(store.fileHeat(c.req.query("project") || undefined, Math.max(1, Math.min(90, Number(c.req.query("days") ?? 14) || 14)))));
11850
11971
  app.get("/v1/graphs/resources", (c) => c.json(store.resourceHolding(c.req.query("project") || undefined, Math.max(1, Math.min(30, Number(c.req.query("days") ?? 3) || 3)))));
@@ -12568,8 +12689,16 @@ function createApp(store = new Store, hooks2 = {}) {
12568
12689
  });
12569
12690
  });
12570
12691
  app.get("/", (c) => c.html(readFileSync4(join10(WEB_DIR, "index.html"), "utf8")));
12571
- const MIME = { js: "text/javascript", css: "text/css" };
12572
- app.get("/:file{[a-z0-9-]+\\.(js|css)}", (c) => {
12692
+ app.get("/next", (c) => c.redirect("/", 308));
12693
+ const MIME = {
12694
+ js: "text/javascript",
12695
+ css: "text/css",
12696
+ svg: "image/svg+xml",
12697
+ ico: "image/x-icon",
12698
+ png: "image/png"
12699
+ };
12700
+ const BINARY = new Set(["ico", "png"]);
12701
+ app.get("/:file{[a-z0-9-]+\\.(js|css|svg|ico|png)}", (c) => {
12573
12702
  const f = c.req.param("file");
12574
12703
  const p = join10(WEB_DIR, f);
12575
12704
  if (!existsSync7(p))
@@ -12578,8 +12707,9 @@ function createApp(store = new Store, hooks2 = {}) {
12578
12707
  const etag = `W/"${st.size.toString(16)}-${st.mtimeMs.toString(16)}"`;
12579
12708
  if (c.req.header("if-none-match") === etag)
12580
12709
  return c.body(null, 304, { etag });
12581
- return c.body(readFileSync4(p, "utf8"), 200, {
12582
- "content-type": MIME[f.split(".").pop() ?? ""] ?? "text/plain",
12710
+ const ext = f.split(".").pop() ?? "";
12711
+ return c.body(BINARY.has(ext) ? readFileSync4(p) : readFileSync4(p, "utf8"), 200, {
12712
+ "content-type": MIME[ext] ?? "text/plain",
12583
12713
  "cache-control": "no-cache",
12584
12714
  etag
12585
12715
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ra3orblade/swarm",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Local-first control plane for AI-agent development: watch every Claude Code / Codex / Grok session on your machine, ledger tasks and worktrees, enforce rules as hook denials.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -0,0 +1 @@
1
+ :root{--bg:#f6f7f9;--panel:#fff;--panel-2:#f0f2f5;--line:#e4e7ec;--line-2:#eef0f3;--fg:#1a1d21;--fg-2:#3d4650;--dim:#8b929c;--faint:#aab1bb;--acc:#388114;--acc-fill:#559b1b;--acc-soft:#559b1b26;--ok:#1f9d55;--ok-soft:#1f9d551f;--warn:#c77800;--warn-soft:#c778001f;--bad:#d1352b;--bad-soft:#d1352b1f;--violet:#7857c9;--c0:#8b929c;--c1:#4d9e2a;--c2:#1b9e77;--c3:#9ab828;--c4:#2f7d4f;--c5:#7fb069;--c6:#0f5c3a;--c7:#c3d84a;--acc-1:#e2f6d8;--acc-2:#b8e4a1;--acc-3:#8bc866;--acc-4:#5aa12e;--acc-5:#35741f;--mono:ui-monospace,"SF Mono",SFMono-Regular,Menlo,monospace;--sans:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;--fs-2xs:11px;--fs-xs:11.5px;--fs-sm:12px;--fs-mono:12.5px;--fs-md:13px;--fs-menu:13.5px;--fs-lg:14px;--fs-xl:15px;--fs-2xl:24px;--pill-h:calc(var(--fs-xs)*1.2 + 8px);--shadow:0 1px 2px #1018280a,0 1px 3px #1018280f;--shadow-pop:0 8px 24px #10182824,0 1px 3px #10182814;--overlay:#00000073;--r:9px;--r-sm:6px;--r-xs:4px;--r-pill:20px;--t-fast:.12s;--t-med:.2s;--t-in:.32s;--t-pulse:2s;--hdr-h:48px;--sb-w:240px;--inset-tl:96px;--acc-contrast:#fff;--pad-cell:9px 12px;--pad-page:20px 22px;--pad-ctl:7px 11px;--pad-row:7px 10px;--gap-sec:18px}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--bg:#0c0e12;--panel:#14171d;--panel-2:#1a1e26;--line:#242932;--line-2:#1e222a;--fg:#e6e9ee;--fg-2:#c2c8d0;--dim:#7c8592;--faint:#5a626e;--acc:#a3e635;--acc-fill:#a3e635;--acc-soft:#a3e63524;--ok:#3fb571;--ok-soft:#3fb57124;--warn:#d9a441;--warn-soft:#d9a44124;--bad:#f0655a;--bad-soft:#f0655a24;--violet:#a68bec;--c0:#7c8592;--c1:#6bbf3a;--c2:#2bb78f;--c3:#b0cf3a;--c4:#3f9d63;--c5:#93c47d;--c6:#2f8f5a;--c7:#d3e88a;--acc-1:#1c3311;--acc-2:#2f5a18;--acc-3:#4d8a24;--acc-4:#7cc02f;--acc-5:#bfef7a;--shadow:0 1px 2px #0000004d,0 2px 6px #00000040;--shadow-pop:0 8px 24px #00000080,0 1px 3px #0006;--acc-contrast:#0e1013}}:root[data-theme=dark]{--bg:#0c0e12;--panel:#14171d;--panel-2:#1a1e26;--line:#242932;--line-2:#1e222a;--fg:#e6e9ee;--fg-2:#c2c8d0;--dim:#7c8592;--faint:#5a626e;--acc:#a3e635;--acc-fill:#a3e635;--acc-soft:#a3e63524;--ok:#3fb571;--ok-soft:#3fb57124;--warn:#d9a441;--warn-soft:#d9a44124;--bad:#f0655a;--bad-soft:#f0655a24;--violet:#a68bec;--c0:#7c8592;--c1:#6bbf3a;--c2:#2bb78f;--c3:#b0cf3a;--c4:#3f9d63;--c5:#93c47d;--c6:#2f8f5a;--c7:#d3e88a;--acc-1:#1c3311;--acc-2:#2f5a18;--acc-3:#4d8a24;--acc-4:#7cc02f;--acc-5:#bfef7a;--shadow:0 1px 2px #0000004d,0 2px 6px #00000040;--shadow-pop:0 8px 24px #00000080,0 1px 3px #0006;--acc-contrast:#0e1013}*{box-sizing:border-box}html,body{height:100%}html{zoom:var(--ui-zoom,1)}body{background:var(--bg);color:var(--fg);font:var(--fs-lg)/1.5 var(--sans);-webkit-font-smoothing:antialiased;display:grid;grid-template-rows:var(--hdr-h)1fr;grid-template-columns:var(--sb-w)1fr;overflow:hidden;animation:appin var(--t-in)ease both;user-select:none;-webkit-user-select:none;margin:0}@keyframes appin{0%{opacity:0}to{opacity:1}}input,textarea,tbody td,.mono,code,kbd{user-select:text;-webkit-user-select:text}::selection{background:var(--acc-soft)}a{color:var(--acc);text-decoration:none}.dim{color:var(--dim)}.faint{color:var(--faint)}.mono{font-family:var(--mono);font-size:var(--fs-mono)}.num{text-align:right;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}kbd{font:var(--fs-mono)var(--mono);background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-xs);color:var(--fg-2);padding:1px 5px}code{font:var(--fs-md)var(--mono);color:var(--fg-2)}body.nosb{grid-template-columns:46px 1fr}body.nosb aside{overflow:hidden;padding:12px 5px}body.nosb #projects{display:none}#root>aside{grid-column:1;grid-row:2}#root>main{grid-column:2;grid-row:2}#projects h4{display:flex;align-items: center;gap:5px}.h4-act{cursor:pointer;color:var(--faint);display:inline-flex;border-radius:var(--r-xs);margin-left:auto;padding:2px}.h4-act:hover{color:var(--acc)}.pk-h input{background:var(--panel-2);border:1px solid var(--line);color:var(--fg);border-radius:var(--r-sm);font:var(--fs-mono)var(--mono);outline:none;flex:1;min-width:0;padding:5px 9px}.pk-h input:focus{border-color:var(--acc)}header{grid-column:1/3;display:flex;border-bottom:1px solid var(--line);background:var(--panel);z-index:5;align-items: center;gap:6px;padding:0 16px}html.chrome-inset header{padding-left:var(--inset-tl)}html.chrome-inset.fs header{padding-left:16px}html.chrome-inset header{cursor:default}header .logo{letter-spacing:.02em;font-weight:700;font-size:var(--fs-xl);display:flex;align-items: center;gap:8px;margin-right:14px}header .logo svg{image-rendering:pixelated;image-rendering:crisp-edges;width:22px;height:auto;transform:translateY(-2px)}header .nav{color:var(--dim);border-radius:var(--r-sm);transition:color var(--t-fast),background var(--t-fast);padding:6px 11px;font-weight:500}header .nav:hover{color:var(--fg-2)}header .nav.on{color:var(--fg);background:var(--panel-2)}header .sp{flex:1}header #today{color:var(--dim);font-variant-numeric:tabular-nums;margin-right:18px}header #today b{color:var(--fg-2);font-weight:600}#daemon{display:flex;color:var(--dim);font-size:var(--fs-md);align-items: center;gap:7px}#daemon .dot{background:var(--bad);transition:background var(--t-med);border-radius:50%;width:7px;height:7px}#daemon .dot.on{background:var(--ok);box-shadow:0 0 0 3px var(--ok-soft)}#root>aside{border-right:1px solid var(--line);background:var(--panel);overflow:auto;display:flex;flex-direction:column;padding:12px 10px}#viewnav{display:flex;align-items: center;gap:2px}#viewnav .navgrp{display:flex;color:var(--dim);border-radius:var(--r-sm);font:inherit;font-size:var(--fs-md);cursor:pointer;transition:color var(--t-fast),background var(--t-fast);background:0 0;border:0;align-items: center;gap:6px;padding:6px 10px;font-weight:500}#viewnav .navgrp:hover{color:var(--fg-2);background:var(--panel-2)}#viewnav .navgrp.on{color:var(--fg);background:var(--panel-2)}#viewnav .navview{color:var(--acc);font-weight:600}#viewnav .navview:before{content:"";display:inline-block;background:var(--line);width:1px;height:11px;margin:0 7px -1px}#viewnav .navgrp.open{color:var(--fg);background:var(--line)}#viewnav .navgrp.open .chev{opacity:.9;transform:rotate(180deg)}#viewnav .navgrp .chev{opacity:.5;flex:none}#viewnav .navcount{background:var(--bad-soft);color:var(--bad);font-size:var(--fs-2xs);border-radius:99px;padding:0 5px;font-weight:600}#root>aside h4{color:var(--faint);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.09em;margin:14px 8px 6px;font-weight:600}#root>aside h4:first-child{margin-top:2px}.proj{position:relative;padding:var(--pad-row);border-radius:var(--r-sm);cursor:pointer;display:flex;color:var(--fg-2);transition:background var(--t-fast);user-select:none;align-items: center;gap:9px}.proj:hover{background:var(--panel-2)}.proj.sel{background:var(--acc-soft);color:var(--fg)}.proj.sel .nm{font-weight:600}.proj .st{background:var(--faint);transition:background var(--t-med);border-radius:50%;flex:none;width:7px;height:7px}.proj .st.live{background:var(--ok);box-shadow:0 0 0 3px var(--ok-soft)}.proj .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.proj small{color:var(--dim);font-variant-numeric:tabular-nums;font-size:var(--fs-sm);text-align:right;flex:none;min-width:15px}.proj .act{position:absolute;right:var(--pad-row-x,7px);display:inline-flex;opacity:0;pointer-events:none;color:var(--faint);font-size:var(--fs-lg);border-radius:var(--r-xs);transition:color var(--t-fast),background var(--t-fast),opacity var(--t-fast);padding:2px;line-height:1;top:50%;transform:translateY(-50%)}.proj:hover .act,.proj.menu-open .act{opacity:1;pointer-events:auto}.proj .act:focus-visible{opacity:1;pointer-events:auto}.proj:hover small,.proj.menu-open small{visibility:hidden}.proj .act:hover{color:var(--fg);background:var(--line)}.proj .act.rm:hover{color:var(--bad)}.srch{display:flex;gap:8px;margin-bottom:14px}.srch input{background:var(--panel);border:1px solid var(--line);color:var(--fg);border-radius:var(--r-sm);font:var(--fs-md)var(--sans);flex:1;max-width:640px;padding:8px 12px}.srch input:focus{border-color:var(--acc);outline:none}.hit{border:1px solid var(--line);border-radius:var(--r-sm);background:var(--panel);margin-bottom:8px;padding:10px 12px}.hit .ht{display:flex;align-items: center;gap:8px;margin-bottom:4px}.hit .hs{font-size:var(--fs-sm);color:var(--fg-2);white-space:pre-wrap}.hit mark{background:var(--warn-soft);color:var(--fg);border-radius:2px;padding:0 1px}.dr-rules{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px 16px;margin:10px 0}.dr-rule{display:flex;font-size:var(--fs-sm);align-items: center;gap:8px}.dr-rule select{background:var(--panel-2);color:var(--fg);border:1px solid var(--line);border-radius:var(--r-sm);padding:2px 4px}.dr-flaky{border:1px solid var(--line);border-radius:var(--r-sm);background:var(--panel-2);margin:6px 0;padding:6px 8px}table.plain{border-collapse:collapse;font-size:var(--fs-sm);width:100%}table.plain td{border-top:1px solid var(--line);vertical-align:top;padding:3px 6px}.pk.pal{align-self: start;margin-top:9vh}.pal .pk-list{min-height:120px;max-height:min(440px,62vh)}.pal .pk-row.on{background:var(--acc-soft);color:var(--fg)}.pal-empty{padding:16px}.pal .pk-row .grp{color:var(--faint);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.07em;margin-left:auto}#picker:empty{display:none}#picker{position:fixed;background:var(--overlay);display:grid;z-index:50;place-items: center;inset:0}.pk{display:flex;background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow-pop);overflow:hidden;flex-direction:column;width:min(560px,92vw);max-height:78vh}.pk-h{display:flex;border-bottom:1px solid var(--line);align-items: center;gap:8px;padding:12px 14px}.pk-list{overflow:auto;padding:6px}.pk-row{display:flex;padding:var(--pad-row);border-radius:var(--r-sm);cursor:pointer;color:var(--fg-2);align-items: center;gap:9px}.pk-row:hover{background:var(--panel-2)}.pk-row .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.pk-row.up{color:var(--dim)}.pk-row .badge{margin:0}.pk-b{display:grid;gap:10px;padding:12px 14px}.pk-b label{display:grid;font:500 var(--fs-sm)var(--sans);color:var(--dim);gap:4px}.pk-b input,.pk-b textarea,.pk-b select{background:var(--panel-2);border:1px solid var(--line);color:var(--fg);border-radius:var(--r-sm);font:var(--fs-md)var(--sans);outline:none;width:100%;padding:7px 9px}.pk-b textarea{resize:vertical;font-family:var(--mono);font-size:var(--fs-sm);min-height:120px;line-height:1.5}.pk-b input:focus,.pk-b textarea:focus,.pk-b select:focus{border-color:var(--acc)}.pk-b .row{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px}.pk.wide{width:min(960px,96vw)}.df-files{display:grid;overflow:auto;border:1px solid var(--line);border-radius:var(--r-sm);gap:1px;max-height:22vh}.df-files a{display:flex;color:var(--fg-2);text-decoration:none;font:var(--fs-sm)var(--mono);gap:10px;padding:4px 8px}.df-files a:hover,.df-files a.on{background:var(--panel-2);color:var(--fg)}.df-files .st{color:var(--dim);width:12px}.df-files .pl{color:var(--ok)}.df-files .mi{color:var(--warn)}.df-files .pa{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.df-patch{overflow:auto;background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-sm);font:var(--fs-sm)var(--mono);white-space:pre;max-height:44vh;margin:0;padding:8px 10px;line-height:1.45}.df-patch .a{color:var(--ok)}.df-patch .d{color:var(--warn)}.df-patch .h{color:var(--acc)}.df-patch .m{color:var(--dim)}.wn .pk-b{overflow:auto;gap:2px;max-height:64vh}.wn h3{font:600 var(--fs-lg)var(--sans);color:var(--fg);margin:0 0 2px}.wn .date{color:var(--dim);font-size:var(--fs-sm);margin-bottom:12px}.wn h4{font:600 var(--fs-md)var(--sans);color:var(--acc);text-transform:none;letter-spacing:0;margin:14px 0 4px}.wn ul{margin:0 0 6px;padding-left:18px}.wn li{color:var(--fg-2);margin:5px 0;line-height:1.55}.wn p{color:var(--fg-2);margin:0 0 10px;line-height:1.6}.wn code{font-family:var(--mono);font-size:var(--fs-sm);background:var(--panel-2);border-radius:var(--r-xs);padding:1px 5px}.wn a{color:var(--acc)}.wn b{color:var(--fg)}.wn .snip{background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-sm);font-family:var(--mono);font-size:var(--fs-sm);white-space:pre-wrap;word-break:break-word;color:var(--fg-2);margin:2px 0 12px;padding:9px 11px;line-height:1.5}.wn .cbtn{font-weight:500;font-size:var(--fs-sm);color:var(--acc);margin-left:8px}.rp{height:78vh}.rp .pk-b{overflow:auto;flex:1;gap:2px;min-height:0;max-height:none}.rp .snip{overflow:visible;max-height:none}.rp .pk-f input[type=range]{accent-color:var(--acc)}.perm{background:var(--warn-soft);border:1px solid var(--warn);border-radius:var(--r-sm);margin-top:10px;padding:10px 12px}.perm-t{font:500 var(--fs-md)var(--sans);color:var(--fg)}.perm-c{font-family:var(--mono);font-size:var(--fs-sm);color:var(--fg-2);word-break:break-all;background:var(--panel-2);border-radius:var(--r-xs);margin:6px 0 8px;padding:6px 8px}.perm-b{display:flex;gap:8px}.perm-b .ok{color:var(--acc);border-color:var(--acc-soft)}.perm-b .danger{color:var(--warn);border-color:var(--warn-soft)}.stdin{display:flex;align-items: center;gap:8px;margin-top:10px}.stdin input{background:var(--panel-2);border:1px solid var(--line);color:var(--fg);border-radius:var(--r-sm);font:var(--fs-md)var(--sans);outline:none;flex:1;padding:8px 10px}.stdin input:focus{border-color:var(--acc)}.stdin button.danger{color:var(--warn);border-color:var(--warn-soft)}.stdin .hint{color:var(--dim);font-size:var(--fs-sm)}.pk-f{display:flex;border-top:1px solid var(--line);gap:8px;padding:12px 14px}.pk-f button{flex:none}.grow{flex:1}.pk-f .primary{background:var(--acc);border-color:var(--acc);color:var(--acc-contrast)}.pk-f .primary:hover{filter:brightness(1.06);color:var(--acc-contrast)}.proj .nm .pdir{opacity:.5;font-weight:400}.proj[draggable]{cursor:grab}.proj.dragging{opacity:.35;background:var(--panel-2);outline:1px dashed var(--acc)}button{background:var(--panel);border:1px solid var(--line);color:var(--fg-2);padding:var(--pad-ctl);border-radius:var(--r-sm);font:600 var(--fs-md)var(--sans);cursor:pointer;transition:border-color var(--t-fast),color var(--t-fast);display:inline-flex;justify-content:center;align-items: center;gap:6px;line-height:1}.pk-h button{padding:6px;line-height:0}button:hover{border-color:var(--acc);color:var(--fg)}main{overflow:auto;padding:var(--pad-page)}h2.hrow{display:flex;flex-wrap:wrap;align-items: center;gap:7px}h2.hrow .s{margin:0}h2{font-size:var(--fs-md);color:var(--dim);text-transform:uppercase;letter-spacing:.07em;display:flex;align-items:baseline;gap:10px;margin:0 0 12px;font-weight:600}h2 span{text-transform:none;letter-spacing:0;color:var(--faint);font-weight:500;font-size:var(--fs-md)}h2 .nav{display:inline-flex;font:500 var(--fs-md)var(--sans);text-transform:none;letter-spacing:0;color:var(--acc);text-decoration:none;border-radius:var(--r-sm);transition:background var(--t-fast);align-items: center;gap:5px;padding:2px 8px}h2 .nav:hover,h2 .nav.on{background:var(--acc-soft)}h2 .nav .ph{display:block}h2 .back{color:var(--fg-2);text-transform:none;letter-spacing:0;font-weight:600;font-size:var(--fs-md);display:inline-flex;border:1px solid var(--line);border-radius:var(--r-pill);background:var(--panel);transition:border-color var(--t-fast),color var(--t-fast);align-items: center;gap:5px;padding:5px 11px 5px 8px}.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);overflow-x:auto}table{border-collapse:collapse;table-layout:fixed;width:100%}.card table{background:var(--panel)}thead th{text-align:left;padding:var(--pad-cell);color:var(--dim);font-weight:500;font-size:var(--fs-sm);border-bottom:1px solid var(--line);background:var(--panel-2);white-space:nowrap}tbody td{padding:var(--pad-cell);border-bottom:1px solid var(--line-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle}tbody tr:last-child td{border-bottom:0}tbody td.td-tools{text-overflow:clip;text-align:center;padding-left:0;padding-right:0;line-height:0}tbody td.td-badge{text-overflow:clip}tbody td.td-badge .badge{margin-right:0}tbody tr{transition:background var(--t-fast)}tbody tr[data-s]{cursor:pointer}tbody tr:hover{background:var(--panel-2)}tbody td.td-lead{overflow:visible}tbody td{--cap:calc(var(--fs-lg)*.352)}tbody td .pg{vertical-align:calc(var(--cap) - 8px)}tbody td .pg:before{content:"";display:block;width:0;height:16px}tbody td>*+.badge{vertical-align:calc(var(--cap) - var(--pill-h)/2)}tbody td:not(.td-tools)>svg.ph[width="12"]{vertical-align:calc(var(--cap) - 6px)}tbody td:not(.td-tools)>svg.ph[width="13"]{vertical-align:calc(var(--cap) - 6.5px)}tbody td:not(.td-tools)>svg.ph[width="14"]{vertical-align:calc(var(--cap) - 7px)}tbody td:not(.td-tools)>svg.ph[width="16"]{vertical-align:calc(var(--cap) - 8px)}.dt thead th{position:relative;user-select:none;-webkit-user-select:none}.dt thead tr:first-child th[data-col]:not(:last-child):after{content:"";position:absolute;border-right:1px solid var(--line);height:50%;top:25%;right:0}.dt thead th[data-sort]{cursor:pointer}.dt thead th[data-sort]:hover{color:var(--fg-2)}.dt thead th.dragging{opacity:.4}.dt .th-l{display:inline-flex;align-items: center;gap:5px}.dt th.num .th-l{justify-content:flex-end;width:100%}.dt .sort{display:inline-block;border-left:4px solid #0000;border-right:4px solid #0000;width:0;height:0}.dt .sort.asc{border-bottom:5px solid var(--acc)}.dt .sort.desc{border-top:5px solid var(--acc)}.dt .th-grip{position:absolute;cursor:col-resize;z-index:2;width:9px;height:100%;top:0;right:-4px}.dt .th-grip:hover{background:linear-gradient(to right,transparent 3px,var(--acc)3px,var(--acc)5px,transparent 5px)}.dt thead th:last-child .th-grip{right:0}.dt thead th:last-child .th-grip:hover{background:linear-gradient(to left,var(--acc)0,var(--acc)2px,transparent 2px)}body.col-resizing,body.col-resizing .dt thead th{cursor:col-resize}.dt .th-tools{text-align:right}.dt .th-tools,.dt .td-tools{position:sticky;z-index:1;right:0}.dt .th-tools{background:var(--panel-2)}.dt .td-tools{background:var(--panel)}tbody tr:hover .td-tools{background:var(--panel-2)}.dt .th-cols{cursor:pointer;color:var(--faint);display:inline-flex}.dt .th-cols:hover{color:var(--fg-2)}.dt tr.filters th{background:var(--panel);padding:4px 8px}.dt tr.filters input{background:var(--panel-2);border:1px solid var(--line);color:var(--fg);border-radius:var(--r-sm);font:var(--fs-sm)var(--mono);outline:none;width:100%;padding:3px 7px}.dt tr.filters input:focus{border-color:var(--acc)}.dt .tbl-empty td{color:var(--dim);text-align:center;cursor:default;padding:18px}td b{color:var(--fg);font-weight:600}td.now,.br{font-family:var(--mono);font-size:var(--fs-mono);color:var(--fg-2)}.br+.badge{margin-left:6px}td.now{color:var(--dim)}td a{color:var(--acc)}.num,th.num{text-align:right}.s{display:inline-block;background:var(--faint);border-radius:50%;flex:none;width:8px;height:8px}.s.active{background:var(--ok);box-shadow:0 0 0 3px var(--ok-soft);animation:pulse var(--t-pulse)ease-in-out infinite}.s.waiting{background:var(--warn);box-shadow:0 0 0 3px var(--warn-soft)}.s.idle{background:var(--faint)}.s.ended{background:var(--line);border:1px solid var(--faint);box-shadow:none}@keyframes pulse{0%,to{box-shadow:0 0 0 3px var(--ok-soft)}50%{box-shadow:0 0 0 5px #0000}}.badge{display:inline-block;font:500 var(--fs-xs)/1.2 var(--sans);border-radius:var(--r-pill);background:var(--panel-2);color:var(--dim);vertical-align:middle;margin-right:4px;padding:4px 8px}.badge.warn{color:var(--warn);background:var(--warn-soft)}.badge.acc{color:var(--acc);background:var(--acc-soft)}.badge.ok{color:var(--ok);background:var(--ok-soft)}.badge.bad{color:var(--bad);background:var(--bad-soft)}.badge.agent{color:var(--violet);background:color-mix(in srgb,var(--violet)14%,transparent);font-weight:600}.err-h{color:var(--bad);align-items: center}.err-h .err-ic{color:var(--bad);flex:none}.err-card{border:1px solid var(--bad);max-width:760px;padding:18px}.err-detail{background:var(--panel-2);border-radius:var(--r-sm);font:var(--fs-mono)/1.5 var(--mono);color:var(--fg-2);white-space:pre-wrap;overflow-x:auto;border:0;max-height:220px;margin:0;padding:10px 12px}.clusters{list-style:none;margin:0;padding:0}.clusters li{display:grid;grid-template-columns:minmax(0,13em)3.2em minmax(0,1fr);border-bottom:1px solid var(--line-2);font-size:var(--fs-md);align-items: center;gap:10px;padding:6px 0}.clusters li:last-child{border-bottom:0}.clusters li>*{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}.clusters li b{font-family:var(--mono);font-size:var(--fs-mono);color:var(--fg)}.clusters li .n{color:var(--fg-2);text-align:right;font-variant-numeric:tabular-nums}.clusters li>span:last-child{color:var(--dim);font-family:var(--mono);font-size:var(--fs-mono)}.plainlist{list-style:none;display:flex;flex-direction:column;gap:6px;margin:0;padding:0}.plainlist li{display:flex;font-size:var(--fs-md);color:var(--fg-2);border-bottom:1px solid var(--line-2);align-items: center;gap:8px;padding:5px 0}.plainlist li:last-child{border-bottom:0}.plainlist li b{font-family:var(--mono);font-size:var(--fs-mono);color:var(--fg);font-weight:600}td.path,span.path{font-family:var(--mono);font-size:var(--fs-mono)}td.path b,span.path b{color:var(--fg);font-weight:600}td.path .dim,span.path .dim{font-size:var(--fs-xs)}.heatlist{list-style:none;display:flex;flex-direction:column;gap:2px;margin:0;padding:0}.heatlist li{position:relative;display:flex;font-size:var(--fs-md);color:var(--fg-2);border-radius:var(--r-sm);overflow:hidden;align-items: center;gap:10px;padding:6px 10px}.heatlist li .bar{position:absolute;width:var(--w);background:var(--acc-soft);border-radius:var(--r-sm);inset:0 auto 0 0}.heatlist li>span.clip{position:relative;font-family:var(--mono);font-size:var(--fs-mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}.heatlist li b{position:relative;font-variant-numeric:tabular-nums;color:var(--fg)}.heatlist li .dim{position:relative;font-size:var(--fs-sm);white-space:nowrap}.empty{color:var(--dim);text-align:center;border:1px dashed var(--line);border-radius:var(--r);background:var(--panel);padding:44px 24px;line-height:1.7}.sess{display:grid;grid-template-columns:1fr 1fr;align-items:stretch;gap:16px}.sess>*{height:calc(100vh - 140px);min-height:320px}.sess.has-stdin>*{height:calc(100vh - 196px)}@media (max-width:980px){.sess{grid-template-columns:1fr}.sess>*{height:auto;max-height:calc(100vh - 140px)}}#log{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);overflow:auto;padding:6px 0}.ev{display:grid;grid-template-columns:56px 54px 1fr;align-items:baseline;gap:10px;padding:5px 14px}.ev:hover{background:var(--panel-2)}.ev .t{color:var(--faint);font:var(--fs-sm)var(--mono)}.ev .k{color:var(--dim);font:500 var(--fs-sm)var(--mono);text-transform:lowercase;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ev .m{white-space:pre-wrap;word-break:break-word;color:var(--fg-2);font-size:var(--fs-menu)}.ev.assistant .k{color:var(--violet)}.ev.assistant .m{color:var(--fg)}.ev.tool\.requested .k{color:var(--acc)}.ev.tool\.requested .m{color:var(--dim);font-family:var(--mono);font-size:var(--fs-mono)}.ev.incident\.opened .k,.ev.incident\.opened .m{color:var(--warn)}.ev.session\.ended .k{color:var(--bad)}.ev.prompt\.submitted .k{color:var(--ok)}.ev.prompt\.submitted .m{color:var(--fg);font-weight:500}.side{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);overflow:auto;padding:14px 18px}.side .stats{display:grid;grid-template-columns:1fr 1fr;gap:0 28px}.stat{display:flex;border-bottom:1px solid var(--line-2);justify-content:space-between;align-items:baseline;padding:7px 0}.stat:last-of-type{border-bottom:0}.stat span{color:var(--dim)}.stat b{font-variant-numeric:tabular-nums;font-weight:600}.stat small{color:var(--faint);font-weight:400}.side h4{color:var(--faint);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.08em;margin:16px 0 6px;font-weight:600}table.mini{table-layout:fixed;border:0;width:100%}table.mini td{font-size:var(--fs-md);vertical-align:middle;border:0;padding:6px 0}table.mini th{vertical-align:middle;padding-top:6px;padding-bottom:6px}table.mini th+th,table.mini td+td{padding-left:14px}table.mini td:first-child{color:var(--fg-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}table.mini td.num{color:var(--dim);width:34px}table.mini td.clip{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bars{display:flex;background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);margin-bottom:var(--gap-sec);align-items: flex-end;gap:5px;height:110px;padding:14px 16px 26px}.bar{position:relative;display:flex;flex:1;align-items: flex-end;min-width:0;height:100%}.bar>div{background:linear-gradient(180deg,var(--acc),color-mix(in srgb,var(--acc)70%,transparent));border-radius:var(--r-xs)var(--r-xs)0 0;transition:opacity var(--t-fast);width:100%;min-height:2px}.bar:hover>div{opacity:.75}.bar span{position:absolute;text-align:center;font:var(--fs-2xs)var(--mono);color:var(--faint);bottom:-20px;left:0;right:0}.cols{display:grid;grid-template-columns:1fr 1fr;gap:var(--gap-sec);align-items: start}.chart{display:block;overflow:visible;width:100%}.chart .grid{stroke:var(--line-2);stroke-width:1;vector-effect:non-scaling-stroke}.chart .base{stroke:var(--line);stroke-width:1;vector-effect:non-scaling-stroke}.chart .ax{fill:var(--faint);font:var(--fs-2xs)var(--mono);text-anchor:start}.chart .ax.mid{text-anchor:middle}.chart .col:hover path{filter:brightness(1.12)}.chart-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);margin-bottom:var(--gap-sec);padding:14px 16px 10px}.chart-card h3{font-size:var(--fs-md);color:var(--fg-2);display:flex;align-items:baseline;gap:10px;margin:0 0 10px;font-weight:600}.chart-card h3 span{color:var(--faint);font-weight:400}.legend{display:flex;font-size:var(--fs-mono);color:var(--fg-2);flex-wrap:wrap;gap:4px 14px;margin:8px 0 0}.legend span{display:inline-flex;align-items: center;gap:6px}.legend i{display:inline-block;border-radius:2px;width:9px;height:9px}.legend em{color:var(--dim);font-variant-numeric:tabular-nums;font-style:normal}.legend.small{font-size:var(--fs-sm);margin-top:6px}#tip{position:fixed;display:none;z-index:50;pointer-events:none;background:var(--fg);color:var(--bg);border-radius:var(--r-sm);font:var(--fs-mono)/1.5 var(--sans);box-shadow:var(--shadow-pop);font-variant-numeric:tabular-nums;max-width:280px;padding:7px 10px;top:0;left:0}#tip b{font-weight:600}#tip span{opacity:.7}#tip i{display:inline-block;border-radius:2px;width:8px;height:8px;margin-right:6px}.spark{display:block;overflow:visible;width:88px;height:20px}.spark path{fill:none;stroke-width:1.5;vector-effect:non-scaling-stroke;stroke-linejoin:round}.comp{display:flex;border-radius:var(--r-xs);overflow:hidden;gap:2px;height:12px;margin-top:4px}.comp i{display:block;transition:filter var(--t-fast);min-width:2px}.comp i:hover{filter:brightness(1.15)}.hbars{display:flex;flex-direction:column;gap:4px}.hb{display:grid;grid-template-columns:minmax(0,120px)1fr auto;font-size:var(--fs-md);align-items: center;gap:8px}.hb .k{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--fg-2)}.hb .t{background:var(--panel-2);overflow:hidden;border-radius:3px;height:8px}.hb .t i{display:block;border-radius:3px;min-width:2px;height:100%}.hb .n{text-align:right;white-space:nowrap;color:var(--dim);font-variant-numeric:tabular-nums;font-size:var(--fs-mono)}.cal{position:relative;padding-top:16px}.cal-months{position:absolute;height:14px;top:0;left:0;right:0}.cal-months span{position:absolute;font:var(--fs-2xs)var(--mono);color:var(--faint)}.cal-grid{display:grid;gap:2px}.cal-col{display:grid;grid-template-rows:repeat(7,1fr);aspect-ratio:1/7;gap:2px}.cal-col i{display:block;background:var(--acc);outline:1px solid var(--line-2);outline-offset:-1px;border-radius:2px}.cal-col i:hover{outline-color:var(--fg)}.chart.line .pt circle{opacity:0}.chart.line .pt:hover circle{opacity:1}.records{display:grid;grid-template-columns:1fr 1fr;gap:12px}.rec{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);display:flex;flex-direction:column;gap:2px;padding:10px 14px}.rec .l{font-size:var(--fs-sm);color:var(--dim);text-transform:uppercase;letter-spacing:.06em;font-weight:600}.rec .v{font-size:var(--fs-lg);color:var(--fg);font-variant-numeric:tabular-nums;font-weight:600}.rec .d{font-size:var(--fs-mono);color:var(--faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hm{display:grid;grid-template-columns:34px 1fr;align-items: center;gap:3px 8px}.hm-lbl{font:var(--fs-xs)var(--mono);color:var(--faint)}.hm-row{display:grid;grid-template-columns:repeat(24,1fr);gap:2px;height:16px}.hm-row i{display:block;background:var(--acc);outline:1px solid var(--line-2);outline-offset:-1px;border-radius:2px}.hm-row i:hover{outline-color:var(--fg)}.hm-hours{position:relative;font:var(--fs-2xs)var(--mono);color:var(--faint);height:14px}.hm-hours span{position:absolute;top:0}.tl{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);padding:8px 16px 12px}.tl-row{display:grid;grid-template-columns:200px 1fr;cursor:pointer;border-radius:var(--r-xs);align-items: center;gap:12px;height:24px}.tl-row.claimlane{cursor:default}.tl-row:hover{background:var(--panel-2)}.tl-row.head{cursor:default;position:sticky;background:var(--panel);z-index:2;height:22px;margin-bottom:4px;top:-20px}.tl-row.head:hover{background:var(--panel)}.tl-name{font-size:var(--fs-md);color:var(--fg-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-left:10px}.tl-track{position:relative;height:100%}.tl-track>i{position:absolute;opacity:.9;border-radius:3px;min-width:3px;height:12px;top:6px}.tl-track>i.live{box-shadow:0 0 0 2px var(--panel),0 0 0 3px currentColor;animation:none}.tl-track>i:hover{opacity:1;filter:brightness(1.1)}.tl-track>i:not([data-tip]){background:var(--line-2);opacity:1;pointer-events:none;border-radius:0;width:1px;min-width:0;height:100%;top:0}.tl-axis{position:absolute;font:var(--fs-2xs)var(--mono);color:var(--faint);inset:0}.tl-axis span{position:absolute;top:3px;transform:translate(-50%)}.tl-now{position:absolute;background:var(--bad);z-index:1;pointer-events:none;width:1px;top:0;bottom:-2000px}.tl-group{position:relative;border-top:1px solid var(--line-2);margin-top:6px;padding-top:4px}.tl-proj{font-size:var(--fs-sm);color:var(--dim);text-transform:uppercase;letter-spacing:.06em;padding:4px 10px 2px;font-weight:600}.tl-proj small{text-transform:none;letter-spacing:0;color:var(--faint);margin-left:8px;font-weight:400}.tl,.tl-group{overflow:hidden}.sw{display:inline-block;vertical-align:baseline;border-radius:2px;width:9px;height:9px;margin-right:7px}.kpis{display:grid;grid-template-columns:repeat(4,1fr);margin-bottom:var(--gap-sec);gap:12px}.kpi{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);padding:12px 14px}.kpi .l{font-size:var(--fs-sm);color:var(--dim);text-transform:uppercase;letter-spacing:.06em;font-weight:600}.kpi .v{font-size:var(--fs-2xl);font-variant-numeric:tabular-nums;color:var(--fg);margin-top:2px;font-weight:600}.kpi .d{font-size:var(--fs-mono);color:var(--faint)}.ph{display:inline-block;vertical-align:-.09em;flex:none}header .nav{display:inline-flex;align-items: center;gap:6px}.navcount{display:inline-block;font:500 var(--fs-xs)var(--sans);text-transform:none;letter-spacing:0;color:var(--warn);background:var(--warn-soft);border-radius:var(--r-pill);padding:4px 8px;line-height:1.2}header .nav .ph{opacity:.75}header .nav.on .ph{opacity:1;color:var(--acc)}.icon-btn{display:inline-flex;border-radius:var(--r-sm);color:var(--dim);background:0 0;border:1px solid #0000;justify-content:center;align-items: center;width:28px;height:28px;padding:0}.icon-btn:hover{background:var(--panel-2);color:var(--fg);border-color:#0000}.icon-btn.on{background:var(--panel-2);color:var(--fg)}header #settings{margin-left:10px}.proj .ph{color:var(--faint)}.proj.sel .ph{color:var(--acc)}.kind{color:var(--faint);margin-right:6px}td .more{opacity:0;color:var(--faint);border-radius:var(--r-xs);transition:opacity var(--t-fast),background var(--t-fast);display:inline-flex;vertical-align:middle;padding:2px;line-height:0}tr:hover td .more,.proj:hover .more,tr.menu-open td .more,.menu-open>.more,.more.menu-open{opacity:1}td .more:hover{background:var(--line);color:var(--fg)}.mini-act{display:inline-flex;color:var(--fg-2);border:1px solid var(--line);border-radius:var(--r-sm);font-size:var(--fs-sm);text-decoration:none;transition:color var(--t-fast),border-color var(--t-fast);align-items: center;padding:2px 9px;font-weight:500}.mini-act:hover{color:var(--acc);border-color:var(--acc)}.mini-act.bad:hover{color:var(--bad);border-color:var(--bad)}.track{display:inline-flex;align-items: center;gap:3px}.track i{background:var(--line);border:1px solid var(--line-2);border-radius:50%;width:7px;height:7px}.track i.on{background:var(--acc);border-color:var(--acc)}.chip.off{opacity:.4;pointer-events:none}.stat .ph{color:var(--faint);margin-right:7px}.empty .ph{display:block;color:var(--faint);margin:0 auto 10px}.empty .px{display:block;image-rendering:pixelated;margin:0 auto 14px}h2 .back:hover{border-color:var(--acc);color:var(--fg)}:root{--fm-surface-bg:var(--panel);--fm-surface-fg:var(--fg);--fm-surface-border:var(--line);--fm-surface-radius:var(--r);--fm-surface-shadow:var(--shadow-pop);--fm-accent:var(--acc);--fm-accent-fg:var(--acc-contrast);--fm-destructive:var(--bad);--fm-muted-fg:var(--dim);--fm-divider-color:var(--line-2);--fm-row-hover-bg:var(--panel-2);--fm-row-active-bg:var(--panel-2);--fm-row-active-fg:var(--fg);--fm-font-size-row:var(--fs-menu);--fm-font-size-caption:var(--fs-sm);--fm-font-size-section:var(--fs-xs);--fm-row-min-h:30px;--fm-row-radius:var(--r-sm)}.fm-row--danger,.fm-row--danger .fm-row__icon{color:var(--bad)}.fm-row--danger:hover{background:var(--bad-soft)}.fm-row[data-pressed=true]{background:var(--acc-soft);color:var(--acc);position:relative;font-weight:600}.fm-row[data-pressed=true]:before{content:"";position:absolute;border-radius:0 var(--r-xs)var(--r-xs)0;background:var(--acc);width:3px;height:58%;top:50%;left:0;transform:translateY(-50%)}.fm-row[data-pressed=true] .fm-ico{color:var(--acc)}.fm-row__icon,.fm-ico{display:inline-flex;justify-content:center;align-items: center}.fm-row__name{flex:auto;min-width:0}.fm-row__caption{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:0 auto;min-width:0;max-width:45%;margin-left:auto}.fm-ico .ph{vertical-align:0}main>h2:not(:first-child),.mt-sec{margin-top:var(--gap-sec)}.pg{display:inline-flex;font-size:var(--fs-md);color:var(--dim);overflow:visible;flex:none;justify-content:center;align-items: center;width:16px;height:16px;line-height:1}.pg-c1{color:var(--c1)}.pg-c2{color:var(--c2)}.pg-c3{color:var(--c3)}.pg-c4{color:var(--c4)}.pg-c5{color:var(--c5)}.pg-c6{color:var(--c6)}.pg-c7{color:var(--c7)}.pg-img{object-fit:cover;border-radius:var(--r-xs);display:block;width:16px;height:16px}.pg-lg{font-size:var(--fs-2xl);border:1px solid var(--line);border-radius:var(--r-sm);background:var(--panel-2);overflow:hidden;width:34px;height:34px;line-height:1}.pg-lg .pg-img{border-radius:0;width:34px;height:34px}.icon-row{display:flex;align-items: center;gap:8px}.icon-row input{flex:1}.icon-row .btn{display:inline-flex;padding:var(--pad-ctl);border:1px solid var(--line);border-radius:var(--r-sm);background:var(--panel-2);color:var(--fg-2);cursor:pointer;font:500 var(--fs-sm)var(--sans);white-space:nowrap;align-items: center;gap:5px}.icon-row .btn:hover{border-color:var(--acc)}.emoji-row{display:flex;flex-wrap:wrap;gap:4px}.emoji-all{overflow:auto;border:1px solid var(--line);border-radius:var(--r-sm);display:grid;gap:6px;max-height:200px;padding:8px}.emoji-sec{font-size:var(--fs-2xs);color:var(--dim);text-transform:uppercase;letter-spacing:.06em;margin-top:4px;font-weight:600}.more-emoji{color:var(--fg-2);font-weight:700}.emoji{display:inline-flex;border:1px solid var(--line);border-radius:var(--r-sm);cursor:pointer;font-size:var(--fs-xl);background:var(--panel-2);color:var(--dim);overflow:hidden;justify-content:center;align-items: center;width:34px;height:34px;line-height:1}.emoji .ph{width:14px;height:14px}.emoji:hover{border-color:var(--acc)}.emoji.on{border-color:var(--acc);background:var(--acc-soft)}.swatches{display:flex;gap:6px}.swatch{cursor:pointer;box-shadow:inset 0 0 0 2px var(--panel);background:currentColor;border:2px solid #0000;border-radius:50%;width:22px;height:22px}.swatch.none{background:var(--panel-2);color:var(--line);box-shadow:inset 0 0 0 1px var(--line)}.swatch:hover{border-color:var(--fg-2)}.swatch.on{border-color:var(--fg)}.pk-b label.chk{display:flex;flex-direction:row;align-items: center;gap:8px}.pk-b label.chk input{width:auto}.kpis-5{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.kpi.hot .v{color:var(--warn)}.kpi.warm .v{color:var(--acc)}.grow{flex:1}.kanban{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin-bottom:var(--gap-sec);align-items: start;gap:12px}.lane{background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r);display:flex;flex-direction:column;gap:8px;min-height:60px;padding:8px}.lane-h{font-size:var(--fs-sm);color:var(--dim);text-transform:uppercase;letter-spacing:.06em;padding:2px 4px;font-weight:600}.lane-h span{color:var(--faint);font-weight:500}.lane-empty{color:var(--faint);text-align:center;padding:10px 0}.lane-more{font-size:var(--fs-xs);padding:2px 4px}.tcard{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-sm);box-shadow:var(--shadow);cursor:pointer;transition:border-color var(--t-fast);padding:8px 10px}.tcard:hover{border-color:var(--acc);outline:none}.tcard:focus-visible{border-color:var(--acc);outline:none}.wt:focus-visible{border-color:var(--acc);outline:none}.more:focus-visible{border-color:var(--acc);outline:none}.more:focus-visible{opacity:1}.tcard.ready{border-color:var(--ok)}.tcard.held{border-color:var(--acc)}.tcard.blocked{border-color:var(--line)}.tcard.done{opacity:.7}.tc-h{display:flex;font-size:var(--fs-sm);align-items: center;gap:8px;margin-bottom:3px}.tc-h .dim{font-family:var(--mono);font-size:var(--fs-2xs);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tc-t{font-size:var(--fs-md);color:var(--fg);display:-webkit-box;-webkit-line-clamp:3;overflow:hidden;-webkit-box-orient:vertical;line-height:1.35}.tc-m{font-size:var(--fs-xs);color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:4px}.tc-g{margin-top:6px}.wtmap{display:flex;margin-bottom:var(--gap-sec);flex-direction:column;gap:14px}.wt-proj{font-size:var(--fs-sm);color:var(--dim);text-transform:uppercase;letter-spacing:.06em;margin-bottom:6px;font-weight:600}.wt-proj span{color:var(--faint);font-weight:500}.wt-tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:8px}.wt{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-sm);box-shadow:var(--shadow);cursor:pointer;transition:border-color var(--t-fast);min-width:0;padding:8px 10px}.wt:hover{border-color:var(--acc)}.wt.main{background:var(--panel-2)}.wt.live{border-color:var(--ok)}.wt.dirty{border-color:var(--warn)}.wt.merged{opacity:.6}.wt-b{display:flex;align-items: center;gap:6px;min-width:0}.wt-b .s{flex:none;margin:0}.wt-b .br{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wt-m{font-size:var(--fs-xs);color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:3px}.wt-m i{font-style:normal}.wt-m i.warn{color:var(--warn)}.wt-m i.acc{color:var(--acc)}.chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:14px}.chip{display:inline-flex;font:500 var(--fs-md)var(--sans);border-radius:var(--r-pill);background:var(--panel);border:1px solid var(--line);color:var(--dim);cursor:pointer;user-select:none;align-items: center;gap:5px;padding:4px 11px}.chip:hover{border-color:var(--acc);color:var(--fg-2)}.chip.on{background:var(--acc-soft);color:var(--acc);border-color:#0000}.seg{display:inline-flex;background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-sm);gap:2px;padding:2px}.seg a{border-radius:var(--r-sm);font:600 var(--fs-md)var(--sans);color:var(--dim);text-decoration:none;transition:color var(--t-fast),background var(--t-fast);letter-spacing:0;text-transform:none;padding:3px 10px}.seg a:hover{color:var(--fg-2)}.seg a.on{background:var(--acc-soft);color:var(--acc)}.chip b{font-weight:700}.wf-steps{display:inline-flex;flex-wrap:wrap;gap:6px}.wfs{font:500 var(--fs-sm)var(--sans);color:var(--dim);background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-pill);white-space:nowrap;padding:1px 8px}.wfs.ok{color:var(--ok);background:var(--ok-soft);border-color:#0000}.wfs.run{color:var(--acc);background:var(--acc-soft);border-color:#0000}.wfs.bad{color:var(--warn);background:var(--warn-soft);border-color:#0000}.tl-track u{position:absolute;opacity:.95;border-radius:1px;width:2px;top:4px;bottom:4px}.tl-track i.thin{opacity:.25}.tl-row.claimlane .tl-name{font-size:var(--fs-2xs);text-transform:uppercase;letter-spacing:.06em}.tl-track i.claim{background:var(--violet);opacity:.6;border-radius:2px;height:4px;top:7px}.tl-track i.claim.orphaned{background:var(--warn);opacity:.9}.tl-track i.claim.expired{background:var(--faint)}.proj-spark{display:inline-flex;opacity:.7;flex:none;width:44px}.proj-spark .spark{width:44px;height:14px}.gh-strip{display:inline-flex;gap:12px;font-weight:400}.gh{font-size:var(--fs-sm);color:var(--dim);display:inline-flex;align-items: center;gap:3px}.gh i{display:inline-block;border-radius:2px;width:7px;height:7px}.gh i.ok{background:var(--ok)}.gh i.bad{background:var(--warn)}.msgs{display:flex;overflow:auto;flex-direction:column;gap:6px;max-height:220px;margin-bottom:8px}.msg{background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-sm);font-size:var(--fs-md);color:var(--fg-2);word-break:break-word;padding:6px 9px}.msg.out{background:var(--acc-soft);border-color:#0000}.msg-f{display:block;font-size:var(--fs-2xs);color:var(--dim);margin-bottom:2px}.msg-compose{display:flex;gap:6px}.msg-compose input{background:var(--panel-2);border:1px solid var(--line);color:var(--fg);border-radius:var(--r-sm);font:400 var(--fs-md)var(--sans);flex:1;min-width:0;padding:7px 10px}.msg-compose input:focus{border-color:var(--acc);outline:none}.msg-compose button{display:inline-flex;background:var(--panel-2);border:1px solid var(--line);color:var(--fg-2);border-radius:var(--r-sm);cursor:pointer;font:500 var(--fs-sm)var(--sans);flex:none;align-items: center;gap:5px;padding:7px 11px}.msg-compose button:hover{color:var(--acc);border-color:var(--acc)}.msg-compose input:disabled,.msg-compose button:disabled{opacity:.45;cursor:not-allowed}.msg-compose button:disabled:hover{color:var(--fg-2);border-color:var(--line)}.msg-hint{display:flex;color:var(--dim);font-size:var(--fs-sm);align-items: center;gap:5px;margin:7px 0 0;line-height:1.4}.msg-hint .ph{color:var(--faint);flex:none}.msg-hint b{color:var(--fg-2);font-weight:600}.pathrow{display:flex;text-align:left;cursor:pointer;background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-sm);color:var(--fg-2);font:400 var(--fs-sm)var(--mono);align-items: center;gap:6px;width:100%;padding:6px 9px}.pathrow:hover{border-color:var(--acc);color:var(--fg)}.pathrow .dir{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dim);flex:0 9999 auto;min-width:0}.pathrow b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:0 auto;min-width:0;font-weight:400}.pathrow .cp{color:var(--faint);flex:none;margin-left:auto}.pathrow:hover .cp{color:var(--acc)}.pathrow.copied{border-color:var(--ok);color:var(--ok)}.pathrow.copied .dir,.pathrow.copied .cp{color:var(--ok)}.pathrow.copy-failed{border-color:var(--bad);color:var(--bad)}.pathrow.copy-failed .dir,.pathrow.copy-failed .cp{color:var(--bad)}.onboard{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);display:flex;flex-direction:column;align-items: flex-start;gap:16px;max-width:640px;margin:40px auto;padding:28px 30px}.onboard h3{font-size:var(--fs-xl);color:var(--fg)}.onboard .px{margin:0 auto}.ob-steps{display:flex;flex-direction:column;gap:12px}.ob-step{display:flex;color:var(--fg-2);align-items: flex-start;gap:12px;line-height:1.5}.ob-step.done{color:var(--dim)}.ob-n{border:1px solid var(--line);display:inline-flex;font:600 var(--fs-sm)var(--sans);color:var(--dim);border-radius:50%;flex:none;justify-content:center;align-items: center;width:22px;height:22px;margin-top:1px}.ob-step.done .ob-n{background:var(--ok-soft);color:var(--ok);border-color:#0000}.nudge{position:fixed;z-index:40;background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow-pop);display:flex;font:var(--fs-md)var(--sans);color:var(--fg-2);align-items: flex-start;gap:12px;max-width:400px;padding:14px 16px;line-height:1.5;bottom:18px;right:18px}.nudge .ic{color:var(--acc);flex:none;margin-top:1px}.nudge b{color:var(--fg);display:block;margin-bottom:2px}.nudge .row{display:flex;white-space:nowrap;align-items: center;gap:8px;margin-top:10px}.nudge button.pri{background:var(--acc-soft);color:var(--acc);border-color:#0000}.nudge a.dim{color:var(--dim);font-size:var(--fs-sm);margin-left:auto}body.nosb .nudge{right:18px}.dt .th-cols{font:inherit;background:0 0;border:0;padding:0}#root{display:contents}.note{font-size:var(--fs-sm);margin-top:10px}.proj,.chip,.h4-act,.nav-group,.mini-act{appearance:none;font:inherit;color:inherit;text-align:left;background:0 0;border:0}.proj{width:100%}.chart-card.flush{margin:0}.stack{display:flex;gap:var(--gap-sec);flex-direction:column;min-width:0}.rule-spark{display:flex;align-items: center;gap:12px;margin-bottom:10px}.rule-spark .dim{font-size:var(--fs-sm)}.rule-shape{font-size:var(--fs-md);margin:0 0 8px}.h4-note{text-transform:none;letter-spacing:0;font-weight:400}.chips.pager{margin-top:10px}.chips.pager .dim{font-size:var(--fs-sm);align-self: center}tr.clickable{cursor:pointer}.link{appearance:none;font:inherit;color:var(--acc);cursor:pointer;text-align:left;background:0 0;border:0;padding:0}.link:hover{text-decoration:underline}.h2-actions{margin-left:auto}.gpager{display:flex;border-top:1px solid var(--line);font-size:var(--fs-sm);align-items: center;gap:10px;padding:7px 12px}.gpager .gp-size{margin-left:auto}.gp-btn{appearance:none;border-radius:var(--r-xs);color:var(--dim);cursor:pointer;display:inline-flex;background:0 0;border:0;padding:2px}.gp-btn:hover:not(:disabled){color:var(--acc);background:var(--panel-2)}.gp-btn:disabled{color:var(--line-2);cursor:default}.addproj{padding:4px 0 8px}.addproj input{background:var(--panel-2);border:1px solid var(--line);color:var(--fg);border-radius:var(--r-xs);font:var(--fs-md)var(--mono);width:100%;padding:5px 7px}.addproj input:focus{outline:none;border-color:var(--acc)}.addproj-err{color:var(--bad);font-size:var(--fs-sm);margin-top:4px}.mt-panel{margin-top:14px}.bipartite{max-width:1100px}.matrix-scroll{overflow:auto}.card-pad{padding:14px}.card-scroll{overflow:auto;max-height:72vh;padding:14px}.graph-key{display:flex;font-size:var(--fs-sm);flex-wrap:wrap;align-items: center;gap:18px;margin-top:10px}.graph-key svg{vertical-align:middle}.edge-key{display:inline-flex;align-items: center;gap:6px}.dag-node{cursor:pointer}.ring-card{margin-bottom:12px}.ring-list{margin:8px 0 0;padding-left:18px}.more{appearance:none;font:inherit;color:inherit;background:0 0;border:0}.pk-sub{flex:1;margin-left:8px}.rp-summary{font-family:var(--mono);font-size:var(--fs-sm);margin-bottom:8px}.rp-range{flex:1;max-width:280px}.df-commits{font-size:var(--fs-sm)}.df-files button{appearance:none;font:inherit;color:inherit;text-align:left;background:0 0;border:0;width:100%}.wn-full{color:var(--dim);font-size:var(--fs-sm);align-self: center}.linkish{font:inherit;cursor:pointer;text-decoration:underline;background:0 0;border:0;padding:0}.linkish:hover{color:var(--fg-2)}