@try-works/dsh-recursive-mode 0.1.12 → 0.1.13

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/lib/client.js CHANGED
@@ -206,6 +206,34 @@ window.__ModuleLoader__.load({
206
206
  subagents
207
207
  };
208
208
  }
209
+ /** Human pill label per kind (neutral renders an empty dash). */
210
+ const PILL_LABELS = {
211
+ locked: "locked",
212
+ "in-progress": "in progress",
213
+ paused: "paused",
214
+ blocked: "blocked",
215
+ tampered: "tampered",
216
+ advisory: "advisory",
217
+ neutral: "—"
218
+ };
219
+ /**
220
+ * Solid-pill kind for a whole run card. Priority: tamper > fully-locked >
221
+ * run-state blocked > run-state paused > still in-progress.
222
+ */
223
+ function cardPill(card) {
224
+ const facts = cardFacts(card);
225
+ if (facts.tampered) return "tampered";
226
+ if (facts.lockValidity === "locked") return "locked";
227
+ if (facts.state === "blocked") return "blocked";
228
+ if (facts.state === "paused") return "paused";
229
+ return "in-progress";
230
+ }
231
+ /** Solid-pill kind for a phase row status string (LOCKED / DRAFT / '—'). */
232
+ function phaseStatusPill(status) {
233
+ if (status === "LOCKED") return "locked";
234
+ if (status === "" || status === "—") return "neutral";
235
+ return "in-progress";
236
+ }
209
237
  /**
210
238
  * Expand a card's phase chain into full inspector rows: the always-shown
211
239
  * '03.5' slot (§11.10 mandatory deviation) plus 01.5 when present, and
@@ -242,15 +270,59 @@ window.__ModuleLoader__.load({
242
270
  return rows;
243
271
  }
244
272
  //#endregion
273
+ //#region src/client/theme.ts
274
+ /**
275
+ * Board/Inspector theme state (run 16 / Paper). Default LIGHT, dark via a
276
+ * header toggle that flips data-theme on the root .rec-board / .rec-inspector.
277
+ * Persisted to localStorage under 'dsh-recursive-theme' (first visit = light).
278
+ */
279
+ const BOARD_THEME_STORAGE_KEY = "dsh-recursive-theme";
280
+ function readInitialTheme() {
281
+ if (typeof localStorage === "undefined") return "light";
282
+ try {
283
+ return localStorage.getItem("dsh-recursive-theme") === "dark" ? "dark" : "light";
284
+ } catch {
285
+ return "light";
286
+ }
287
+ }
288
+ /**
289
+ * Hoisted at the TOP of Board and Inspector (never after an early return — run
290
+ * 0.1.10 invariant). Defaults light, reads a persisted dark on init, and writes
291
+ * the chosen theme back to localStorage.
292
+ */
293
+ function useBoardTheme() {
294
+ const [theme, setTheme] = (0, react.useState)(readInitialTheme);
295
+ const toggle = (0, react.useCallback)(() => setTheme((t) => t === "light" ? "dark" : "light"), []);
296
+ (0, react.useEffect)(() => {
297
+ try {
298
+ localStorage.setItem(BOARD_THEME_STORAGE_KEY, theme);
299
+ } catch {}
300
+ }, [theme]);
301
+ return {
302
+ theme,
303
+ toggle
304
+ };
305
+ }
306
+ /** The shared header toggle button (moon in light, sun in dark). */
307
+ function ThemeToggle({ theme, toggle }) {
308
+ return (0, react.createElement)("button", {
309
+ type: "button",
310
+ className: "rec-theme-toggle",
311
+ onClick: toggle,
312
+ title: theme === "light" ? "Switch to dark theme" : "Switch to light theme",
313
+ "aria-label": "Toggle theme"
314
+ }, theme === "light" ? "☾" : "☀");
315
+ }
316
+ //#endregion
245
317
  //#region src/client/board.tsx
246
318
  /**
247
- * Board overlay (SP2 R1 + run 08 R3 + run 15): the kanban view over the live
248
- * host-route projection. Pure read-only renderer no filesystem, no run-file
249
- * scraping. Cards are grouped by worktree root and mapped to their current-phase
250
- * lane via derive.columnForRun.
319
+ * Board overlay (SP2 R1 + run 08 R3 + run 15/16): kanban over the live
320
+ * host-route projection, class-based grid board with the Paper theme.
321
+ * Pure read-only renderer no filesystem, no run-file scraping.
251
322
  *
252
- * Run 15 (task-board redesign): class-based structure + theme-token stylesheet
253
- * injected once via styles.ts (no inline styles unlocks hover/grid/theme).
323
+ * Run 16 (Paper): data-theme (default light), header theme toggle, workspace
324
+ * path + count chip, solid status pills. useBoardTheme is hoisted ABOVE the
325
+ * early returns (0.1.10 hook invariant).
254
326
  */
255
327
  /** Flatten the worktree-grouped projection into a stable run list. */
256
328
  function listRuns(projection) {
@@ -269,18 +341,36 @@ window.__ModuleLoader__.load({
269
341
  "aria-label": "Close"
270
342
  }, "×");
271
343
  }
344
+ function solidPill$1(kind) {
345
+ return (0, react.createElement)("span", {
346
+ className: "rec-pill",
347
+ "data-pill": kind
348
+ }, PILL_LABELS[kind]);
349
+ }
272
350
  function Board({ snapshot, onOpenInspector, onClose }) {
351
+ const { theme, toggle } = useBoardTheme();
273
352
  if (snapshot === null || snapshot.root === null) return null;
274
353
  const runs = listRuns(snapshot.projection);
354
+ const workspacePath = snapshot.root;
275
355
  const open = (run) => () => onOpenInspector?.({
276
356
  worktreeRoot: run.worktreeRoot,
277
357
  runId: run.runId
278
358
  });
279
359
  if (runs.length === 0) return (0, react.createElement)("div", {
280
360
  className: "rec-board",
361
+ "data-theme": theme,
281
362
  "data-empty": true
282
- }, (0, react.createElement)("header", { className: "rec-board-header" }, (0, react.createElement)("h2", { className: "rec-board-title" }, "Recursive runs"), closeButton$1(onClose)), (0, react.createElement)("p", { className: "rec-board-empty" }, "No recursive runs in this workspace yet."));
283
- return (0, react.createElement)("div", { className: "rec-board" }, (0, react.createElement)("header", { className: "rec-board-header" }, (0, react.createElement)("h2", { className: "rec-board-title" }, "Recursive runs"), (0, react.createElement)("span", { className: "rec-board-count" }, String(runs.length)), closeButton$1(onClose)), (0, react.createElement)("div", { className: "rec-columns" }, KANBAN_LANES.map((lane) => {
363
+ }, (0, react.createElement)("header", { className: "rec-board-header" }, (0, react.createElement)("h2", { className: "rec-board-title" }, "Recursive runs"), (0, react.createElement)("span", { className: "rec-board-path" }, workspacePath), (0, react.createElement)("span", { className: "rec-board-count" }, "0 runs"), (0, react.createElement)(ThemeToggle, {
364
+ theme,
365
+ toggle
366
+ }), closeButton$1(onClose)), (0, react.createElement)("p", { className: "rec-board-empty" }, "No recursive runs in this workspace yet."));
367
+ return (0, react.createElement)("div", {
368
+ className: "rec-board",
369
+ "data-theme": theme
370
+ }, (0, react.createElement)("header", { className: "rec-board-header" }, (0, react.createElement)("h2", { className: "rec-board-title" }, "Recursive runs"), (0, react.createElement)("span", { className: "rec-board-path" }, workspacePath), (0, react.createElement)("span", { className: "rec-board-count" }, runs.length + " runs"), (0, react.createElement)(ThemeToggle, {
371
+ theme,
372
+ toggle
373
+ }), closeButton$1(onClose)), (0, react.createElement)("div", { className: "rec-columns" }, KANBAN_LANES.map((lane) => {
284
374
  const laneRuns = runs.filter((r) => columnForRun(r) === lane.id);
285
375
  return (0, react.createElement)("section", {
286
376
  key: lane.id,
@@ -291,6 +381,7 @@ window.__ModuleLoader__.load({
291
381
  "aria-hidden": true
292
382
  }), (0, react.createElement)("h3", { className: "rec-column-title" }, lane.label), (0, react.createElement)("span", { className: "rec-column-count" }, String(laneRuns.length))), (0, react.createElement)("div", { className: "rec-cards" }, laneRuns.map((run) => {
293
383
  const facts = cardFacts(run);
384
+ const pill = cardPill(run);
294
385
  return (0, react.createElement)("article", {
295
386
  key: run.worktreeRoot + "\0" + run.runId,
296
387
  className: "rec-card",
@@ -299,23 +390,17 @@ window.__ModuleLoader__.load({
299
390
  }, (0, react.createElement)("div", { className: "rec-card-title" }, run.runId), (0, react.createElement)("div", { className: "rec-card-progress" }, (0, react.createElement)("div", {
300
391
  className: "rec-card-progress-fill",
301
392
  style: { width: Math.round(facts.progress * 100) + "%" }
302
- })), (0, react.createElement)("div", { className: "rec-card-meta" }, (0, react.createElement)("span", { className: "rec-card-phase" }, facts.currentPhase ?? "no phases"), facts.tampered && (0, react.createElement)("span", {
303
- className: "rec-badge rec-badge-tamper",
304
- "data-status": run.state,
305
- title: "tampered"
306
- }, "!"), (0, react.createElement)("span", {
307
- className: "rec-badge",
308
- "data-status": run.state
309
- }, run.state)));
393
+ })), (0, react.createElement)("div", { className: "rec-card-meta" }, (0, react.createElement)("span", { className: "rec-card-phase" }, facts.currentPhase ?? "no phases"), solidPill$1(pill)));
310
394
  }), laneRuns.length === 0 && (0, react.createElement)("div", { className: "rec-column-empty" }, "—")));
311
395
  })));
312
396
  }
313
397
  //#endregion
314
398
  //#region src/client/inspector.tsx
315
399
  /**
316
- * Drill-down inspector (SP2 R1 + run 15): centered modal-style detail panel
317
- * (task-board .detail shape) rendering one run's phase chain, lock badges, and
318
- * tamper/gate facts all from the live host-route snapshot, never disk.
400
+ * Drill-down inspector (SP2 R1 + run 15/16): centered modal-style detail panel
401
+ * (Paper .detail shape) with back + close, data-theme (default light), theme
402
+ * toggle, and solid status pills. All from the live host-route snapshot.
403
+ * useBoardTheme is hoisted ABOVE the not-found early return.
319
404
  */
320
405
  function closeButton(onClose) {
321
406
  if (onClose === void 0) return null;
@@ -327,37 +412,35 @@ window.__ModuleLoader__.load({
327
412
  "aria-label": "Close"
328
413
  }, "×");
329
414
  }
330
- function detailShell(runId, onBackToToolDetails, onClose, headerExtra, body) {
331
- return (0, react.createElement)("div", { className: "rec-inspector" }, (0, react.createElement)("div", { className: "rec-detail" }, (0, react.createElement)("div", { className: "rec-detail-header" }, (0, react.createElement)("button", {
415
+ function solidPill(kind) {
416
+ return (0, react.createElement)("span", {
417
+ className: "rec-pill",
418
+ "data-pill": kind
419
+ }, PILL_LABELS[kind]);
420
+ }
421
+ function detailShell(runId, onBackToToolDetails, onClose, headerExtra, body, theme, toggle) {
422
+ return (0, react.createElement)("div", {
423
+ className: "rec-inspector",
424
+ "data-theme": theme
425
+ }, (0, react.createElement)("div", { className: "rec-detail" }, (0, react.createElement)("div", { className: "rec-detail-header" }, (0, react.createElement)("button", {
332
426
  type: "button",
333
427
  className: "rec-back",
334
428
  onClick: onBackToToolDetails
335
- }, "← Back"), (0, react.createElement)("h2", { className: "rec-detail-title" }, runId), headerExtra, closeButton(onClose)), (0, react.createElement)("div", { className: "rec-detail-body" }, body)));
429
+ }, "← Back"), (0, react.createElement)("h2", { className: "rec-detail-title" }, runId), headerExtra, (0, react.createElement)(ThemeToggle, {
430
+ theme,
431
+ toggle
432
+ }), closeButton(onClose)), (0, react.createElement)("div", { className: "rec-detail-body" }, body)));
336
433
  }
337
434
  function Inspector({ runId, worktreeRoot, snapshot, onBackToToolDetails, onClose }) {
435
+ const { theme, toggle } = useBoardTheme();
338
436
  const card = snapshot?.projection?.[worktreeRoot]?.[runId];
339
- if (card === void 0) return detailShell(runId, onBackToToolDetails, onClose, null, (0, react.createElement)("p", { className: "rec-detail-text" }, "Run not found: " + runId));
437
+ if (card === void 0) return detailShell(runId, onBackToToolDetails, onClose, null, (0, react.createElement)("p", { className: "rec-detail-text" }, "Run not found: " + runId), theme, toggle);
340
438
  const facts = cardFacts(card);
341
439
  const rows = expandPhaseRows(card);
342
- const badge = (0, react.createElement)("span", {
343
- className: "rec-badge",
344
- "data-status": card.state
345
- }, facts.state);
346
- const tamper = facts.tampered ? (0, react.createElement)("span", {
347
- className: "rec-badge rec-badge-tamper",
348
- "data-status": card.state
349
- }, "tampered") : null;
350
- return detailShell(runId, onBackToToolDetails, onClose, (0, react.createElement)("span", { style: {
351
- display: "flex",
352
- alignItems: "center",
353
- gap: 6
354
- } }, badge, tamper), (0, react.createElement)("section", { className: "rec-detail-section" }, (0, react.createElement)("h3", {}, "Phases"), rows.map((row) => (0, react.createElement)("div", {
440
+ return detailShell(runId, onBackToToolDetails, onClose, solidPill(cardPill(card)), (0, react.createElement)("section", { className: "rec-detail-section" }, (0, react.createElement)("h3", {}, "Phases"), rows.map((row) => (0, react.createElement)("div", {
355
441
  key: row.phase,
356
442
  className: "rec-phase-row"
357
- }, (0, react.createElement)("span", { className: "rec-phase-id" }, row.phase), (0, react.createElement)("span", { className: "rec-phase-name" }, row.fileName ?? "—"), (0, react.createElement)("span", {
358
- className: "rec-badge",
359
- "data-status": row.status === "LOCKED" ? "complete" : "active"
360
- }, row.status), row.lockHash !== void 0 && (0, react.createElement)("code", { className: "rec-lockhash" }, "#" + row.lockHash.slice(0, 8)))), facts.gateBlocked && (0, react.createElement)("div", { className: "rec-detail-section" }, (0, react.createElement)("h3", {}, "Gate"), (0, react.createElement)("p", { className: "rec-detail-text" }, "Blocked (" + (facts.gateKind ?? "") + ")"))));
443
+ }, (0, react.createElement)("span", { className: "rec-phase-id" }, row.phase), (0, react.createElement)("span", { className: "rec-phase-name" }, row.fileName ?? "—"), solidPill(phaseStatusPill(row.status)), row.lockHash !== void 0 && (0, react.createElement)("code", { className: "rec-lockhash" }, "#" + row.lockHash.slice(0, 8)))), facts.gateBlocked && (0, react.createElement)("div", { className: "rec-detail-section" }, (0, react.createElement)("h3", {}, "Gate"), (0, react.createElement)("p", { className: "rec-detail-text" }, "Blocked (" + (facts.gateKind ?? "") + ")"))), theme, toggle);
361
444
  }
362
445
  //#endregion
363
446
  //#region src/client/strip.tsx
@@ -565,28 +648,138 @@ window.__ModuleLoader__.load({
565
648
  //#endregion
566
649
  //#region src/client/styles.ts
567
650
  /**
568
- * One-shot board/inspector stylesheet injection (run 15). The client bundle is a
569
- * plain CJS closure with NO CSS pipeline (tsdown has no CSS handling), so we
570
- * inject a single <style data-dsh-recursive> element into document.head and
571
- * style via class names + the shell's --dsw-* theme tokens. That unlocks hover,
572
- * grid layout, and light/dark/skin theme followingimpossible with inline
573
- * styles. Idempotent: guarded by document.querySelector, so every registration
574
- * reuses the one element; the returned disposer removes it.
651
+ * One-shot board/inspector stylesheet injection (run 15 + run 16 / Paper).
652
+ * The client bundle is a plain CJS closure with NO CSS pipeline (tsdown), so we
653
+ * inject a single <style data-dsh-recursive> element into document.head.
654
+ *
655
+ * Run 16 (Paper): the design is ported 1:1 DEFAULT LIGHT theme, dark via a
656
+ * data-theme attribute on the .rec-board / .rec-inspector root. Raw --rm3-*
657
+ * tokens live on the scoped roots; semantic --board-* aliases remap under
658
+ * [data-theme='dark']. EVERY component rule consumes ONLY --board-* aliases
659
+ * (never --rm3-* directly). Idempotent injection; disposer removes the element.
575
660
  */
576
661
  const BOARD_CSS = `
577
- /* dsh-recursive board + inspector (theme-token driven, .rec-* scoped) */
662
+ /* ===== dsh-recursive Paper theme (run 16) ===== */
663
+
664
+ /* Raw tokens: light (default) + dark + shared, scoped to the board/inspector. */
665
+ .rec-board, .rec-inspector {
666
+ /* light */
667
+ --rm3-light-background: #FFFFFF;
668
+ --rm3-light-foreground: #111111;
669
+ --rm3-light-card: #FFFFFF;
670
+ --rm3-light-muted: #FAFAFA;
671
+ --rm3-light-muted-foreground: #666666;
672
+ --rm3-light-accent: #F5F5F5;
673
+ --rm3-light-border: #EAEAEA;
674
+ --rm3-light-success: #27A644;
675
+ --rm3-light-warning: #B67A11;
676
+ --rm3-light-error: #D84F6A;
677
+ --rm3-light-advisory: #9664E8;
678
+ --rm3-light-info: #3F87F5;
679
+ --rm3-light-destructive: #B4261A;
680
+ /* dark */
681
+ --rm3-background: #0A0A0A;
682
+ --rm3-foreground: #EDEDED;
683
+ --rm3-card: #0F0F0F;
684
+ --rm3-muted: #141414;
685
+ --rm3-muted-foreground: #9A9A9A;
686
+ --rm3-accent: #1A1A1A;
687
+ --rm3-border: #1F1F1F;
688
+ --rm3-success: #27A644;
689
+ --rm3-warning: #D9A441;
690
+ --rm3-error: #E06C89;
691
+ --rm3-advisory: #B479FF;
692
+ --rm3-info: #6EA8FF;
693
+ /* shared */
694
+ --rm3-font-sans: 'Geist', ui-sans-serif, system-ui, sans-serif;
695
+ --rm3-font-mono: 'Geist Mono', ui-monospace, Menlo, monospace;
696
+ --rm3-text-xs: 12px;
697
+ --rm3-text-sm: 14px;
698
+ --rm3-text-md: 16px;
699
+ --rm3-text-lg: 20px;
700
+ --rm3-text-xl: 28px;
701
+ --rm3-font-weight-regular: 400;
702
+ --rm3-font-weight-medium: 500;
703
+ --rm3-font-weight-semibold: 600;
704
+ --rm3-radius-sm: 5px;
705
+ --rm3-radius-md: 6px;
706
+ --rm3-radius-lg: 8px;
707
+ --rm3-radius-xl: 11px;
708
+ --rm3-space-8: 8px;
709
+ --rm3-space-12: 12px;
710
+ --rm3-space-16: 16px;
711
+ --rm3-space-24: 24px;
712
+ --rm3-space-32: 32px;
713
+ --rm3-tracking-tight: -0.02em;
714
+ --rm3-tracking-mono: 0.02em;
715
+
716
+ /* Semantic aliases (LIGHT default) */
717
+ --board-bg: var(--rm3-light-background);
718
+ --board-fg: var(--rm3-light-foreground);
719
+ --board-card: var(--rm3-light-card);
720
+ --board-muted: var(--rm3-light-muted);
721
+ --board-muted-fg: var(--rm3-light-muted-foreground);
722
+ --board-accent: var(--rm3-light-accent);
723
+ --board-border: var(--rm3-light-border);
724
+ --board-success: var(--rm3-light-success);
725
+ --board-warning: var(--rm3-light-warning);
726
+ --board-error: var(--rm3-light-error);
727
+ --board-advisory: var(--rm3-light-advisory);
728
+ --board-info: var(--rm3-light-info);
729
+ --board-destructive: var(--rm3-light-destructive);
730
+ --board-font-sans: var(--rm3-font-sans);
731
+ --board-font-mono: var(--rm3-font-mono);
732
+ --board-text-xs: var(--rm3-text-xs);
733
+ --board-text-sm: var(--rm3-text-sm);
734
+ --board-text-md: var(--rm3-text-md);
735
+ --board-text-lg: var(--rm3-text-lg);
736
+ --board-text-xl: var(--rm3-text-xl);
737
+ --board-fw-regular: var(--rm3-font-weight-regular);
738
+ --board-fw-medium: var(--rm3-font-weight-medium);
739
+ --board-fw-semibold: var(--rm3-font-weight-semibold);
740
+ --board-radius-sm: var(--rm3-radius-sm);
741
+ --board-radius-md: var(--rm3-radius-md);
742
+ --board-radius-lg: var(--rm3-radius-lg);
743
+ --board-radius-xl: var(--rm3-radius-xl);
744
+ --board-space-8: var(--rm3-space-8);
745
+ --board-space-12: var(--rm3-space-12);
746
+ --board-space-16: var(--rm3-space-16);
747
+ --board-space-24: var(--rm3-space-24);
748
+ --board-space-32: var(--rm3-space-32);
749
+ --board-tracking-tight: var(--rm3-tracking-tight);
750
+ --board-tracking-mono: var(--rm3-tracking-mono);
751
+ }
752
+
753
+ /* Semantic aliases remapped for DARK. */
754
+ .rec-board[data-theme='dark'], .rec-inspector[data-theme='dark'] {
755
+ --board-bg: var(--rm3-background);
756
+ --board-fg: var(--rm3-foreground);
757
+ --board-card: var(--rm3-card);
758
+ --board-muted: var(--rm3-muted);
759
+ --board-muted-fg: var(--rm3-muted-foreground);
760
+ --board-accent: var(--rm3-accent);
761
+ --board-border: var(--rm3-border);
762
+ --board-success: var(--rm3-success);
763
+ --board-warning: var(--rm3-warning);
764
+ --board-error: var(--rm3-error);
765
+ --board-advisory: var(--rm3-advisory);
766
+ --board-info: var(--rm3-info);
767
+ --board-destructive: var(--rm3-error);
768
+ }
769
+
770
+ /* ===== Board ===== */
578
771
  .rec-board {
579
772
  position: fixed;
580
773
  inset: 0;
581
774
  z-index: 9999;
582
- background: var(--dsw-alias-bg-base);
583
- color: var(--dsw-alias-label-primary);
584
- font-family: var(--dsw-font-family);
585
775
  display: flex;
586
776
  flex-direction: column;
587
777
  box-sizing: border-box;
588
- padding: 14px 16px 16px;
589
- gap: 12px;
778
+ padding: var(--board-space-16);
779
+ gap: var(--board-space-12);
780
+ background: var(--board-bg);
781
+ color: var(--board-fg);
782
+ font-family: var(--board-font-sans);
590
783
  pointer-events: auto;
591
784
  overflow: hidden;
592
785
  }
@@ -594,86 +787,119 @@ window.__ModuleLoader__.load({
594
787
  .rec-board-header {
595
788
  display: flex;
596
789
  align-items: center;
597
- gap: 10px;
790
+ gap: var(--board-space-12);
598
791
  flex: none;
599
792
  }
600
793
 
601
794
  .rec-board-title {
602
795
  margin: 0;
603
- font-size: 16px;
604
- font-weight: 700;
605
- color: var(--dsw-alias-label-primary);
796
+ font-size: 22px;
797
+ font-weight: var(--board-fw-semibold);
798
+ letter-spacing: var(--board-tracking-tight);
799
+ color: var(--board-fg);
800
+ white-space: nowrap;
801
+ }
802
+
803
+ .rec-board-path {
804
+ flex: none;
805
+ font-family: var(--board-font-mono);
806
+ font-size: var(--board-text-xs);
807
+ letter-spacing: var(--board-tracking-mono);
808
+ color: var(--board-muted-fg);
809
+ overflow: hidden;
810
+ text-overflow: ellipsis;
606
811
  white-space: nowrap;
812
+ max-width: 40%;
607
813
  }
608
814
 
609
815
  .rec-board-count {
610
816
  flex: none;
611
- font-size: 12px;
612
- color: var(--dsw-alias-label-tertiary);
613
- background: var(--dsw-alias-interactive-bg-hover);
614
- border-radius: 999px;
615
- padding: 1px 8px;
817
+ font-size: var(--board-text-xs);
818
+ font-weight: var(--board-fw-medium);
819
+ color: var(--board-muted-fg);
820
+ background: var(--board-muted);
821
+ border-radius: 9999px;
822
+ padding: 4px 10px;
616
823
  }
617
824
 
618
825
  .rec-board-empty {
619
826
  margin: 0;
620
- padding: 40px;
827
+ padding: var(--board-space-32);
621
828
  text-align: center;
622
- color: var(--dsw-alias-label-tertiary);
829
+ color: var(--board-muted-fg);
623
830
  }
624
831
 
625
832
  .rec-close {
626
- position: absolute;
627
- top: 14px;
628
- right: 16px;
629
- z-index: 1;
630
833
  display: inline-flex;
631
834
  align-items: center;
632
835
  justify-content: center;
633
- width: 26px;
634
- height: 26px;
836
+ width: 28px;
837
+ height: 28px;
635
838
  padding: 0;
839
+ margin-left: auto;
840
+ flex: none;
636
841
  background: transparent;
637
- border: 1px solid var(--dsw-alias-border-l2);
638
- border-radius: 6px;
639
- color: var(--dsw-alias-label-secondary);
842
+ border: 1px solid var(--board-border);
843
+ border-radius: var(--board-radius-md);
844
+ color: var(--board-muted-fg);
640
845
  cursor: pointer;
641
- font-size: 15px;
846
+ font-size: var(--board-text-md);
642
847
  line-height: 1;
643
848
  }
644
849
 
645
850
  .rec-close:hover {
646
- background: var(--dsw-alias-interactive-bg-hover);
647
- color: var(--dsw-alias-label-primary);
851
+ background: var(--board-accent);
852
+ color: var(--board-fg);
853
+ }
854
+
855
+ .rec-theme-toggle {
856
+ display: inline-flex;
857
+ align-items: center;
858
+ justify-content: center;
859
+ width: 28px;
860
+ height: 28px;
861
+ padding: 0;
862
+ flex: none;
863
+ background: transparent;
864
+ border: 1px solid var(--board-border);
865
+ border-radius: var(--board-radius-md);
866
+ color: var(--board-muted-fg);
867
+ cursor: pointer;
868
+ font-size: var(--board-text-md);
869
+ line-height: 1;
870
+ }
871
+
872
+ .rec-theme-toggle:hover {
873
+ background: var(--board-accent);
874
+ color: var(--board-fg);
648
875
  }
649
876
 
650
877
  .rec-columns {
651
878
  display: grid;
652
879
  grid-auto-flow: column;
653
- grid-auto-columns: minmax(240px, 1fr);
654
- gap: 12px;
880
+ grid-auto-columns: minmax(220px, 1fr);
881
+ gap: var(--board-space-12);
655
882
  flex: 1;
656
883
  min-height: 0;
657
884
  overflow-x: auto;
658
885
  overflow-y: hidden;
659
886
  overscroll-behavior-inline: contain;
660
887
  padding-bottom: 6px;
661
- scrollbar-color: var(--dsw-alias-border-l3) var(--dsw-alias-interactive-bg-hover);
888
+ scrollbar-color: var(--board-border) var(--board-accent);
662
889
  scrollbar-width: thin;
663
890
  }
664
891
 
665
892
  .rec-columns::-webkit-scrollbar { height: 10px; }
666
- .rec-columns::-webkit-scrollbar-track { background: var(--dsw-alias-interactive-bg-hover); border-radius: 999px; }
667
- .rec-columns::-webkit-scrollbar-thumb { background: var(--dsw-alias-border-l3); background-clip: content-box; border: 2px solid transparent; border-radius: 999px; }
668
- .rec-columns::-webkit-scrollbar-thumb:hover { background: var(--dsw-alias-border-l3); background-clip: content-box; }
893
+ .rec-columns::-webkit-scrollbar-track { background: var(--board-accent); border-radius: 999px; }
894
+ .rec-columns::-webkit-scrollbar-thumb { background: var(--board-border); border-radius: 999px; }
669
895
 
670
896
  .rec-column {
671
897
  display: flex;
672
898
  flex-direction: column;
673
899
  min-height: 0;
674
- background: var(--dsw-alias-bg-layer-2);
675
- border: 1px solid var(--dsw-alias-border-l1);
676
- border-radius: 12px;
900
+ background: var(--board-muted);
901
+ border: 1px solid var(--board-border);
902
+ border-radius: var(--board-radius-xl);
677
903
  overflow: hidden;
678
904
  }
679
905
 
@@ -681,7 +907,7 @@ window.__ModuleLoader__.load({
681
907
  display: flex;
682
908
  align-items: center;
683
909
  gap: 6px;
684
- padding: 10px 12px;
910
+ padding: var(--board-space-12);
685
911
  flex: none;
686
912
  }
687
913
 
@@ -689,8 +915,8 @@ window.__ModuleLoader__.load({
689
915
  margin: 0;
690
916
  flex: 1;
691
917
  font-size: 13px;
692
- font-weight: 700;
693
- color: var(--dsw-alias-label-primary);
918
+ font-weight: var(--board-fw-semibold);
919
+ color: var(--board-fg);
694
920
  overflow: hidden;
695
921
  text-overflow: ellipsis;
696
922
  white-space: nowrap;
@@ -698,77 +924,71 @@ window.__ModuleLoader__.load({
698
924
 
699
925
  .rec-column-count {
700
926
  flex: none;
701
- font-size: 12px;
702
- color: var(--dsw-alias-label-tertiary);
703
- background: var(--dsw-alias-interactive-bg-hover);
704
- border-radius: 999px;
927
+ font-size: var(--board-text-xs);
928
+ font-weight: var(--board-fw-medium);
929
+ color: var(--board-muted-fg);
930
+ background: var(--board-accent);
931
+ border-radius: 9999px;
705
932
  padding: 1px 8px;
706
933
  }
707
934
 
708
935
  .rec-status-dot {
709
- width: 8px;
710
- height: 8px;
936
+ width: 6px;
937
+ height: 6px;
711
938
  border-radius: 50%;
712
939
  flex: none;
713
940
  }
714
941
 
715
- .rec-status-dot[data-status='new'] { background: var(--dsw-alias-label-tertiary); }
716
- .rec-status-dot[data-status='active'] { background: var(--dsw-alias-state-business-primary); }
717
- .rec-status-dot[data-status='paused'] { background: var(--dsw-alias-state-warn-primary); }
718
- .rec-status-dot[data-status='blocked'] { background: var(--dsw-alias-state-error-primary); }
719
- .rec-status-dot[data-status='complete'] { background: var(--dsw-alias-state-success-primary); }
942
+ .rec-status-dot[data-status='new'] { background: var(--board-muted-fg); }
943
+ .rec-status-dot[data-status='active'] { background: var(--board-info); }
944
+ .rec-status-dot[data-status='paused'] { background: var(--board-warning); }
945
+ .rec-status-dot[data-status='blocked'] { background: var(--board-error); }
946
+ .rec-status-dot[data-status='complete'] { background: var(--board-success); }
720
947
 
721
948
  .rec-cards {
722
949
  display: flex;
723
950
  flex-direction: column;
724
- gap: 8px;
725
- padding: 2px 8px 10px;
951
+ gap: var(--board-space-8);
952
+ padding: 10px;
726
953
  overflow-y: auto;
727
954
  flex: 1;
728
955
  min-height: 0;
729
956
  }
730
957
 
731
958
  .rec-column-empty {
732
- padding: 24px 8px;
959
+ padding: var(--board-space-24) var(--board-space-8);
733
960
  text-align: center;
734
- font-size: 12px;
735
- color: var(--dsw-alias-label-tertiary);
961
+ font-size: var(--board-text-xs);
962
+ color: var(--board-muted-fg);
736
963
  }
737
964
 
738
965
  .rec-card {
739
966
  display: flex;
740
967
  flex-direction: column;
741
- gap: 6px;
742
- padding: 10px 12px;
968
+ gap: var(--board-space-8);
969
+ padding: var(--board-space-12) 14px;
743
970
  text-align: left;
744
- background: var(--dsw-alias-bg-base);
745
- border: 1px solid var(--dsw-alias-border-l2);
746
- border-radius: 10px;
971
+ background: var(--board-card);
972
+ border: 1px solid var(--board-border);
973
+ border-radius: var(--board-radius-lg);
747
974
  cursor: pointer;
748
- color: var(--dsw-alias-label-primary);
975
+ color: var(--board-fg);
749
976
  font-family: inherit;
750
977
  transition: box-shadow 120ms ease, border-color 120ms ease, transform 120ms ease;
751
978
  }
752
979
 
753
980
  .rec-card:hover {
754
- box-shadow: var(--dsw-shadow-lv2);
755
- border-color: var(--dsw-alias-border-l3);
981
+ border-color: var(--board-info);
756
982
  transform: translateY(-1px);
757
983
  }
758
984
 
759
985
  .rec-card:active {
760
- box-shadow: var(--dsw-shadow-lv1);
761
986
  transform: translateY(0);
762
987
  }
763
988
 
764
- .rec-card[data-state='active'] { border-color: var(--dsw-alias-state-business-primary); }
765
- .rec-card[data-state='paused'] { border-color: var(--dsw-alias-state-warn-primary); }
766
- .rec-card[data-state='blocked'] { border-color: var(--dsw-alias-state-error-primary); }
767
- .rec-card[data-state='complete'] { border-color: var(--dsw-alias-state-success-primary); }
768
-
769
989
  .rec-card-title {
770
990
  font-size: 13px;
771
- font-weight: 600;
991
+ font-weight: var(--board-fw-semibold);
772
992
  line-height: 1.35;
773
993
  overflow: hidden;
774
994
  display: -webkit-box;
@@ -778,52 +998,55 @@ window.__ModuleLoader__.load({
778
998
 
779
999
  .rec-card-progress {
780
1000
  height: 6px;
781
- background: var(--dsw-alias-interactive-bg-hover);
1001
+ background: var(--board-accent);
782
1002
  border-radius: 3px;
783
1003
  overflow: hidden;
784
1004
  }
785
1005
 
786
1006
  .rec-card-progress-fill {
787
1007
  height: 100%;
788
- background: var(--dsw-alias-state-business-primary);
1008
+ background: var(--board-info);
789
1009
  }
790
1010
 
791
1011
  .rec-card-meta {
792
1012
  display: flex;
793
1013
  align-items: center;
794
- gap: 8px;
795
- font-size: 11px;
796
- color: var(--dsw-alias-label-tertiary);
1014
+ gap: var(--board-space-8);
797
1015
  }
798
1016
 
799
1017
  .rec-card-phase {
800
1018
  flex: 1;
1019
+ font-family: var(--board-font-mono);
1020
+ font-size: var(--board-text-xs);
1021
+ letter-spacing: var(--board-tracking-mono);
1022
+ color: var(--board-muted-fg);
801
1023
  overflow: hidden;
802
1024
  text-overflow: ellipsis;
803
1025
  white-space: nowrap;
804
1026
  }
805
1027
 
806
- .rec-badge {
1028
+ /* ===== Solid status pill (Paper StatusPill) ===== */
1029
+ .rec-pill {
807
1030
  flex: none;
808
- padding: 2px 10px;
809
- font-size: 12px;
810
- border-radius: 999px;
811
- border: 1px solid var(--dsw-alias-border-l2);
812
- color: var(--dsw-alias-label-secondary);
1031
+ border-radius: 9999px;
1032
+ padding: 4px 10px;
1033
+ font-size: var(--board-text-xs);
1034
+ font-weight: var(--board-fw-medium);
1035
+ line-height: 1;
1036
+ border: none;
1037
+ background: var(--board-muted-fg);
1038
+ color: var(--board-bg);
813
1039
  }
814
1040
 
815
- .rec-badge[data-status='active'] { color: var(--dsw-alias-state-business-primary); border-color: var(--dsw-alias-state-business-primary); }
816
- .rec-badge[data-status='paused'] { color: var(--dsw-alias-state-warn-primary); border-color: var(--dsw-alias-state-warn-primary); }
817
- .rec-badge[data-status='blocked'] { color: var(--dsw-alias-state-error-primary); border-color: var(--dsw-alias-state-error-primary); }
818
- .rec-badge[data-status='complete'] { color: var(--dsw-alias-state-success-primary); border-color: var(--dsw-alias-state-success-primary); }
819
- .rec-badge[data-status='new'] { color: var(--dsw-alias-label-tertiary); }
1041
+ .rec-pill[data-pill='locked'] { background: var(--board-success); color: var(--board-bg); }
1042
+ .rec-pill[data-pill='in-progress'] { background: var(--board-info); color: var(--board-bg); }
1043
+ .rec-pill[data-pill='paused'] { background: var(--board-warning); color: var(--board-bg); }
1044
+ .rec-pill[data-pill='blocked'] { background: var(--board-error); color: var(--board-bg); }
1045
+ .rec-pill[data-pill='tampered'] { background: var(--board-error); color: var(--board-bg); }
1046
+ .rec-pill[data-pill='advisory'] { background: var(--board-advisory); color: var(--board-bg); }
1047
+ .rec-pill[data-pill='neutral'] { background: var(--board-muted-fg); color: var(--board-bg); }
820
1048
 
821
- .rec-badge-tamper {
822
- color: var(--dsw-alias-state-error-primary);
823
- border-color: var(--dsw-alias-state-error-primary);
824
- }
825
-
826
- /* inspector: centered modal-style detail */
1049
+ /* ===== Inspector: centered modal detail ===== */
827
1050
  .rec-inspector {
828
1051
  position: fixed;
829
1052
  inset: 0;
@@ -831,7 +1054,7 @@ window.__ModuleLoader__.load({
831
1054
  display: flex;
832
1055
  align-items: center;
833
1056
  justify-content: center;
834
- background: var(--dsw-alias-bg-mask-1);
1057
+ background: rgba(0, 0, 0, 0.4);
835
1058
  pointer-events: auto;
836
1059
  }
837
1060
 
@@ -840,20 +1063,21 @@ window.__ModuleLoader__.load({
840
1063
  flex-direction: column;
841
1064
  width: min(640px, calc(100vw - 48px));
842
1065
  max-height: calc(100vh - 80px);
843
- background: var(--dsw-alias-bg-base);
844
- border: 1px solid var(--dsw-alias-border-l2);
1066
+ background: var(--board-bg);
1067
+ border: 1px solid var(--board-border);
845
1068
  border-radius: 14px;
846
- box-shadow: var(--dsw-shadow-lv3);
847
- color: var(--dsw-alias-label-primary);
1069
+ box-shadow: 0 24px 64px rgba(0, 0, 0, 0.24);
1070
+ color: var(--board-fg);
1071
+ font-family: var(--board-font-sans);
848
1072
  overflow: hidden;
849
1073
  }
850
1074
 
851
1075
  .rec-detail-header {
852
1076
  display: flex;
853
1077
  align-items: center;
854
- gap: 10px;
855
- padding: 14px 18px;
856
- border-bottom: 1px solid var(--dsw-alias-separator-primary);
1078
+ gap: var(--board-space-12);
1079
+ padding: var(--board-space-16) var(--board-space-16);
1080
+ border-bottom: 1px solid var(--board-border);
857
1081
  flex: none;
858
1082
  }
859
1083
 
@@ -861,7 +1085,8 @@ window.__ModuleLoader__.load({
861
1085
  margin: 0;
862
1086
  flex: 1;
863
1087
  font-size: 15px;
864
- font-weight: 700;
1088
+ font-weight: var(--board-fw-semibold);
1089
+ letter-spacing: var(--board-tracking-tight);
865
1090
  overflow-wrap: anywhere;
866
1091
  }
867
1092
 
@@ -869,26 +1094,26 @@ window.__ModuleLoader__.load({
869
1094
  display: inline-flex;
870
1095
  align-items: center;
871
1096
  gap: 4px;
872
- padding: 5px 12px;
873
- font-size: 12px;
874
- color: var(--dsw-alias-label-primary);
1097
+ padding: 5px var(--board-space-12);
1098
+ font-size: var(--board-text-xs);
1099
+ color: var(--board-fg);
875
1100
  background: transparent;
876
- border: 1px solid var(--dsw-alias-border-l2);
877
- border-radius: 8px;
1101
+ border: 1px solid var(--board-border);
1102
+ border-radius: var(--board-radius-lg);
878
1103
  cursor: pointer;
879
1104
  white-space: nowrap;
880
1105
  }
881
1106
 
882
1107
  .rec-back:hover {
883
- background: var(--dsw-alias-interactive-bg-hover);
1108
+ background: var(--board-accent);
884
1109
  }
885
1110
 
886
1111
  .rec-detail-body {
887
- padding: 14px 18px;
1112
+ padding: var(--board-space-16);
888
1113
  overflow-y: auto;
889
1114
  display: flex;
890
1115
  flex-direction: column;
891
- gap: 16px;
1116
+ gap: var(--board-space-16);
892
1117
  flex: 1;
893
1118
  }
894
1119
 
@@ -900,43 +1125,70 @@ window.__ModuleLoader__.load({
900
1125
 
901
1126
  .rec-detail-section h3 {
902
1127
  margin: 0;
903
- font-size: 12px;
904
- font-weight: 700;
905
- color: var(--dsw-alias-label-tertiary);
1128
+ font-size: var(--board-text-xs);
1129
+ font-weight: var(--board-fw-semibold);
1130
+ color: var(--board-muted-fg);
1131
+ }
1132
+
1133
+ .rec-detail-text {
1134
+ margin: 0;
1135
+ font-size: var(--board-text-sm);
1136
+ color: var(--board-muted-fg);
906
1137
  }
907
1138
 
908
1139
  .rec-phase-row {
909
1140
  display: flex;
910
1141
  align-items: center;
911
- gap: 10px;
912
- padding: 8px 10px;
913
- border: 1px solid var(--dsw-alias-border-l1);
914
- border-radius: 8px;
1142
+ gap: var(--board-space-12);
1143
+ padding: var(--board-space-8) var(--board-space-12);
1144
+ border: 1px solid var(--board-border);
1145
+ border-radius: var(--board-radius-lg);
915
1146
  font-size: 13px;
916
1147
  }
917
1148
 
918
1149
  .rec-phase-id {
919
1150
  min-width: 48px;
920
- font-family: var(--dsw-font-markdown-code-block-small);
921
- color: var(--dsw-alias-state-business-primary);
1151
+ font-family: var(--board-font-mono);
1152
+ font-size: var(--board-text-xs);
1153
+ letter-spacing: var(--board-tracking-mono);
1154
+ color: var(--board-info);
922
1155
  }
923
1156
 
924
1157
  .rec-phase-name {
925
1158
  flex: 1;
926
- color: var(--dsw-alias-label-primary);
1159
+ color: var(--board-fg);
927
1160
  overflow: hidden;
928
1161
  text-overflow: ellipsis;
929
1162
  white-space: nowrap;
930
1163
  }
931
1164
 
932
1165
  .rec-lockhash {
933
- font-family: var(--dsw-font-markdown-code-block-small);
1166
+ font-family: var(--board-font-mono);
934
1167
  font-size: 11px;
935
- color: var(--dsw-alias-label-tertiary);
1168
+ letter-spacing: var(--board-tracking-mono);
1169
+ color: var(--board-muted-fg);
1170
+ }
1171
+
1172
+ /* ===== Strip (session dock) — keeps the shell --dsw-* theme ===== */
1173
+ .rec-badge {
1174
+ flex: none;
1175
+ padding: 2px 10px;
1176
+ font-size: 12px;
1177
+ border-radius: 999px;
1178
+ border: 1px solid var(--dsw-alias-border-l2);
1179
+ color: var(--dsw-alias-label-secondary);
1180
+ }
1181
+ .rec-badge-tamper {
1182
+ color: var(--dsw-alias-state-error-primary);
1183
+ border-color: var(--dsw-alias-state-error-primary);
1184
+ }
1185
+ .rec-badge-gate {
1186
+ color: var(--dsw-alias-state-warn-primary);
1187
+ border-color: var(--dsw-alias-state-warn-primary);
936
1188
  }
937
1189
 
938
1190
  @media (prefers-reduced-motion: reduce) {
939
- .rec-card, .rec-back, .rec-close { transition: none; }
1191
+ .rec-card, .rec-back, .rec-close, .rec-theme-toggle { transition: none; }
940
1192
  }
941
1193
  `;
942
1194
  /**