@tangle-network/charts 0.19.0 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 (24% and 42% both read as "pastel, washed out"); 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) 58%, #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) 30%, #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); }
@@ -162,12 +183,12 @@
162
183
  .fw-root .fw-view-agents .fw-span-name { font-weight: 600; line-height: 18px; }
163
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; }
164
185
  .fw-root .fw-view-agents .fw-detail { font-size: 12px; line-height: 16px; }
165
- .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)); }
166
187
 
167
188
  /* Lanes and marks */
168
189
  .fw-root .fw-lane { position: relative; overflow: hidden; min-width: 0; }
169
190
  .fw-root .fw-invalid { position: absolute; left: var(--fw-pad); top: 50%; transform: translateY(-50%); color: var(--fw-muted); }
170
- .fw-root :is(.fw-bar, .fw-seg, .fw-end) {
191
+ .fw-root :is(.fw-bar, .fw-seg, .fw-end, .fw-mark) {
171
192
  --x0: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px);
172
193
  --w: calc(max(0, min(var(--e), var(--fw-t)) - var(--s)) * var(--fw-k) * 1px);
173
194
  --on: clamp(0, (var(--fw-t) - var(--s)) * 1000, 1);
@@ -176,19 +197,32 @@
176
197
  left: var(--x0);
177
198
  opacity: var(--on);
178
199
  }
179
- .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; }
180
212
  .fw-root .fw-bar { background: var(--fill); box-shadow: inset 0 0 0 1px var(--line); }
181
213
  /* The mark under the pointer lifts: a brighter fill and a ring in its own tone. */
182
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; }
183
215
  .fw-root .fw-bar.fw-k-tool { background: var(--dim); box-shadow: inset 0 0 0 1px var(--dim-line); }
184
216
  /* A handoff is a moment: a slim pill in the receiving tone, not a block of work. */
185
- .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; }
186
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); }
187
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); }
188
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); }
189
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); }
190
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); }
191
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); }
192
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); }
193
227
  /* A host outcome re-tones the whole lane: dot, bar and marks. */
194
228
  .fw-root [data-outcome="ok"], .fw-root [data-outcome="ok"] [data-tone] { --tone: var(--fw-ok); }
@@ -197,6 +231,13 @@
197
231
  .fw-root [data-outcome="neutral"], .fw-root [data-outcome="neutral"] [data-tone] { --tone: var(--fw-muted); }
198
232
  .fw-root .fw-legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 8px 0 0; padding: 0; list-style: none; color: var(--fw-muted); font-size: 12px; line-height: 16px; }
199
233
  .fw-root .fw-legend li { display: inline-flex; align-items: center; gap: 8px; }
234
+ .fw-root .fw-kinds { margin: 0; padding: 8px 24px 12px; justify-content: flex-end; }
235
+ .fw-root .fw-kinds .fw-swatch-model { width: 12px; height: 8px; border-radius: 2px; background: color-mix(in oklab, var(--fw-text) 40%, var(--fw-surface)); }
236
+ .fw-root .fw-kinds .fw-swatch-tool { width: 12px; height: 8px; border-radius: 2px; background: color-mix(in oklab, var(--fw-text) 16%, var(--fw-surface)); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-text) 30%, transparent); }
237
+ .fw-root .fw-kinds .fw-swatch-wait { width: 12px; height: 8px; border-radius: 2px; background: repeating-linear-gradient(-45deg, var(--fw-hatch) 0 1px, transparent 1px 4px); box-shadow: inset 0 0 0 1px var(--fw-hatch); }
238
+ .fw-root .fw-kinds .fw-swatch-handoff { width: 10px; height: 8px; border-left: 1.5px solid var(--fw-muted); border-bottom: 1.5px solid var(--fw-muted); border-bottom-left-radius: 3px; }
239
+ .fw-root .fw-kinds .fw-swatch-failed { width: 12px; height: 8px; border-radius: 2px; box-shadow: inset 0 0 0 1px var(--fw-failed); }
240
+ .fw-root .fw-description { margin: 0; color: var(--fw-muted); font-size: 14px; line-height: 20px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
200
241
  .fw-root .fw-legend .fw-swatch { width: 12px; height: 8px; border-radius: 2px; background: var(--fill); box-shadow: inset 0 0 0 1px var(--line); }
201
242
  .fw-root .fw-legend b { color: var(--fw-text); font-weight: 600; font-variant-numeric: tabular-nums; }
202
243
  .fw-root .fw-legend .fw-swatch-step { display: inline-grid; place-items: center; width: 12px; height: 12px; border-radius: 3px; background: var(--fw-well); color: var(--fw-failed); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-failed) 50%, transparent); }
@@ -211,7 +252,7 @@
211
252
  .fw-root .fw-glyph { display: inline-flex; color: currentColor; }
212
253
  .fw-root .fw-glyph svg { width: 11px; height: 11px; stroke-width: 2; }
213
254
  .fw-root .fw-seg-model .fw-glyph, .fw-root .fw-k-model .fw-glyph { color: light-dark(var(--tone), #fff); }
214
- .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; }
255
+ .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; }
215
256
  .fw-root .fw-duration { font-size: 12px; color: var(--fw-muted); font-variant-numeric: tabular-nums; }
216
257
  .fw-root .fw-k-failed ~ .fw-end .fw-duration { color: var(--fw-failed); }
217
258
  .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); }
@@ -241,7 +282,7 @@
241
282
  .fw-root .fw-card[role="tooltip"] { pointer-events: none; }
242
283
  .fw-root .fw-card-above .fw-card { transform: translateY(-100%); animation-name: fw-arrive-above; }
243
284
  .fw-root .fw-card-agent { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 12px; font-weight: 600; }
244
- .fw-root .fw-card-agent .fw-agent-dot { margin-top: 0; align-self: center; }
285
+ .fw-root .fw-card-agent .fw-agent-dot { align-self: center; }
245
286
  .fw-root .fw-card-head { display: flex; align-items: flex-start; gap: 8px; }
246
287
  .fw-root .fw-card-head .fw-icon-tile { flex-basis: 28px; width: 28px; height: 28px; border-radius: 8px; }
247
288
  .fw-root .fw-card-head .fw-icon-tile :is(svg, img) { width: 16px; height: 16px; }
@@ -262,12 +303,13 @@
262
303
  .fw-root .fw-card-text { margin-top: 12px; }
263
304
  .fw-root .fw-card-compact { width: 280px; padding: 12px; }
264
305
  .fw-root .fw-card-compact .fw-card-agent { margin-bottom: 8px; font-size: 14px; line-height: 20px; }
265
- .fw-root .fw-card-who { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
306
+ .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; }
266
307
  .fw-root .fw-card-detail { margin: -4px 0 8px 16px; color: var(--fw-muted); font-size: 12px; line-height: 16px; overflow-wrap: anywhere; }
267
308
  .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); }
268
309
  .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); }
269
310
  .fw-root .fw-card-cells dt { font-size: 12px; line-height: 16px; color: var(--fw-muted); }
270
311
  .fw-root .fw-card-cells dd { font-size: 14px; line-height: 20px; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
312
+ .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; }
271
313
  .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; }
272
314
  .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; }
273
315
 
@@ -292,6 +334,12 @@
292
334
  .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; }
293
335
 
294
336
  @keyframes fw-spin { to { transform: rotate(360deg); } }
337
+ /* Motion verbs. Grow: an arriving bar extends from its start. Unfold: an arriving row's cells slide in, staggered by
338
+ --fw-enter-delay. Settle: a bar that just finished eases its edge and lands its end label. */
339
+ @keyframes fw-grow { from { clip-path: inset(0 100% 0 0 round 4px); } }
340
+ @keyframes fw-unfold { from { opacity: 0; translate: 0 -4px; } }
341
+ @keyframes fw-land { from { opacity: 0; translate: -6px 0; } }
342
+ @keyframes fw-settle { 40% { filter: brightness(1.3); } }
295
343
  @keyframes fw-pulse { 50% { opacity: .35; } }
296
344
  @keyframes fw-arrive { from { opacity: 0; transform: translateY(4px); } }
297
345
  @keyframes fw-arrive-above { from { opacity: 0; transform: translateY(calc(-100% - 4px)); } }
@@ -319,10 +367,12 @@
319
367
  .fw-root .fw-heading, .fw-root .fw-playback { padding-left: 12px; padding-right: 12px; }
320
368
  }
321
369
 
322
- /* The agent timeline is one quiet surface: no inner rules, more air, the axis under the lanes. */
370
+ /* The agent timeline is one quiet surface: no inner rules; controls and axis sit above the lanes. */
323
371
  .fw-root-agents .fw-heading { border-bottom: 0; padding: 20px 24px 12px; }
324
- .fw-root-agents .fw-axis-bottom { border-top: 0; }
325
- .fw-root-agents .fw-playback { border-top: 0; padding: 8px 24px 20px; }
372
+ .fw-root-agents .fw-axis-top { border-bottom: 0; }
373
+ .fw-root-agents .fw-axis-top .fw-axis-label { border-right-color: transparent; }
374
+ .fw-root-agents .fw-playback { border-top: 0; padding: 0 24px 8px; }
375
+ .fw-root-agents .fw-body { padding-bottom: 12px; }
326
376
  .fw-root-agents .fw-view-agents .fw-label { padding-left: 24px; }
327
377
  .fw-root-agents .fw-zoom, .fw-root-agents .fw-time { display: none; }
328
378
  /* The agent view keeps scrubbing on a hairline track; the lanes above already show the activity. */
@@ -336,13 +386,13 @@
336
386
  (At 768 px a 28% column cut 15 of 17 names on a real 17-agent run.) */
337
387
  @container (max-width: 899px) {
338
388
  /* The root is the queried container, so the variables go on its children. */
339
- .fw-root-agents > * { --fw-label-col: 0px; --fw-bar-shift: 8px; }
389
+ /* In a 40 px row: the name on 0-20 px, a 16 px bar on 20-36 px. */
390
+ .fw-root-agents > * { --fw-label-col: 0px; --fw-bar-shift: 8px; --fw-bar-h: 16px; }
340
391
  .fw-root-agents .fw-view-agents .fw-names { flex-direction: row; align-items: baseline; gap: 8px; min-width: 0; }
341
- .fw-root-agents .fw-view-agents .fw-agent-dot { align-self: center; margin-top: 0; }
342
392
  /* The label leaves the grid flow, so the lane must claim the track column itself. */
343
393
  .fw-root-agents .fw-view-agents .fw-lane { grid-column: 2; }
344
394
  /* Elbows pass behind the name, not through its letters. A transform or layout containment would make each row
345
395
  its own stacking context and trap the name under the connector layer, so stacked rows place by top instead. */
346
396
  .fw-root-agents .fw-view-agents .fw-row { transform: none; top: var(--row-y); contain: style; }
347
- .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); }
397
+ .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); }
348
398
  }
@@ -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-D6RDkVrJ.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-DqCMrnTs.js";
2
2
  import { CSSProperties, ReactElement, ReactNode } from "react";
3
3
  //#region src/react/sparkline.d.ts
4
4
  type SparklineDirection = "rising" | "falling" | "flat";
@@ -175,6 +175,7 @@ export declare function HBars({ rows, format, color, max, limit }: {
175
175
  note?: string;
176
176
  color?: string;
177
177
  href?: string;
178
+ title?: string;
178
179
  }[];
179
180
  format?: (v: number) => string;
180
181
  color?: string;
@@ -369,11 +370,23 @@ interface FlowWaterfallProps {
369
370
  maxHeight?: number;
370
371
  /** Called when a row is opened or a bar is pinned, with that row's span; the built-in behavior still runs. */
371
372
  onSelect?: (span: FlowSpan) => void;
372
- /** Labelled instants, such as releases, drawn across the rows on the trace clock. */
373
+ /** Labelled instants, such as releases, drawn across the rows and as event dots on the axis; click or N/P jumps to one. */
373
374
  markers?: FlowMarker[];
375
+ /** The time the reader moved to, in trace ms; `null` when following live or showing the whole trace. */
376
+ onTimeChange?: (t: number | null) => void;
377
+ /** 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
378
+ * crash glyph; or its `outcome`. */
379
+ agentFill?: 'outcome' | 'agent';
380
+ /** One line beside the title saying what the run was for, such as its goal. */
381
+ description?: string;
382
+ /** The row the host has selected, such as the agent whose transcript is open: it lifts and, in the agent view, its peers dim.
383
+ * A pinned card alone only highlights its row, so the rest of the run stays readable around it. */
384
+ selectedId?: string;
385
+ /** Escape clears the host's selection, after closing any open card. */
386
+ onDeselect?: () => void;
374
387
  }
375
388
  /** Shared trace inspector: the agent timeline and the span waterfall over one clock.
376
389
  * 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;
390
+ export declare function FlowWaterfall({ trace, live, startedAt, label, defaultCollapsed, defaultView, renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill, selectedId, onDeselect, description }: FlowWaterfallProps): import("react").JSX.Element;
378
391
  //#endregion
379
392
  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 };