@runwisp/ui 0.13.0 → 0.14.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.
Files changed (60) hide show
  1. package/package.json +40 -45
  2. package/src/astro/CTABand.astro +19 -12
  3. package/src/astro/Hero.astro +3 -3
  4. package/src/astro/SiteFooter.astro +4 -4
  5. package/src/astro/SiteHeader.astro +4 -4
  6. package/src/lib/assets/runwisp-logo.svg +1 -8
  7. package/src/lib/components/AccordionItem.svelte +4 -10
  8. package/src/lib/components/Alert.svelte +11 -11
  9. package/src/lib/components/Avatar.svelte +1 -1
  10. package/src/lib/components/Badge.svelte +13 -13
  11. package/src/lib/components/Breadcrumb.svelte +3 -3
  12. package/src/lib/components/Button.svelte +2 -2
  13. package/src/lib/components/Card.svelte +4 -4
  14. package/src/lib/components/Checkbox.svelte +12 -10
  15. package/src/lib/components/CodeBlock.svelte +7 -13
  16. package/src/lib/components/CronInput.svelte +12 -11
  17. package/src/lib/components/DataGrid.svelte +14 -11
  18. package/src/lib/components/Drawer.svelte +9 -6
  19. package/src/lib/components/Dropdown.svelte +10 -14
  20. package/src/lib/components/DurationInput.svelte +10 -14
  21. package/src/lib/components/EmptyState.svelte +1 -1
  22. package/src/lib/components/ErrorState.svelte +4 -4
  23. package/src/lib/components/FeatureCard.svelte +4 -4
  24. package/src/lib/components/FormField.svelte +4 -6
  25. package/src/lib/components/Heading.svelte +4 -1
  26. package/src/lib/components/Input.svelte +10 -12
  27. package/src/lib/components/Kbd.svelte +1 -1
  28. package/src/lib/components/Link.svelte +2 -3
  29. package/src/lib/components/LinkButton.svelte +2 -2
  30. package/src/lib/components/LogConsole.svelte +22 -21
  31. package/src/lib/components/Logo.svelte +3 -1
  32. package/src/lib/components/Modal.svelte +9 -8
  33. package/src/lib/components/PageContainer.svelte +1 -1
  34. package/src/lib/components/PageHeader.svelte +1 -1
  35. package/src/lib/components/Pagination.svelte +4 -4
  36. package/src/lib/components/Popover.svelte +5 -7
  37. package/src/lib/components/Progress.svelte +6 -4
  38. package/src/lib/components/Prose.svelte +4 -4
  39. package/src/lib/components/Radio.svelte +11 -10
  40. package/src/lib/components/RadioGroup.svelte +3 -5
  41. package/src/lib/components/Select.svelte +21 -31
  42. package/src/lib/components/Separator.svelte +4 -1
  43. package/src/lib/components/Skeleton.svelte +6 -6
  44. package/src/lib/components/StatusIndicator.svelte +7 -15
  45. package/src/lib/components/Table.svelte +1 -1
  46. package/src/lib/components/TableCell.svelte +1 -1
  47. package/src/lib/components/TableRow.svelte +1 -5
  48. package/src/lib/components/Tabs.svelte +10 -11
  49. package/src/lib/components/TaskCard.svelte +7 -4
  50. package/src/lib/components/Textarea.svelte +10 -11
  51. package/src/lib/components/ThemeToggle.svelte +1 -1
  52. package/src/lib/components/ToastContainer.svelte +3 -3
  53. package/src/lib/components/Toggle.svelte +2 -3
  54. package/src/lib/components/Tooltip.svelte +8 -9
  55. package/src/lib/components/button-styles.ts +17 -18
  56. package/src/lib/components/dashboard/RunDetailPanel.svelte +47 -43
  57. package/src/lib/components/dashboard/RunFilterPopover.svelte +17 -11
  58. package/src/lib/components/dashboard/RunsList.svelte +26 -21
  59. package/src/lib/theme-tokens.css +179 -114
  60. package/src/lib/theme.css +49 -35
@@ -62,7 +62,7 @@
62
62
  <div
63
63
  in:fly={{ y: 20, duration: 300 }}
64
64
  out:fade={{ duration: 200 }}
65
- class="pointer-events-auto isolate flex max-w-md min-w-[320px] items-start gap-3 rounded-xl border bg-surface-overlay/95 px-4 py-3 shadow-lg ring-1 ring-on-surface/5 backdrop-blur-md {getColorClasses(
65
+ class="pointer-events-auto isolate flex max-w-md min-w-[320px] items-start gap-3 rounded-[4px] border bg-surface-overlay px-4 py-3 shadow-lg {getColorClasses(
66
66
  toastItem.type,
67
67
  )}"
68
68
  role="alert"
@@ -79,14 +79,14 @@
79
79
  action.onClick();
80
80
  toast.remove(toastItem.id);
81
81
  }}
82
- class="flex-shrink-0 rounded-md px-2 py-1 text-xs font-semibold text-on-surface underline-offset-2 transition-colors hover:bg-surface-sunken hover:underline"
82
+ class="flex-shrink-0 rounded-[3px] px-2 py-1 font-mono text-xs font-semibold text-on-surface underline-offset-2 hover:bg-surface-sunken hover:underline"
83
83
  >
84
84
  {action.label}
85
85
  </button>
86
86
  {/if}
87
87
  <button
88
88
  onclick={() => toast.remove(toastItem.id)}
89
- class="flex-shrink-0 rounded-lg p-1 text-on-surface-muted transition-colors hover:bg-surface-sunken hover:text-on-surface"
89
+ class="flex-shrink-0 rounded-[3px] p-1 text-on-surface-muted hover:bg-surface-sunken hover:text-on-surface"
90
90
  aria-label="Close notification"
91
91
  >
92
92
  <X class="h-4 w-4" aria-hidden="true" />
@@ -55,7 +55,6 @@
55
55
  class="
56
56
  relative inline-flex shrink-0 items-center rounded-full
57
57
  {sizeConfig.track}
58
- transition-colors duration-200
59
58
  focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2
60
59
  {checked ? 'bg-primary' : 'bg-outline-hover'}
61
60
  {disabled ? 'cursor-not-allowed' : 'cursor-pointer'}
@@ -65,7 +64,7 @@
65
64
  class="
66
65
  inline-block rounded-full bg-surface-raised shadow-sm
67
66
  {sizeConfig.thumb}
68
- transform transition-transform duration-200
67
+ transform transition-transform duration-[120ms]
69
68
  {checked ? sizeConfig.translate : 'translate-x-0.5'}
70
69
  "
71
70
  ></span>
@@ -74,7 +73,7 @@
74
73
  {#if label || description}
75
74
  <div class="flex flex-col gap-0.5">
76
75
  {#if label}
77
- <span class="{sizeConfig.text} font-medium text-on-surface">{label}</span>
76
+ <span class="{sizeConfig.text} font-mono font-medium text-on-surface">{label}</span>
78
77
  {/if}
79
78
  {#if description}
80
79
  <span class="text-sm text-on-surface-muted">{description}</span>
@@ -31,10 +31,10 @@
31
31
  };
32
32
 
33
33
  const arrowClasses: Record<TooltipPosition, string> = {
34
- top: "top-full left-1/2 -translate-x-1/2 border-t-mist-800 border-x-transparent border-b-transparent",
35
- bottom: "bottom-full left-1/2 -translate-x-1/2 border-b-mist-800 border-x-transparent border-t-transparent",
36
- left: "left-full top-1/2 -translate-y-1/2 border-l-mist-800 border-y-transparent border-r-transparent",
37
- right: "right-full top-1/2 -translate-y-1/2 border-r-mist-800 border-y-transparent border-l-transparent",
34
+ top: "top-full left-1/2 -translate-x-1/2 border-t-outline border-x-transparent border-b-transparent",
35
+ bottom: "bottom-full left-1/2 -translate-x-1/2 border-b-outline border-x-transparent border-t-transparent",
36
+ left: "left-full top-1/2 -translate-y-1/2 border-l-outline border-y-transparent border-r-transparent",
37
+ right: "right-full top-1/2 -translate-y-1/2 border-r-outline border-y-transparent border-l-transparent",
38
38
  };
39
39
  </script>
40
40
 
@@ -44,12 +44,11 @@
44
44
  <div
45
45
  class="
46
46
  absolute z-50 {positionClasses[position]}
47
- pointer-events-none invisible rounded-lg
48
- bg-mist-800 px-2.5 py-1.5 text-xs
49
- font-medium
47
+ pointer-events-none invisible rounded-[3px]
48
+ border border-outline bg-surface-overlay px-2.5 py-1.5 font-sans
49
+ text-xs
50
50
  {wide ? 'w-max max-w-xs whitespace-normal' : 'whitespace-nowrap'}
51
- text-white opacity-0 transition-opacity
52
- duration-150 group-hover:visible
51
+ text-on-surface opacity-0 group-hover:visible
53
52
  group-hover:opacity-100
54
53
  "
55
54
  role="tooltip"
@@ -7,45 +7,44 @@ export type ButtonSize = "xs" | "sm" | "md" | "lg";
7
7
  export const BUTTON_BASE = `
8
8
  group
9
9
  inline-flex items-center justify-center gap-2
10
- font-medium cursor-pointer select-none
11
- border border-transparent
12
- focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring/10 focus-visible:border-ring
10
+ font-mono font-medium tracking-normal
11
+ cursor-pointer select-none border
12
+ focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2
13
13
  disabled:opacity-50 disabled:cursor-not-allowed
14
- transition-all duration-normal ease-out
15
- active:scale-[0.98]
14
+ active:translate-y-px
16
15
  `;
17
16
 
18
17
  export const BUTTON_VARIANTS: Record<ButtonVariant, string> = {
19
18
  primary: `
20
- bg-primary text-on-primary shadow-sm shadow-primary/20
21
- hover:bg-primary-hover hover:shadow-md hover:shadow-primary/30
19
+ bg-primary text-on-primary border-transparent
20
+ hover:bg-primary-hover
22
21
  active:bg-primary-active
23
22
  `,
24
23
  secondary: `
25
- bg-surface-raised text-on-surface-muted border-outline shadow-sm
26
- hover:bg-surface-sunken hover:text-on-surface hover:border-outline-hover
24
+ bg-surface-raised text-on-surface border-outline
25
+ hover:border-outline-hover hover:text-primary
27
26
  active:bg-surface-sunken
28
27
  `,
29
28
  ghost: `
30
- bg-transparent text-on-surface-muted
29
+ bg-transparent text-on-surface-muted border-transparent
31
30
  hover:bg-surface-sunken hover:text-on-surface
32
31
  active:bg-surface-sunken
33
32
  `,
34
33
  danger: `
35
- bg-danger-surface text-on-danger shadow-sm shadow-danger-surface/20
36
- hover:bg-danger-hover hover:shadow-md hover:shadow-danger-surface/30
34
+ bg-danger-surface text-on-danger border-transparent
35
+ hover:bg-danger-hover
37
36
  active:bg-danger-active
38
37
  `,
39
38
  success: `
40
- bg-success-surface text-on-success shadow-sm shadow-success-surface/20
41
- hover:bg-success-hover hover:shadow-md hover:shadow-success-surface/30
39
+ bg-success-surface text-on-success border-transparent
40
+ hover:bg-success-hover
42
41
  active:bg-success-surface
43
42
  `,
44
43
  };
45
44
 
46
45
  export const BUTTON_SIZES: Record<ButtonSize, string> = {
47
- xs: "text-xs px-2 py-1 rounded-md",
48
- sm: "text-sm px-3 py-1.5 rounded-lg",
49
- md: "text-sm px-4 py-2 rounded-lg",
50
- lg: "text-base px-6 py-3 rounded-xl",
46
+ xs: "text-xs px-2.5 py-1 rounded-[3px]",
47
+ sm: "text-sm px-3 py-1.5 rounded-[3px]",
48
+ md: "text-sm px-4 py-2 rounded-[3px]",
49
+ lg: "text-base px-6 py-2.5 rounded-[3px]",
51
50
  };
@@ -15,7 +15,7 @@
15
15
  RotateCw,
16
16
  RefreshCcw,
17
17
  ChevronDown,
18
- History,
18
+ RotateCcwClock,
19
19
  PanelLeftClose,
20
20
  SlidersHorizontal,
21
21
  Maximize2,
@@ -362,7 +362,7 @@
362
362
  <div class="flex items-start gap-4">
363
363
  <!-- Verdict tile -->
364
364
  <div
365
- class="flex h-[38px] w-[38px] shrink-0 items-center justify-center rounded-[11px] {config.bg} {config.color} ring-1 ring-current/25 ring-inset"
365
+ class="flex h-[38px] w-[38px] shrink-0 items-center justify-center rounded-[4px] {config.bg} {config.color} ring-1 ring-current/25 ring-inset"
366
366
  >
367
367
  <DetailIcon size={20} class={isRunning ? "animate-spin" : ""} />
368
368
  </div>
@@ -388,7 +388,7 @@
388
388
  outcome, so stopped reads amber, not red. -->
389
389
  <Tooltip content={config.description} position="bottom" wide>
390
390
  <span
391
- class="rounded-full border px-2.5 py-0.5 text-2xs font-bold tracking-wider uppercase {config.color} {config.bg} {config.border}"
391
+ class="rounded-[3px] border px-2.5 py-0.5 font-mono text-2xs font-bold tracking-wider uppercase {config.color} {config.bg} {config.border}"
392
392
  >
393
393
  {status.toUpperCase()}
394
394
  </span>
@@ -402,7 +402,7 @@
402
402
  <!-- When the title carries the task name, the run's
403
403
  date/time lives here in the sub-line (otherwise it's
404
404
  already the title, so don't repeat it). -->
405
- <span title={formatFullDateTime(startedAt)}>
405
+ <span class="font-mono" title={formatFullDateTime(startedAt)}>
406
406
  Run · {formatCalendarDate(startedAt)}
407
407
  {formatTimeHM(startedAt)}
408
408
  </span>
@@ -412,7 +412,7 @@
412
412
  type="button"
413
413
  onclick={() => copyRunId(run.id)}
414
414
  title="Copy run ID"
415
- class="inline-flex items-center gap-1.5 rounded-md border border-outline-faint bg-surface-sunken px-1.5 py-0.5 font-mono text-2xs text-on-surface-faint transition-colors hover:border-outline hover:text-on-surface-muted"
415
+ class="inline-flex items-center gap-1.5 rounded-[3px] border border-outline-faint bg-surface-sunken px-1.5 py-0.5 font-mono text-2xs text-on-surface-faint hover:border-outline-hover hover:text-primary"
416
416
  >
417
417
  {#if copiedId}
418
418
  <Check size={11} class="text-success-surface" />Copied
@@ -423,7 +423,7 @@
423
423
  {#if retry}
424
424
  <span class="hidden h-1 w-1 rounded-full bg-outline-faint sm:block"
425
425
  ></span>
426
- <span class="inline-flex items-center gap-1.5">
426
+ <span class="inline-flex items-center gap-1.5 font-mono">
427
427
  <RotateCw size={14} />
428
428
  Retry #{run.retry_attempt}{#if run.retry_of_run_id}
429
429
  <span class="text-on-surface-faint"
@@ -437,7 +437,7 @@
437
437
  <Popover placement="bottom-start">
438
438
  {#snippet trigger()}
439
439
  <span
440
- class="inline-flex cursor-pointer items-center gap-1.5 rounded-full border border-outline-faint bg-surface-sunken px-2.5 py-0.5 text-xs font-medium text-on-surface-muted transition-colors hover:border-outline hover:text-on-surface"
440
+ class="inline-flex cursor-pointer items-center gap-1.5 rounded-[3px] border border-outline-faint bg-surface-sunken px-2.5 py-0.5 font-mono text-xs font-medium text-on-surface-muted hover:border-outline-hover hover:text-primary"
441
441
  title="View run parameters"
442
442
  >
443
443
  <SlidersHorizontal size={12} />
@@ -447,7 +447,7 @@
447
447
  {/snippet}
448
448
  <div class="max-w-md min-w-48">
449
449
  <span
450
- class="text-xs font-semibold tracking-wide text-on-surface-faint uppercase"
450
+ class="font-mono text-xs font-semibold tracking-[0.14em] text-on-surface-faint uppercase"
451
451
  >Parameters</span
452
452
  >
453
453
  <dl
@@ -477,7 +477,7 @@
477
477
  <button
478
478
  type="button"
479
479
  onclick={() => onToggleHistory()}
480
- class="inline-flex items-center justify-center rounded-lg border border-outline-faint bg-surface-raised p-2 text-on-surface-muted transition-colors hover:bg-surface-sunken hover:text-on-surface"
480
+ class="inline-flex items-center justify-center rounded-[3px] border border-outline-faint bg-surface-raised p-2 text-on-surface-muted hover:border-outline-hover hover:bg-surface-sunken hover:text-primary"
481
481
  title={historyVisible ? "Hide run history" : "Show run history"}
482
482
  aria-label={historyVisible
483
483
  ? "Hide run history"
@@ -486,7 +486,7 @@
486
486
  {#if historyVisible}
487
487
  <PanelLeftClose size={15} />
488
488
  {:else}
489
- <History size={15} />
489
+ <RotateCcwClock size={15} />
490
490
  {/if}
491
491
  </button>
492
492
  {/if}
@@ -505,7 +505,7 @@
505
505
  title={serviceStopped
506
506
  ? "Starts the service"
507
507
  : "Cancels and respawns every instance"}
508
- class="inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-lg border border-primary-soft bg-surface-raised px-3 text-sm font-medium text-primary transition-colors hover:bg-primary-soft disabled:cursor-not-allowed disabled:opacity-60"
508
+ class="inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-[3px] border border-primary-soft-border bg-surface-raised px-3 font-mono text-sm font-medium text-primary hover:bg-primary-soft active:translate-y-px disabled:cursor-not-allowed disabled:opacity-60"
509
509
  >
510
510
  {#if serviceStopped}
511
511
  <Play size={15} fill="currentColor" stroke="none" />
@@ -523,7 +523,7 @@
523
523
  onclick={() => onStopService()}
524
524
  disabled={serviceBusy}
525
525
  title="Stops the service for the rest of the daemon's lifetime"
526
- class="inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-lg border border-danger-soft bg-surface-raised px-3 text-sm font-medium text-danger-surface transition-colors hover:bg-danger-soft disabled:cursor-not-allowed disabled:opacity-60"
526
+ class="inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-[3px] border border-danger-soft-border bg-surface-raised px-3 font-mono text-sm font-medium text-danger-surface hover:bg-danger-soft active:translate-y-px disabled:cursor-not-allowed disabled:opacity-60"
527
527
  >
528
528
  <Square size={15} fill="currentColor" stroke="none" />
529
529
  <span class="@max-md:hidden">Stop Service</span>
@@ -534,13 +534,13 @@
534
534
  <!-- Split button: Run (defaults) + an arrow for the
535
535
  reuse-parameters variant, shown only when there is one. -->
536
536
  <div
537
- class="inline-flex overflow-hidden rounded-lg border border-primary-soft"
537
+ class="inline-flex overflow-hidden rounded-[3px] border border-primary-soft-border"
538
538
  >
539
539
  <button
540
540
  type="button"
541
541
  onclick={() => onRun()}
542
542
  title="Run this task now with default options"
543
- class="inline-flex h-9 cursor-pointer items-center gap-1.5 bg-surface-raised px-3 text-sm font-medium text-primary transition-colors hover:bg-primary-soft"
543
+ class="inline-flex h-9 cursor-pointer items-center gap-1.5 bg-surface-raised px-3 font-mono text-sm font-medium text-primary hover:bg-primary-soft active:translate-y-px"
544
544
  >
545
545
  <Play size={15} fill="currentColor" stroke="none" />
546
546
  <span class="@max-md:hidden">Run</span>
@@ -549,7 +549,7 @@
549
549
  <Popover bind:open={runMenuOpen} placement="bottom-end">
550
550
  {#snippet trigger()}
551
551
  <span
552
- class="flex h-9 cursor-pointer items-center border-l border-primary-soft bg-surface-raised px-2 text-primary transition-colors hover:bg-primary-soft"
552
+ class="flex h-9 cursor-pointer items-center border-l border-primary-soft-border bg-surface-raised px-2 text-primary hover:bg-primary-soft"
553
553
  title="More run options"
554
554
  aria-label="More run options"
555
555
  >
@@ -570,7 +570,7 @@
570
570
  />
571
571
  <span class="flex flex-col">
572
572
  <span
573
- class="text-sm font-medium text-on-surface"
573
+ class="font-mono text-sm font-medium text-on-surface"
574
574
  >Run again</span
575
575
  >
576
576
  <span class="text-xs text-on-surface-muted"
@@ -586,7 +586,7 @@
586
586
  <button
587
587
  type="button"
588
588
  onclick={() => onStop(run.id)}
589
- class="inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-lg border border-danger-soft bg-surface-raised px-3 text-sm font-medium text-danger-surface transition-colors hover:bg-danger-soft"
589
+ class="inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-[3px] border border-danger-soft-border bg-surface-raised px-3 font-mono text-sm font-medium text-danger-surface hover:bg-danger-soft active:translate-y-px"
590
590
  >
591
591
  <Square size={15} fill="currentColor" stroke="none" />
592
592
  <span class="@max-md:hidden">Stop</span>
@@ -598,7 +598,7 @@
598
598
  run.task_name,
599
599
  )}/runs/{encodeURIComponent(run.id)}/log/raw"
600
600
  download="{run.task_name}-{run.id}.log"
601
- class="inline-flex items-center justify-center rounded-lg border border-outline-faint bg-surface-raised p-2 text-on-surface-muted transition-colors hover:bg-surface-sunken hover:text-on-surface"
601
+ class="inline-flex items-center justify-center rounded-[3px] border border-outline-faint bg-surface-raised p-2 text-on-surface-muted hover:border-outline-hover hover:bg-surface-sunken hover:text-primary"
602
602
  title="Download the full log (rotated and current parts as one file)"
603
603
  aria-label="Download log"
604
604
  >
@@ -608,7 +608,7 @@
608
608
  <Popover bind:open={confirmDeleteOpen} placement="bottom-end">
609
609
  {#snippet trigger()}
610
610
  <span
611
- class="flex cursor-pointer items-center justify-center rounded-lg border border-outline-faint bg-surface-raised p-2 text-on-surface-muted transition-colors hover:border-danger-soft hover:bg-danger-soft hover:text-danger-surface"
611
+ class="flex cursor-pointer items-center justify-center rounded-[3px] border border-outline-faint bg-surface-raised p-2 text-on-surface-muted hover:border-danger-soft-border hover:bg-danger-soft hover:text-danger-surface"
612
612
  title="Delete this run"
613
613
  aria-label="Delete run"
614
614
  >
@@ -616,7 +616,7 @@
616
616
  </span>
617
617
  {/snippet}
618
618
  <div class="w-60">
619
- <div class="text-sm font-semibold text-on-surface">
619
+ <div class="font-mono text-sm font-semibold text-on-surface">
620
620
  Delete this run?
621
621
  </div>
622
622
  <div class="mt-1 text-xs leading-relaxed text-on-surface-muted">
@@ -651,13 +651,13 @@
651
651
  <!-- Instrument cluster: the run's vital readout — value over a one-word
652
652
  context line, hairline-divided. -->
653
653
  <div
654
- class="mt-4 flex flex-wrap overflow-hidden rounded-xl border border-outline-faint bg-surface-raised"
654
+ class="mt-4 flex flex-wrap overflow-hidden rounded-[4px] border border-outline-faint bg-surface-raised"
655
655
  >
656
656
  <div
657
657
  class="flex min-w-30 flex-1 flex-col gap-0.5 border-l border-outline-faint px-4 py-2.5 first:border-l-0"
658
658
  >
659
659
  <span
660
- class="text-2xs font-bold tracking-wider text-on-surface-faint uppercase"
660
+ class="font-mono text-2xs font-bold tracking-[0.12em] text-on-surface-faint uppercase"
661
661
  >Queued</span
662
662
  >
663
663
  <span
@@ -666,7 +666,7 @@
666
666
  >
667
667
  {formatClockTime(run.created_at)}
668
668
  </span>
669
- <span class="text-2xs text-on-surface-muted"
669
+ <span class="font-mono text-2xs text-on-surface-muted"
670
670
  >+{startDelay ?? "0s"} queued</span
671
671
  >
672
672
  </div>
@@ -675,7 +675,7 @@
675
675
  class="flex min-w-30 flex-1 flex-col gap-0.5 border-l border-outline-faint px-4 py-2.5 first:border-l-0"
676
676
  >
677
677
  <span
678
- class="text-2xs font-bold tracking-wider text-on-surface-faint uppercase"
678
+ class="font-mono text-2xs font-bold tracking-[0.12em] text-on-surface-faint uppercase"
679
679
  >Started</span
680
680
  >
681
681
  <span
@@ -683,7 +683,7 @@
683
683
  >
684
684
  {run.start_at ? formatClockTime(run.start_at) : "—"}
685
685
  </span>
686
- <span class="text-2xs text-on-surface-muted">
686
+ <span class="font-mono text-2xs text-on-surface-muted">
687
687
  {run.start_at ? formatCalendarDate(run.start_at) : "not started"}
688
688
  </span>
689
689
  </div>
@@ -692,7 +692,7 @@
692
692
  class="flex min-w-30 flex-1 flex-col gap-0.5 border-l border-outline-faint px-4 py-2.5 first:border-l-0"
693
693
  >
694
694
  <span
695
- class="text-2xs font-bold tracking-wider text-on-surface-faint uppercase"
695
+ class="font-mono text-2xs font-bold tracking-[0.12em] text-on-surface-faint uppercase"
696
696
  >Ran for</span
697
697
  >
698
698
  <span
@@ -700,7 +700,7 @@
700
700
  >
701
701
  {duration ?? "—"}
702
702
  </span>
703
- <span class="text-2xs text-on-surface-muted">
703
+ <span class="font-mono text-2xs text-on-surface-muted">
704
704
  {isRunning ? "and counting" : run.end_at ? "wall clock" : "—"}
705
705
  </span>
706
706
  </div>
@@ -709,7 +709,7 @@
709
709
  class="flex min-w-30 flex-1 flex-col gap-0.5 border-l border-outline-faint px-4 py-2.5 first:border-l-0"
710
710
  >
711
711
  <span
712
- class="text-2xs font-bold tracking-wider text-on-surface-faint uppercase"
712
+ class="font-mono text-2xs font-bold tracking-[0.12em] text-on-surface-faint uppercase"
713
713
  >Exit</span
714
714
  >
715
715
  <span
@@ -722,26 +722,28 @@
722
722
  <span>{showCode ? run.exit_code : "—"}</span>
723
723
  {#if exitFail}
724
724
  <span
725
- class="rounded bg-danger-soft px-1 py-px text-[9px] font-bold tracking-wide text-danger-surface uppercase"
725
+ class="rounded-[3px] bg-danger-soft px-1 py-px font-mono text-[9px] font-bold tracking-wide text-danger-surface uppercase"
726
726
  >fail</span
727
727
  >
728
728
  {/if}
729
729
  </span>
730
- <span class="text-2xs text-on-surface-muted">{exitSubLabel(status)}</span>
730
+ <span class="font-mono text-2xs text-on-surface-muted"
731
+ >{exitSubLabel(status)}</span
732
+ >
731
733
  </div>
732
734
 
733
735
  <div
734
736
  class="flex min-w-30 flex-1 flex-col gap-0.5 border-l border-outline-faint px-4 py-2.5 first:border-l-0"
735
737
  >
736
738
  <span
737
- class="text-2xs font-bold tracking-wider text-on-surface-faint uppercase"
739
+ class="font-mono text-2xs font-bold tracking-[0.12em] text-on-surface-faint uppercase"
738
740
  >Trigger</span
739
741
  >
740
742
  <span
741
743
  class="font-mono text-base font-medium tracking-tight whitespace-nowrap text-on-surface tabular-nums"
742
744
  >{formatTriggeredByLabel(run.triggered_by)}</span
743
745
  >
744
- <span class="text-2xs text-on-surface-muted"
746
+ <span class="font-mono text-2xs text-on-surface-muted"
745
747
  >{triggerSub(run.triggered_by)}</span
746
748
  >
747
749
  </div>
@@ -761,25 +763,27 @@
761
763
  <div
762
764
  use:maximizePortal={consoleMaximized}
763
765
  class={consoleMaximized
764
- ? "console-zoom fixed inset-3 z-50 flex flex-col overflow-hidden rounded-xl bg-[var(--rw-con-bg)] shadow-2xl ring-1 ring-[rgb(255_255_255_/_0.08)] sm:inset-6"
765
- : "ml-1 flex min-h-[300px] flex-1 flex-col overflow-hidden border-t border-[rgb(255_255_255_/_0.06)] bg-[var(--rw-con-bg)]"}
766
+ ? "console-zoom fixed inset-3 z-50 flex flex-col overflow-hidden rounded-[4px] bg-[var(--rw-con-bg)] shadow-2xl ring-1 ring-[var(--rw-con-gutter)] sm:inset-6"
767
+ : "ml-1 flex min-h-[300px] flex-1 flex-col overflow-hidden border-t border-[var(--rw-con-gutter)] bg-[var(--rw-con-bg)]"}
766
768
  >
767
769
  <div
768
- class="flex shrink-0 items-center justify-between gap-3 border-b border-[rgb(255_255_255_/_0.06)] bg-[var(--rw-con-panel)] px-3.5 py-[9px] font-mono text-[11.5px] text-[var(--rw-con-dim)]"
770
+ class="flex shrink-0 items-center justify-between gap-3 border-b border-[var(--rw-con-gutter)] bg-[var(--rw-con-panel)] px-3.5 py-[9px] font-mono text-[11.5px] text-[var(--rw-con-dim)]"
769
771
  >
770
772
  <div class="flex min-w-0 items-center gap-3">
771
773
  {#if consoleMaximized}
772
774
  <!-- Focus-mode identity: which run is filling the screen -->
773
775
  <span class="flex min-w-0 items-center gap-2">
774
776
  <span class="h-2 w-2 shrink-0 rounded-full {spine}"></span>
775
- <span class="truncate font-medium text-[#b8c5d1]">
777
+ <span class="truncate font-medium text-[var(--rw-con-text)]">
776
778
  {run.task_name}{suffix}
777
779
  </span>
778
780
  <span class="text-[var(--rw-con-gutter)]">·</span>
779
781
  <span class="font-semibold capitalize {config.color}">{status}</span>
780
782
  </span>
781
783
  {:else}
782
- <span class="flex items-center gap-2 font-semibold text-[#98a7b5]">
784
+ <span
785
+ class="flex items-center gap-2 font-semibold text-[var(--rw-con-text)]"
786
+ >
783
787
  <TerminalIcon size={14} class="opacity-70" />
784
788
  Console output
785
789
  </span>
@@ -792,8 +796,8 @@
792
796
  <button
793
797
  type="button"
794
798
  onclick={() => (consoleWrap = !consoleWrap)}
795
- class="flex cursor-pointer items-center gap-1.5 rounded-md px-2 py-1 transition-colors hover:bg-[rgb(255_255_255_/_0.05)] hover:text-[#b8c5d1] {consoleWrap
796
- ? 'text-[#b8c5d1]'
799
+ class="flex cursor-pointer items-center gap-1.5 rounded-[3px] px-2 py-1 hover:bg-[var(--rw-con-gutter)]/30 hover:text-[var(--rw-con-text)] {consoleWrap
800
+ ? 'text-[var(--rw-con-text)]'
797
801
  : 'text-[var(--rw-con-dim)]'}"
798
802
  title={consoleWrap ? "Unwrap lines" : "Wrap long lines"}
799
803
  aria-pressed={consoleWrap}
@@ -805,14 +809,14 @@
805
809
  <button
806
810
  type="button"
807
811
  onclick={() => (consoleMaximized = !consoleMaximized)}
808
- class="flex cursor-pointer items-center gap-1.5 rounded-md px-2 py-1 text-[var(--rw-con-dim)] transition-colors hover:bg-[rgb(255_255_255_/_0.05)] hover:text-[#b8c5d1]"
812
+ class="flex cursor-pointer items-center gap-1.5 rounded-[3px] px-2 py-1 text-[var(--rw-con-dim)] hover:bg-[var(--rw-con-gutter)]/30 hover:text-[var(--rw-con-text)]"
809
813
  title={consoleMaximized ? "Restore console (Esc)" : "Maximize console · F"}
810
814
  aria-label={consoleMaximized ? "Restore console" : "Maximize console"}
811
815
  >
812
816
  {#if consoleMaximized}
813
817
  <Minimize2 size={13} />
814
818
  <span
815
- class="rounded border border-[var(--rw-con-gutter)] px-1.5 text-[10px] tracking-wide"
819
+ class="rounded-[3px] border border-[var(--rw-con-gutter)] px-1.5 text-[10px] tracking-wide"
816
820
  >Esc</span
817
821
  >
818
822
  {:else}
@@ -855,7 +859,7 @@
855
859
  <button
856
860
  type="button"
857
861
  onclick={() => onRunTask()}
858
- class="inline-flex cursor-pointer items-center gap-1.5 rounded-lg border border-primary-soft bg-surface-raised px-3 py-2 text-sm font-medium text-primary transition-colors hover:bg-primary-soft"
862
+ class="inline-flex cursor-pointer items-center gap-1.5 rounded-[3px] border border-primary-soft-border bg-surface-raised px-3 py-2 font-mono text-sm font-medium text-primary hover:bg-primary-soft active:translate-y-px"
859
863
  >
860
864
  <Play size={15} fill="currentColor" stroke="none" />
861
865
  Run task
@@ -874,7 +878,7 @@
874
878
 
875
879
  /* Gentle fade for the maximize backdrop; disabled under reduced motion. */
876
880
  .console-backdrop {
877
- animation: console-backdrop-in 150ms ease-out;
881
+ animation: console-backdrop-in 150ms;
878
882
  }
879
883
  @keyframes console-backdrop-in {
880
884
  from {
@@ -47,10 +47,13 @@
47
47
  filters = $bindable(),
48
48
  showTask = false,
49
49
  tasks = [],
50
+ compact = false,
50
51
  }: {
51
52
  filters: RunsListFilters;
52
53
  showTask?: boolean;
53
54
  tasks?: { name: string }[];
55
+ // Icon-only trigger for narrow rails where a "Filter" label wouldn't fit.
56
+ compact?: boolean;
54
57
  } = $props();
55
58
 
56
59
  // The individual statuses behind the "Advanced" expander, grouped the way
@@ -64,10 +67,11 @@
64
67
 
65
68
  const count = $derived(activeFilterCount(filters) + (showTask && filters.task_name ? 1 : 0));
66
69
 
67
- const headerClass = "text-xs font-semibold tracking-wide text-on-surface-muted uppercase";
68
- const labelClass = "text-2xs text-on-surface-faint uppercase";
70
+ const headerClass =
71
+ "font-mono text-xs font-semibold tracking-[0.14em] text-on-surface-muted uppercase";
72
+ const labelClass = "font-mono text-2xs tracking-[0.12em] text-on-surface-faint uppercase";
69
73
  const selectClass =
70
- "h-9 w-full appearance-none rounded-md border border-outline bg-surface-raised px-2.5 text-sm text-on-surface focus:border-ring focus:outline-none";
74
+ "h-9 w-full appearance-none rounded-[3px] border border-outline bg-surface-raised px-2.5 font-mono text-sm text-on-surface focus:border-ring focus:outline-none";
71
75
 
72
76
  function statusDot(status: RunStatus): string {
73
77
  return RUN_STATUS_CONFIG[status].dot.replace(" animate-pulse", "");
@@ -136,14 +140,16 @@
136
140
  <Popover placement="right-start" mobileSheet>
137
141
  {#snippet trigger()}
138
142
  <span
139
- class="inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md border px-2 text-xs font-medium transition-colors {count >
140
- 0
141
- ? 'border-wisp-300 bg-primary-soft text-primary-soft-text'
142
- : 'border-transparent text-on-surface-muted hover:bg-surface-sunken'}"
143
+ class="inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-[3px] border font-mono text-xs font-medium {compact &&
144
+ count === 0
145
+ ? 'w-7 justify-center px-0'
146
+ : 'px-2'} {count > 0
147
+ ? 'border-primary-soft-border bg-primary-soft text-primary-soft-text'
148
+ : 'border-transparent text-on-surface-muted hover:border-outline-hover hover:bg-surface-sunken hover:text-primary'}"
143
149
  title="Filter runs"
144
150
  >
145
151
  <Funnel size={13} />
146
- Filter
152
+ {#if !compact}Filter{/if}
147
153
  {#if count > 0}
148
154
  <Badge variant="primary" size="sm" class="px-1.5 py-0">{count}</Badge>
149
155
  {/if}
@@ -167,14 +173,14 @@
167
173
  class="size-4 shrink-0 cursor-pointer rounded border-outline accent-primary"
168
174
  />
169
175
  <span class="size-2.5 shrink-0 rounded-full {bucket.dot}"></span>
170
- <span class="text-sm text-on-surface">{bucket.label}</span>
176
+ <span class="font-mono text-sm text-on-surface">{bucket.label}</span>
171
177
  </label>
172
178
  {/each}
173
179
  </div>
174
180
 
175
181
  <details class="mt-0.5" bind:open={advancedOpen}>
176
182
  <summary
177
- class="flex cursor-pointer items-center gap-1 text-2xs font-medium text-on-surface-muted transition-colors select-none marker:content-none hover:text-on-surface [&::-webkit-details-marker]:hidden"
183
+ class="flex cursor-pointer items-center gap-1 font-mono text-2xs font-medium text-on-surface-muted select-none marker:content-none hover:text-on-surface [&::-webkit-details-marker]:hidden"
178
184
  >
179
185
  <ChevronRight size={12} class={advancedOpen ? "rotate-90" : ""} />
180
186
  Advanced — pick exact statuses
@@ -185,7 +191,7 @@
185
191
  <div class="grid grid-cols-2 gap-x-2 gap-y-1">
186
192
  {#each group.values as status (status)}
187
193
  <label
188
- class="flex cursor-pointer items-center gap-1.5 truncate text-xs"
194
+ class="flex cursor-pointer items-center gap-1.5 truncate font-mono text-xs"
189
195
  >
190
196
  <input
191
197
  type="checkbox"