@tangle-network/charts 0.18.1 → 0.20.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.
@@ -2,7 +2,11 @@
2
2
  * Geometry reads three variables the clock writes every frame: --fw-t (clock ms), --fw-v0 (window start ms)
3
3
  * and --fw-k (px per ms). A mark carries --s and --e (its start and end ms), so growth, playback and zoom
4
4
  * move marks without a React render.
5
- * Type uses four sizes (11, 13, 14, 20 px); spacing sits on a 4 px grid. */
5
+ * Type uses the 12/14/18 px scale; spacing sits on a 4 px grid. */
6
+ /* light-dark() follows the host's Brand theme (data-theme or the light/dark class), not the OS: a light page
7
+ on a dark OS otherwise resolves the dark fallbacks and muted text drops to 2.4:1. */
8
+ :is(:root[data-theme="light"], .light) .fw-root { color-scheme: light; }
9
+ :is(:root[data-theme="dark"], .dark) .fw-root { color-scheme: dark; }
6
10
  .fw-root {
7
11
  --fw-text: var(--text-primary, light-dark(#23232b, #ececf1));
8
12
  --fw-muted: var(--text-muted, light-dark(#5d5d68, #a4a4b0));
@@ -28,7 +32,8 @@
28
32
  --fw-h4: light-dark(#b0418a, #dc72bb);
29
33
  --fw-h5: light-dark(#6d44c7, #ab8cf7);
30
34
  --fw-ease: cubic-bezier(.2, .8, .2, 1);
31
- --fw-bar-h: 16px;
35
+ /* Bar height = row height - 16, so a centered bar sits 8 px from the row edge: 20 px in a 36 px step row. */
36
+ --fw-bar-h: 20px;
32
37
  /* One label column for rows, axis and every lane layer; the agent view caps it lower and drops it on phones. */
33
38
  --fw-label-col: min(var(--fw-name-w), 42%);
34
39
  --fw-bar-shift: 0px;
@@ -45,7 +50,7 @@
45
50
  font-feature-settings: "tnum" 1, "cv11" 1;
46
51
  -webkit-font-smoothing: antialiased;
47
52
  }
48
- .fw-root-agents { --fw-bar-h: 20px; --fw-label-col: min(var(--fw-name-w), 28%); border-radius: 16px; }
53
+ .fw-root-agents { --fw-bar-h: 24px; --fw-label-col: min(var(--fw-name-w), 28%); border-radius: 16px; }
49
54
  .fw-root *, .fw-root *::before, .fw-root *::after { box-sizing: border-box; }
50
55
  .fw-root :is(p, dl, dd, h3, ul) { margin: 0; padding: 0; }
51
56
  .fw-root :is(button, input, select) { font: inherit; color: inherit; }
@@ -57,11 +62,13 @@
57
62
  .fw-root [data-tone="3"] { --tone: var(--fw-h3); }
58
63
  .fw-root [data-tone="4"] { --tone: var(--fw-h4); }
59
64
  .fw-root [data-tone="5"] { --tone: var(--fw-h5); }
65
+ /* Light fills carry enough of the hue to tell agents apart on white (round 8: 24% read as "pale mint on gray"); the outline is
66
+ the full hue, which passes 3:1 against the surface, so every mark keeps its edge. */
60
67
  .fw-root [data-tone] {
61
- --fill: light-dark(color-mix(in oklab, var(--tone) 24%, #fff), color-mix(in oklab, var(--tone) 86%, #000));
62
- --line: light-dark(color-mix(in oklab, var(--tone) 62%, #fff), var(--tone));
63
- --dim: light-dark(color-mix(in oklab, var(--tone) 12%, #fff), color-mix(in oklab, var(--tone) 40%, #17171d));
64
- --dim-line: light-dark(color-mix(in oklab, var(--tone) 36%, #fff), color-mix(in oklab, var(--tone) 55%, #17171d));
68
+ --fill: light-dark(color-mix(in oklab, var(--tone) 42%, #fff), color-mix(in oklab, var(--tone) 86%, #000));
69
+ --line: light-dark(var(--tone), var(--tone));
70
+ --dim: light-dark(color-mix(in oklab, var(--tone) 22%, #fff), color-mix(in oklab, var(--tone) 40%, #17171d));
71
+ --dim-line: light-dark(color-mix(in oklab, var(--tone) 70%, #fff), color-mix(in oklab, var(--tone) 55%, #17171d));
65
72
  }
66
73
 
67
74
  /* Header */
@@ -79,7 +86,8 @@
79
86
  .fw-root .fw-tools { display: flex; align-items: center; gap: 8px; }
80
87
  .fw-root .fw-views { display: inline-flex; padding: 4px; border-radius: 8px; background: var(--fw-well); border: 1px solid var(--fw-border); }
81
88
  .fw-root .fw-view-button { appearance: none; border: 0; background: transparent; height: 24px; padding: 0 12px; border-radius: 6px; font-size: 14px; color: var(--fw-muted); cursor: pointer; transition: background-color 120ms var(--fw-ease), color 120ms var(--fw-ease); }
82
- .fw-root .fw-view-button[aria-checked="true"] { background: var(--fw-surface); color: var(--fw-text); box-shadow: 0 1px 2px rgb(0 0 0 / .12), 0 0 0 1px var(--fw-border); }
89
+ /* The shown view is a state, not a control: no click target, no pointer. */
90
+ .fw-root .fw-view-button[aria-checked="true"] { opacity: 1; cursor: default; background: var(--fw-surface); color: var(--fw-text); box-shadow: 0 1px 2px rgb(0 0 0 / .12), 0 0 0 1px var(--fw-border); }
83
91
  .fw-root .fw-search { position: relative; display: flex; align-items: center; }
84
92
  .fw-root .fw-search-glyph { position: absolute; left: 8px; display: inline-flex; color: var(--fw-muted); pointer-events: none; }
85
93
  .fw-root .fw-search-input { appearance: none; width: 200px; height: 32px; padding: 0 12px 0 28px; border: 1px solid var(--fw-border); border-radius: 8px; background: var(--fw-well); font-size: 14px; }
@@ -97,9 +105,7 @@
97
105
  /* Axis */
98
106
  .fw-root .fw-axis { display: grid; grid-template-columns: var(--fw-label-col) minmax(0, 1fr); height: 32px; color: var(--fw-muted); font-size: 12px; }
99
107
  .fw-root .fw-axis-top { border-bottom: 1px solid var(--fw-border); }
100
- .fw-root .fw-axis-bottom { height: 28px; border-top: 1px solid var(--fw-border); }
101
108
  .fw-root .fw-axis-label { position: relative; display: flex; align-items: center; gap: 8px; padding: 0 12px 0 16px; border-right: 1px solid var(--fw-border); min-width: 0; }
102
- .fw-root .fw-axis-bottom .fw-axis-label { border-right-color: transparent; }
103
109
  .fw-root .fw-branch-controls { margin-left: auto; display: flex; gap: 4px; }
104
110
  .fw-root .fw-text-button { appearance: none; border: 0; background: transparent; height: 24px; padding: 0 8px; border-radius: 6px; font-size: 12px; color: var(--fw-muted); cursor: pointer; white-space: nowrap; }
105
111
  .fw-root .fw-text-button:hover { background: var(--fw-hover); color: var(--fw-text); }
@@ -108,7 +114,6 @@
108
114
  .fw-root .fw-axis-track { position: relative; overflow: hidden; cursor: ew-resize; touch-action: none; }
109
115
  .fw-root .fw-tick { position: absolute; top: 50%; transform: translate(4px, -50%); left: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px); font-variant-numeric: tabular-nums; white-space: nowrap; line-height: 16px; }
110
116
  .fw-root .fw-cursor-handle { position: absolute; width: 9px; height: 9px; border-radius: 50%; background: var(--fw-text); box-shadow: 0 0 0 2px var(--fw-surface); left: calc(var(--fw-pad) + (var(--fw-t) - var(--fw-v0)) * var(--fw-k) * 1px - 4.5px); bottom: -5px; z-index: 3; }
111
- .fw-root .fw-axis-bottom .fw-cursor-handle { top: -5px; bottom: auto; }
112
117
 
113
118
  /* Body */
114
119
  .fw-root .fw-viewport { position: relative; }
@@ -121,8 +126,20 @@
121
126
  .fw-root .fw-marker { --fw-marker: var(--fw-muted); position: absolute; top: 0; bottom: 0; width: 0; border-left: 1px dashed var(--fw-marker); left: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px); }
122
127
  .fw-root .fw-marker[data-tone="ok"] { --fw-marker: var(--fw-ok); }
123
128
  .fw-root .fw-marker[data-tone="failed"] { --fw-marker: var(--fw-failed); }
129
+ /* A pause: the run stood still. A hatched band across every row with its reason on top, never blank space. */
130
+ .fw-root .fw-pause { position: absolute; top: 0; bottom: 0; left: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px); width: calc(max(0, var(--e) - var(--s)) * var(--fw-k) * 1px);
131
+ background: repeating-linear-gradient(-45deg, color-mix(in oklab, var(--fw-text) 9%, transparent) 0 1px, transparent 1px 6px), color-mix(in oklab, var(--fw-text) 4%, transparent);
132
+ border-inline: 1px dashed color-mix(in oklab, var(--fw-text) 24%, transparent); }
133
+ .fw-root .fw-pause-label { position: sticky; top: 4px; display: block; width: max-content; max-width: calc(100% - 8px); margin: 4px auto 0; padding: 0 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
134
+ border-radius: 4px; font-size: 12px; line-height: 20px; color: var(--fw-muted); background: var(--fw-surface); box-shadow: inset 0 0 0 1px var(--fw-border); }
124
135
  .fw-root .fw-marker-label { position: absolute; top: 2px; left: 3px; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 4px; border-radius: 4px; font-size: 12px; line-height: 16px; color: var(--fw-marker); background: var(--fw-surface); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-marker) 40%, transparent); }
125
136
  .fw-root .fw-marker-label-left { left: auto; right: 3px; }
137
+ .fw-root .fw-marker[data-tone="warn"], .fw-root .fw-event[data-tone="warn"] { --fw-marker: var(--fw-amber); }
138
+ /* The event track: one dot per marker on the axis; click or N/P moves the cursor there. */
139
+ .fw-root .fw-event { --fw-marker: var(--fw-muted); position: absolute; bottom: 2px; width: 8px; height: 8px; margin-left: -4px; padding: 0; border: 0; border-radius: 50%; background: var(--fw-marker); box-shadow: 0 0 0 2px var(--fw-surface); cursor: pointer; z-index: 4; left: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px); }
140
+ .fw-root .fw-event[data-tone="ok"] { --fw-marker: var(--fw-ok); }
141
+ .fw-root .fw-event[data-tone="failed"] { --fw-marker: var(--fw-failed); }
142
+ .fw-root .fw-event:hover, .fw-root .fw-event:focus-visible { transform: scale(1.4); outline: 0; }
126
143
  .fw-root .fw-cursor { position: absolute; top: 0; bottom: 0; width: 1px; background: color-mix(in oklab, var(--fw-text) 70%, transparent); left: calc(var(--fw-pad) + (var(--fw-t) - var(--fw-v0)) * var(--fw-k) * 1px); }
127
144
  .fw-root .fw-empty { padding: 40px 16px; text-align: center; color: var(--fw-muted); }
128
145
  .fw-root .fw-sticky { position: absolute; top: 0; left: 0; right: 0; z-index: 2; background: var(--fw-surface); box-shadow: 0 1px 0 var(--fw-border), 0 6px 12px -8px rgb(0 0 0 / .35); }
@@ -132,6 +149,10 @@
132
149
  .fw-root .fw-row:hover { background: var(--fw-hover); }
133
150
  .fw-root .fw-row.fw-active { background: color-mix(in oklab, var(--fw-accent) 7%, transparent); }
134
151
  .fw-root .fw-row[aria-selected="true"] { background: color-mix(in oklab, var(--fw-accent) 11%, transparent); }
152
+ /* A selected agent lifts: an accent edge on its row, and its peers recede so the reader sees what the panels below follow. */
153
+ .fw-root-agents[data-selection] .fw-row[aria-selected="true"] { box-shadow: inset 3px 0 0 var(--fw-accent); }
154
+ .fw-root-agents[data-selection] .fw-row:not([aria-selected="true"]) > [role="gridcell"] { opacity: .45; transition: opacity 160ms var(--fw-ease); }
155
+ .fw-root-agents[data-selection] .fw-row:not([aria-selected="true"]):hover > [role="gridcell"] { opacity: .8; }
135
156
  .fw-root .fw-row:focus-visible { box-shadow: inset 2px 0 0 var(--fw-accent); }
136
157
  .fw-root .fw-sticky-row { background: var(--fw-surface); }
137
158
  .fw-root .fw-label { position: relative; display: flex; align-items: center; gap: 8px; min-width: 0; padding: 0 12px 0 calc(12px + var(--depth) * 16px); border-right: 1px solid var(--fw-border); }
@@ -160,13 +181,14 @@
160
181
  .fw-root .fw-view-agents .fw-label { padding-left: 16px; gap: 12px; border-right: 0; }
161
182
  .fw-root .fw-view-agents .fw-names { flex-direction: column; align-items: flex-start; gap: 0; }
162
183
  .fw-root .fw-view-agents .fw-span-name { font-weight: 600; line-height: 18px; }
184
+ .fw-root .fw-view-agents .fw-subtitle { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fw-muted); font-size: 12px; line-height: 16px; }
163
185
  .fw-root .fw-view-agents .fw-detail { font-size: 12px; line-height: 16px; }
164
- .fw-root .fw-agent-dot { flex: 0 0 8px; width: 8px; height: 8px; border-radius: 50%; background: var(--line, var(--fw-muted)); align-self: flex-start; margin-top: calc((var(--fw-row-h) - 34px) / 2 + 8px); }
186
+ .fw-root .fw-agent-dot { flex: 0 0 8px; width: 8px; height: 8px; border-radius: 50%; background: var(--line, var(--fw-muted)); }
165
187
 
166
188
  /* Lanes and marks */
167
189
  .fw-root .fw-lane { position: relative; overflow: hidden; min-width: 0; }
168
190
  .fw-root .fw-invalid { position: absolute; left: var(--fw-pad); top: 50%; transform: translateY(-50%); color: var(--fw-muted); }
169
- .fw-root :is(.fw-bar, .fw-seg, .fw-end) {
191
+ .fw-root :is(.fw-bar, .fw-seg, .fw-end, .fw-mark) {
170
192
  --x0: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px);
171
193
  --w: calc(max(0, min(var(--e), var(--fw-t)) - var(--s)) * var(--fw-k) * 1px);
172
194
  --on: clamp(0, (var(--fw-t) - var(--s)) * 1000, 1);
@@ -175,19 +197,32 @@
175
197
  left: var(--x0);
176
198
  opacity: var(--on);
177
199
  }
178
- .fw-root :is(.fw-bar, .fw-seg) { height: var(--fw-bar-h); margin-top: calc(var(--fw-bar-h) / -2 + var(--fw-bar-shift)); width: max(var(--w), calc(var(--on) * 3px)); border-radius: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; overflow: hidden; }
200
+ .fw-root .fw-enter > [role="gridcell"] { animation: fw-unfold 220ms var(--fw-ease) var(--fw-enter-delay) both; }
201
+ .fw-root .fw-enter :is(.fw-bar, .fw-seg) { animation: fw-grow 420ms var(--fw-ease) var(--fw-enter-delay) both; }
202
+ .fw-root .fw-enter .fw-end { animation: fw-land 220ms var(--fw-ease) calc(var(--fw-enter-delay) + 300ms) both; }
203
+ .fw-root .fw-settle :is(.fw-bar, .fw-seg) { animation: fw-settle 600ms var(--fw-ease); }
204
+ .fw-root .fw-settle .fw-end { animation: fw-land 260ms var(--fw-ease); }
205
+ /* A live bar grows with the clock instead of stepping each tick. */
206
+ .fw-root .fw-row[data-running] .fw-bar { transition: width 120ms linear; }
207
+ /* A restart: an amber notch through the bar at that moment; the bar keeps its own state. */
208
+ .fw-root .fw-mark { position: absolute; z-index: 2; left: calc(var(--x0) - 1px); width: 2px; top: calc(50% + var(--fw-bar-shift) - var(--fw-bar-h) / 2 - 4px); height: calc(var(--fw-bar-h) + 8px);
209
+ border-radius: 2px; background: var(--fw-amber); box-shadow: 0 0 0 1px var(--fw-surface); opacity: var(--on); pointer-events: auto; }
210
+ /* Centered by top, not a negative margin, so measured spacing stays on the grid. */
211
+ .fw-root :is(.fw-bar, .fw-seg) { top: calc(50% + var(--fw-bar-shift) - var(--fw-bar-h) / 2); height: var(--fw-bar-h); width: max(var(--w), calc(var(--on) * 3px)); border-radius: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; overflow: hidden; }
179
212
  .fw-root .fw-bar { background: var(--fill); box-shadow: inset 0 0 0 1px var(--line); }
180
213
  /* The mark under the pointer lifts: a brighter fill and a ring in its own tone. */
181
214
  .fw-root :is(.fw-bar, .fw-seg):hover { filter: brightness(1.18); box-shadow: inset 0 0 0 1px var(--line), 0 0 0 2px color-mix(in oklab, var(--line) 55%, transparent); z-index: 1; }
182
215
  .fw-root .fw-bar.fw-k-tool { background: var(--dim); box-shadow: inset 0 0 0 1px var(--dim-line); }
183
216
  /* A handoff is a moment: a slim pill in the receiving tone, not a block of work. */
184
- .fw-root .fw-bar.fw-k-handoff { background: var(--line); height: 6px; margin-top: -4px; box-shadow: none; }
217
+ .fw-root .fw-bar.fw-k-handoff { background: var(--line); height: 8px; top: calc(50% + var(--fw-bar-shift) - 4px); box-shadow: none; }
185
218
  .fw-root .fw-bar.fw-k-waiting { background: repeating-linear-gradient(-45deg, var(--fw-hatch) 0 1px, transparent 1px 5px); box-shadow: inset 0 0 0 1px var(--fw-hatch); }
186
219
  .fw-root .fw-bar.fw-k-failed { background: color-mix(in oklab, var(--fw-failed) 22%, var(--fw-surface)); box-shadow: inset 0 0 0 1px var(--fw-failed); color: var(--fw-failed); }
187
220
  .fw-root .fw-bar.fw-k-pipeline { background: linear-gradient(90deg, var(--fw-neutral-bar), color-mix(in oklab, var(--fw-neutral-bar) 55%, var(--fw-surface))); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-text) 12%, transparent); }
188
221
  .fw-root .fw-bar.fw-k-pipeline.fw-has-marks { background: color-mix(in oklab, var(--tone) 9%, transparent); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--tone) 18%, transparent); }
189
222
  .fw-root .fw-bar.fw-k-pipeline.fw-has-agents { background: repeating-linear-gradient(-45deg, var(--fw-hatch) 0 1px, transparent 1px 5px), color-mix(in oklab, var(--fw-text) 4%, transparent); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-text) 12%, transparent); }
190
223
  /* An agent bar with no child marks says who it is by its lane color, never a neutral grey. */
224
+ /* In the agent view the bar's own extent between steps is waiting: hatched in the outcome tone, under the step segments. */
225
+ .fw-root .fw-view-agents .fw-bar.fw-k-pipeline.fw-has-marks { background: repeating-linear-gradient(-45deg, color-mix(in oklab, var(--tone) 28%, transparent) 0 1px, transparent 1px 5px), color-mix(in oklab, var(--tone) 9%, transparent); }
191
226
  .fw-root .fw-view-agents .fw-bar.fw-k-pipeline:not(.fw-has-marks, .fw-has-agents) { background: var(--fill); box-shadow: inset 0 0 0 1px var(--line); }
192
227
  /* A host outcome re-tones the whole lane: dot, bar and marks. */
193
228
  .fw-root [data-outcome="ok"], .fw-root [data-outcome="ok"] [data-tone] { --tone: var(--fw-ok); }
@@ -210,7 +245,7 @@
210
245
  .fw-root .fw-glyph { display: inline-flex; color: currentColor; }
211
246
  .fw-root .fw-glyph svg { width: 11px; height: 11px; stroke-width: 2; }
212
247
  .fw-root .fw-seg-model .fw-glyph, .fw-root .fw-k-model .fw-glyph { color: light-dark(var(--tone), #fff); }
213
- .fw-root .fw-end { display: inline-flex; align-items: center; gap: 8px; margin-top: -12px; height: 20px; left: calc(var(--x0) + max(var(--w), 3px) + 8px); white-space: nowrap; pointer-events: none; }
248
+ .fw-root .fw-end { display: inline-flex; align-items: center; gap: 8px; top: calc(50% + var(--fw-bar-shift) - var(--fw-bar-h) / 2); height: var(--fw-bar-h); left: calc(var(--x0) + max(var(--w), 3px) + 8px); white-space: nowrap; pointer-events: none; }
214
249
  .fw-root .fw-duration { font-size: 12px; color: var(--fw-muted); font-variant-numeric: tabular-nums; }
215
250
  .fw-root .fw-k-failed ~ .fw-end .fw-duration { color: var(--fw-failed); }
216
251
  .fw-root .fw-badge { height: 18px; padding: 0 8px; border-radius: 999px; font-size: 12px; line-height: 16px; font-weight: 600; color: var(--fw-amber); background: color-mix(in oklab, var(--fw-amber) 13%, transparent); border: 1px solid color-mix(in oklab, var(--fw-amber) 28%, transparent); }
@@ -223,6 +258,9 @@
223
258
  opacity: clamp(0, (var(--fw-t) - var(--s)) * 1000, 1);
224
259
  }
225
260
  .fw-root .fw-view-spans .fw-link { opacity: calc(clamp(0, (var(--fw-t) - var(--s)) * 1000, 1) * .7); }
261
+ /* Agent-view connectors stay quiet at 30% until their agent is hovered, pinned or focused. */
262
+ .fw-root .fw-view-agents .fw-link:not(.fw-link-hot) { opacity: calc(clamp(0, (var(--fw-t) - var(--s)) * 1000, 1) * .3); }
263
+ .fw-root .fw-link { transition: opacity 160ms var(--fw-ease); }
226
264
  .fw-root .fw-link-down { left: calc(var(--x) - 8px); border-left-width: 1.5px; border-bottom-left-radius: 6px; }
227
265
  .fw-root .fw-link-up { left: var(--x); border-right-width: 1.5px; border-bottom-right-radius: 6px; }
228
266
  .fw-root .fw-link::before { content: ""; position: absolute; top: -3.5px; width: 5px; height: 5px; border-radius: 50%; background: var(--line); box-shadow: 0 0 0 1.5px var(--fw-surface); }
@@ -233,9 +271,11 @@
233
271
  .fw-root .fw-card-anchor { display: contents; }
234
272
  .fw-root .fw-card { position: absolute; z-index: 20; width: 320px; padding: 12px; border-radius: 12px; background: var(--fw-raised); border: 1px solid var(--fw-border);
235
273
  box-shadow: 0 12px 32px -8px rgb(0 0 0 / .28), 0 2px 6px rgb(0 0 0 / .08); animation: fw-arrive 140ms var(--fw-ease); }
274
+ /* A hover card never covers the next mark: only a pinned card (a dialog) takes the pointer. */
275
+ .fw-root .fw-card[role="tooltip"] { pointer-events: none; }
236
276
  .fw-root .fw-card-above .fw-card { transform: translateY(-100%); animation-name: fw-arrive-above; }
237
277
  .fw-root .fw-card-agent { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 12px; font-weight: 600; }
238
- .fw-root .fw-card-agent .fw-agent-dot { margin-top: 0; align-self: center; }
278
+ .fw-root .fw-card-agent .fw-agent-dot { align-self: center; }
239
279
  .fw-root .fw-card-head { display: flex; align-items: flex-start; gap: 8px; }
240
280
  .fw-root .fw-card-head .fw-icon-tile { flex-basis: 28px; width: 28px; height: 28px; border-radius: 8px; }
241
281
  .fw-root .fw-card-head .fw-icon-tile :is(svg, img) { width: 16px; height: 16px; }
@@ -256,10 +296,13 @@
256
296
  .fw-root .fw-card-text { margin-top: 12px; }
257
297
  .fw-root .fw-card-compact { width: 280px; padding: 12px; }
258
298
  .fw-root .fw-card-compact .fw-card-agent { margin-bottom: 8px; font-size: 14px; line-height: 20px; }
259
- .fw-root .fw-card-who { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
260
- .fw-root .fw-card-cells { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 8px; padding: 8px 12px; border-radius: 8px; background: var(--fw-well); }
299
+ .fw-root .fw-card-who { min-width: 0; flex: 1; overflow: hidden; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
300
+ .fw-root .fw-card-detail { margin: -4px 0 8px 16px; color: var(--fw-muted); font-size: 12px; line-height: 16px; overflow-wrap: anywhere; }
301
+ .fw-root .fw-pill-outcome { color: var(--line); background: color-mix(in oklab, var(--tone) 16%, transparent); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--tone) 35%, transparent); }
302
+ .fw-root .fw-card-cells { display: grid; grid-template-columns: repeat(auto-fit, minmax(72px, 1fr)); gap: 8px; padding: 8px 12px; border-radius: 8px; background: var(--fw-well); }
261
303
  .fw-root .fw-card-cells dt { font-size: 12px; line-height: 16px; color: var(--fw-muted); }
262
304
  .fw-root .fw-card-cells dd { font-size: 14px; line-height: 20px; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
305
+ .fw-root .fw-card-step { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--fw-border); color: var(--fw-muted); font-size: 12px; line-height: 16px; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
263
306
  .fw-root .fw-card-result { margin-top: 8px; font-size: 14px; line-height: 20px; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
264
307
  .fw-root .fw-card-text p { margin-top: 4px; color: var(--fw-text); overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
265
308
 
@@ -284,6 +327,12 @@
284
327
  .fw-root .fw-sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
285
328
 
286
329
  @keyframes fw-spin { to { transform: rotate(360deg); } }
330
+ /* Motion verbs. Grow: an arriving bar extends from its start. Unfold: an arriving row's cells slide in, staggered by
331
+ --fw-enter-delay. Settle: a bar that just finished eases its edge and lands its end label. */
332
+ @keyframes fw-grow { from { clip-path: inset(0 100% 0 0 round 4px); } }
333
+ @keyframes fw-unfold { from { opacity: 0; translate: 0 -4px; } }
334
+ @keyframes fw-land { from { opacity: 0; translate: -6px 0; } }
335
+ @keyframes fw-settle { 40% { filter: brightness(1.3); } }
287
336
  @keyframes fw-pulse { 50% { opacity: .35; } }
288
337
  @keyframes fw-arrive { from { opacity: 0; transform: translateY(4px); } }
289
338
  @keyframes fw-arrive-above { from { opacity: 0; transform: translateY(calc(-100% - 4px)); } }
@@ -311,10 +360,12 @@
311
360
  .fw-root .fw-heading, .fw-root .fw-playback { padding-left: 12px; padding-right: 12px; }
312
361
  }
313
362
 
314
- /* The agent timeline is one quiet surface: no inner rules, more air, the axis under the lanes. */
363
+ /* The agent timeline is one quiet surface: no inner rules; controls and axis sit above the lanes. */
315
364
  .fw-root-agents .fw-heading { border-bottom: 0; padding: 20px 24px 12px; }
316
- .fw-root-agents .fw-axis-bottom { border-top: 0; }
317
- .fw-root-agents .fw-playback { border-top: 0; padding: 8px 24px 20px; }
365
+ .fw-root-agents .fw-axis-top { border-bottom: 0; }
366
+ .fw-root-agents .fw-axis-top .fw-axis-label { border-right-color: transparent; }
367
+ .fw-root-agents .fw-playback { border-top: 0; padding: 0 24px 8px; }
368
+ .fw-root-agents .fw-body { padding-bottom: 12px; }
318
369
  .fw-root-agents .fw-view-agents .fw-label { padding-left: 24px; }
319
370
  .fw-root-agents .fw-zoom, .fw-root-agents .fw-time { display: none; }
320
371
  /* The agent view keeps scrubbing on a hairline track; the lanes above already show the activity. */
@@ -328,13 +379,13 @@
328
379
  (At 768 px a 28% column cut 15 of 17 names on a real 17-agent run.) */
329
380
  @container (max-width: 899px) {
330
381
  /* The root is the queried container, so the variables go on its children. */
331
- .fw-root-agents > * { --fw-label-col: 0px; --fw-bar-shift: 8px; }
382
+ /* In a 40 px row: the name on 0-20 px, a 16 px bar on 20-36 px. */
383
+ .fw-root-agents > * { --fw-label-col: 0px; --fw-bar-shift: 8px; --fw-bar-h: 16px; }
332
384
  .fw-root-agents .fw-view-agents .fw-names { flex-direction: row; align-items: baseline; gap: 8px; min-width: 0; }
333
- .fw-root-agents .fw-view-agents .fw-agent-dot { align-self: center; margin-top: 0; }
334
385
  /* The label leaves the grid flow, so the lane must claim the track column itself. */
335
386
  .fw-root-agents .fw-view-agents .fw-lane { grid-column: 2; }
336
387
  /* Elbows pass behind the name, not through its letters. A transform or layout containment would make each row
337
388
  its own stacking context and trap the name under the connector layer, so stacked rows place by top instead. */
338
389
  .fw-root-agents .fw-view-agents .fw-row { transform: none; top: var(--row-y); contain: style; }
339
- .fw-root-agents .fw-view-agents .fw-label { position: absolute; z-index: 3; top: 4px; left: 0; height: 18px; max-width: calc(100% - var(--fw-pad)); padding: 0 8px 0 var(--fw-pad); gap: 8px; align-items: center; pointer-events: none; overflow: hidden; border-radius: 0 4px 4px 0; background: var(--fw-surface); }
390
+ .fw-root-agents .fw-view-agents .fw-label { position: absolute; z-index: 3; top: 0; left: 0; height: 20px; max-width: calc(100% - var(--fw-pad)); padding: 0 8px 0 var(--fw-pad); gap: 8px; align-items: center; pointer-events: none; overflow: hidden; border-radius: 0 4px 4px 0; background: var(--fw-surface); }
340
391
  }
@@ -1,4 +1,4 @@
1
- import { B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, O as YTarget, S as ChartMark, T as MarkerShape, a as TimelineLane, b as BandKind, c as TimelineTick, g as TickOutcome, i as FlowTrace, k as YTick, o as TimelineOptions, r as FlowSpan, s as TimelineSpan, t as FlowMarker, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph } from "../flow-trace-BYKE-PMb.js";
1
+ import { B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, O as YTarget, S as ChartMark, T as MarkerShape, a as TimelineLane, b as BandKind, c as TimelineTick, g as TickOutcome, i as FlowTrace, k as YTick, o as TimelineOptions, r as FlowSpan, s as TimelineSpan, t as FlowMarker, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph } from "../flow-trace-Sr8GtLm0.js";
2
2
  import { CSSProperties, ReactElement, ReactNode } from "react";
3
3
  //#region src/react/sparkline.d.ts
4
4
  type SparklineDirection = "rising" | "falling" | "flat";
@@ -369,11 +369,21 @@ interface FlowWaterfallProps {
369
369
  maxHeight?: number;
370
370
  /** Called when a row is opened or a bar is pinned, with that row's span; the built-in behavior still runs. */
371
371
  onSelect?: (span: FlowSpan) => void;
372
- /** Labelled instants, such as releases, drawn across the rows on the trace clock. */
372
+ /** Labelled instants, such as releases, drawn across the rows and as event dots on the axis; click or N/P jumps to one. */
373
373
  markers?: FlowMarker[];
374
+ /** The time the reader moved to, in trace ms; `null` when following live or showing the whole trace. */
375
+ onTimeChange?: (t: number | null) => void;
376
+ /** What a bar's color means: the agent (default), whose hue its steps and handoffs share, with the outcome on the row dot, legend and
377
+ * crash glyph; or its `outcome`. */
378
+ agentFill?: 'outcome' | 'agent';
379
+ /** The row the host has selected, such as the agent whose transcript is open: it lifts and, in the agent view, its peers dim.
380
+ * A pinned card alone only highlights its row, so the rest of the run stays readable around it. */
381
+ selectedId?: string;
382
+ /** Escape clears the host's selection, after closing any open card. */
383
+ onDeselect?: () => void;
374
384
  }
375
385
  /** Shared trace inspector: the agent timeline and the span waterfall over one clock.
376
386
  * Data remains producer-owned; playback, zoom and folding change presentation only. */
377
- export declare function FlowWaterfall({ trace, live, startedAt, label, defaultCollapsed, defaultView, renderIcon, maxHeight, onSelect, markers }: FlowWaterfallProps): import("react").JSX.Element;
387
+ export declare function FlowWaterfall({ trace, live, startedAt, label, defaultCollapsed, defaultView, renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill, selectedId, onDeselect }: FlowWaterfallProps): import("react").JSX.Element;
378
388
  //#endregion
379
389
  export type { BandKind, ChartBand, ChartMark, DotMapLabel, DotMapProps, DotMapRect, Figure, FigureAtWidth, FigureViewProps, FlowWaterfallProps, LineSeries, MarkKind, MarkVerdict, MarkerShape, MeterSegment, PointFields, PointGlyph, Refusal, SparklineDirection, SparklineGeometry, SparklineGeometryOptions, SparklineLabelOptions, SparklinePoint, SparklineProps, SparklineValues, StackedBarBucket, StackedBarChartProps, StackedBarSegment, StackedBarSeries, TickOutcome, TimelineLane, TimelineOptions, TimelineSpan, TimelineTick, TimelineViewProps, WaterfallBarProps, WaterfallHeaderProps, WaterfallRowProps, WaterfallSpanGeometry, WaterfallTimeAxisProps, WaterfallWindow, XCategory, YScale, YTarget, YTick };