@north-light/crouter 0.3.197 → 0.3.198

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 (144) hide show
  1. package/dist/api/client.d.ts +2 -2
  2. package/dist/api/dto/inbox.d.ts +46 -0
  3. package/dist/builtin-memory/00-runtime-base.md +3 -3
  4. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  5. package/dist/builtin-memory/internal/storage-tiers.md +1 -1
  6. package/dist/builtin-memory/wedged-child-on-runaway-bash.md +1 -1
  7. package/dist/clients/attach/render/chat-view.d.ts +3 -8
  8. package/dist/clients/attach/render/chat-view.js +3 -24
  9. package/dist/clients/attach/render/markdown-source.js +0 -6
  10. package/dist/clients/attach/render/tool-calls.js +16 -2
  11. package/dist/clients/attach/viewer.js +613 -602
  12. package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +2 -2
  13. package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +11 -4
  14. package/dist/clients/inbox/controller.js +4 -4
  15. package/dist/clients/inbox/page-adapter.d.ts +2 -1
  16. package/dist/clients/inbox/tui/render.js +46 -25
  17. package/dist/clients/inbox/tui/slots.d.ts +1 -3
  18. package/dist/clients/inbox/tui/slots.js +8 -37
  19. package/dist/clients/inbox/tui/types.d.ts +4 -3
  20. package/dist/commands/__tests__/human.test.js +160 -23
  21. package/dist/commands/canvas-browse.js +1 -1
  22. package/dist/commands/human/doc.js +21 -74
  23. package/dist/commands/human/html.d.ts +2 -0
  24. package/dist/commands/human/html.js +81 -0
  25. package/dist/commands/human/prompts.d.ts +5 -4
  26. package/dist/commands/human/prompts.js +81 -153
  27. package/dist/commands/human/shared.d.ts +5 -6
  28. package/dist/commands/human/shared.js +13 -61
  29. package/dist/commands/human.js +7 -2
  30. package/dist/core/__tests__/daemon-boot.test.js +7 -4
  31. package/dist/core/__tests__/dead-node-policy-table.test.js +20 -36
  32. package/dist/core/__tests__/human-deliver.test.js +28 -37
  33. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +13 -11
  34. package/dist/core/__tests__/seam/dormancy-release.test.js +63 -4
  35. package/dist/core/__tests__/serial/human-deliver-e2e.test.js +3 -13
  36. package/dist/core/canvas/__tests__/attention.test.js +2 -2
  37. package/dist/core/canvas/__tests__/render-remote.test.js +2 -2
  38. package/dist/core/canvas/browse/app.d.ts +1 -1
  39. package/dist/core/canvas/browse/app.js +21 -3
  40. package/dist/core/canvas/browse/render.d.ts +4 -0
  41. package/dist/core/canvas/browse/render.js +5 -1
  42. package/dist/core/canvas/canvas.d.ts +26 -0
  43. package/dist/core/canvas/canvas.js +55 -0
  44. package/dist/core/command.js +6 -11
  45. package/dist/core/config.js +3 -2
  46. package/dist/core/help.d.ts +3 -0
  47. package/dist/core/human/__tests__/html-markdown.test.d.ts +1 -0
  48. package/dist/core/human/__tests__/html-markdown.test.js +52 -0
  49. package/dist/core/human/__tests__/page-catalog.test.d.ts +1 -0
  50. package/dist/core/human/__tests__/page-catalog.test.js +16 -0
  51. package/dist/core/human/__tests__/page-render.test.js +40 -23
  52. package/dist/core/human/__tests__/page-tickets.test.js +48 -27
  53. package/dist/core/human/__tests__/page.test.js +48 -65
  54. package/dist/core/human/__tests__/serial/inbox-core.test.js +5 -15
  55. package/dist/core/human/answer-text.d.ts +3 -0
  56. package/dist/core/human/answer-text.js +98 -0
  57. package/dist/core/human/answer.d.ts +51 -0
  58. package/dist/core/human/answer.js +125 -0
  59. package/dist/core/human/component-docs.d.ts +14 -0
  60. package/dist/core/human/component-docs.js +161 -0
  61. package/dist/core/human/html-markdown.d.ts +3 -0
  62. package/dist/core/human/html-markdown.js +288 -0
  63. package/dist/core/human/page-catalog.d.ts +19 -3
  64. package/dist/core/human/page-catalog.js +73 -16
  65. package/dist/core/human/page-render.d.ts +3 -2
  66. package/dist/core/human/page-render.js +19 -45
  67. package/dist/core/human/page-schema.d.ts +108 -8
  68. package/dist/core/human/page-schema.js +88 -31
  69. package/dist/core/human/page-synth.d.ts +2 -4
  70. package/dist/core/human/page-synth.js +23 -7
  71. package/dist/core/human/page.d.ts +14 -7
  72. package/dist/core/human/page.js +178 -90
  73. package/dist/core/human/review-schema.d.ts +1 -0
  74. package/dist/core/human/review-schema.js +1 -1
  75. package/dist/core/human/scan.d.ts +3 -2
  76. package/dist/core/human/scan.js +7 -8
  77. package/dist/core/human/summary.d.ts +4 -7
  78. package/dist/core/human/summary.js +4 -60
  79. package/dist/core/human/tickets.d.ts +10 -9
  80. package/dist/core/human/tickets.js +5 -3
  81. package/dist/core/human/types.d.ts +4 -0
  82. package/dist/core/keybindings/catalog.d.ts +2 -2
  83. package/dist/core/keybindings/catalog.js +1 -0
  84. package/dist/core/review/realize.js +9 -1
  85. package/dist/core/runtime/boot-root.js +6 -1
  86. package/dist/core/runtime/broker.js +8 -6
  87. package/dist/core/runtime/busy.d.ts +4 -3
  88. package/dist/core/runtime/busy.js +4 -3
  89. package/dist/core/runtime/spawn.js +4 -4
  90. package/dist/core/user-settings.d.ts +17 -2
  91. package/dist/core/user-settings.js +32 -11
  92. package/dist/daemon/api/handlers/human.js +1 -1
  93. package/dist/daemon/api/handlers/inbox.js +22 -7
  94. package/dist/daemon/cron-run.js +16 -2
  95. package/dist/daemon/crtrd.js +1 -1
  96. package/dist/daemon/fleet.d.ts +22 -10
  97. package/dist/daemon/fleet.js +43 -24
  98. package/dist/daemon/human/finish.d.ts +2 -1
  99. package/dist/daemon/human/finish.js +45 -28
  100. package/dist/daemon/human/sweep.js +4 -2
  101. package/dist/daemon/reconcilers/broker-supervision.js +11 -8
  102. package/dist/daemon/reconcilers/dormant-inbox.js +11 -6
  103. package/dist/daemon/reconcilers/live-obligation.d.ts +21 -1
  104. package/dist/daemon/reconcilers/live-obligation.js +30 -2
  105. package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -0
  106. package/dist/daemon/reconcilers/storage-maintenance.js +28 -1
  107. package/dist/daemon/review/sweep.js +12 -1
  108. package/dist/pages/bundle.css +1 -1
  109. package/dist/pages/bundle.js +1008 -577
  110. package/dist/pages/comments.d.ts +29 -0
  111. package/dist/pages/comments.js +51 -0
  112. package/dist/pages/controls.d.ts +98 -0
  113. package/dist/pages/controls.js +261 -0
  114. package/dist/pages/elements/cards.d.ts +15 -4
  115. package/dist/pages/elements/cards.js +299 -186
  116. package/dist/pages/elements/chart.d.ts +22 -0
  117. package/dist/pages/elements/chart.js +107 -91
  118. package/dist/pages/elements/options.d.ts +9 -0
  119. package/dist/pages/elements/options.js +268 -155
  120. package/dist/pages/elements/pages.d.ts +6 -0
  121. package/dist/pages/elements/pages.js +60 -38
  122. package/dist/pages/elements/slot.d.ts +5 -0
  123. package/dist/pages/elements/slot.js +17 -10
  124. package/dist/pages/elements/table.d.ts +17 -0
  125. package/dist/pages/elements/table.js +336 -228
  126. package/dist/pages/elements/text.d.ts +9 -3
  127. package/dist/pages/elements/text.js +350 -143
  128. package/dist/pages/host.d.ts +0 -24
  129. package/dist/pages/host.js +0 -17
  130. package/dist/pages/readonly.d.ts +24 -0
  131. package/dist/pages/readonly.js +31 -0
  132. package/dist/pages/responses.d.ts +37 -0
  133. package/dist/pages/responses.js +56 -0
  134. package/dist/pi-extensions/canvas-bash-valve.d.ts +9 -1
  135. package/dist/pi-extensions/canvas-bash-valve.js +12 -8
  136. package/dist/types.d.ts +19 -5
  137. package/dist/types.js +2 -1
  138. package/package.json +1 -1
  139. package/runtime.lock.json +2 -2
  140. package/scripts/install-runtime.mjs +19 -24
  141. package/dist/clients/attach/render/html-markdown.d.ts +0 -13
  142. package/dist/clients/attach/render/html-markdown.js +0 -206
  143. package/dist/core/human/markdown-html.d.ts +0 -8
  144. package/dist/core/human/markdown-html.js +0 -581
@@ -1 +1,23 @@
1
+ /**
2
+ * `<crtr-chart>` — the line, bar and area plots the page bundle draws.
3
+ *
4
+ * ## Every value here is a `--crtr-chart-*` token
5
+ *
6
+ * The frame, the legend, the axes and the marks themselves are painted through
7
+ * `var(--crtr-chart-<part>-<knob>, <kit default>)`, so a host restyles this element by setting
8
+ * properties on the document root — custom properties inherit into shadow roots, which is the
9
+ * whole mechanism. Series colour keeps coming from the bundle-wide `--crtr-chart-1..5` ramp,
10
+ * which is the theme layer rather than a component knob.
11
+ *
12
+ * Mark paint that SVG would otherwise carry as a presentation attribute — the grid's stroke,
13
+ * the line's width and caps, the area's fill opacity, the point radius, the bar's corner
14
+ * radius — is written as CSS instead, because an attribute cannot hold a `var()` chain and so
15
+ * cannot be overridden. The rendered plot height is styling and reads
16
+ * `--crtr-chart-plot-height`; what stays in TypeScript is the coordinate system's layout
17
+ * arithmetic — the drawing height, margins, tick budget and label metrics are inputs to the
18
+ * geometry this element computes, not declarations a stylesheet could carry.
19
+ *
20
+ * Defaults stay inline at the rule that spends them and no `--crtr-chart-*` component token is
21
+ * ever declared: an unset token is what carries the kit default down the chain.
22
+ */
1
23
  export {};
@@ -1,4 +1,25 @@
1
- import { artifactData } from '../host.js';
1
+ /**
2
+ * `<crtr-chart>` — the line, bar and area plots the page bundle draws.
3
+ *
4
+ * ## Every value here is a `--crtr-chart-*` token
5
+ *
6
+ * The frame, the legend, the axes and the marks themselves are painted through
7
+ * `var(--crtr-chart-<part>-<knob>, <kit default>)`, so a host restyles this element by setting
8
+ * properties on the document root — custom properties inherit into shadow roots, which is the
9
+ * whole mechanism. Series colour keeps coming from the bundle-wide `--crtr-chart-1..5` ramp,
10
+ * which is the theme layer rather than a component knob.
11
+ *
12
+ * Mark paint that SVG would otherwise carry as a presentation attribute — the grid's stroke,
13
+ * the line's width and caps, the area's fill opacity, the point radius, the bar's corner
14
+ * radius — is written as CSS instead, because an attribute cannot hold a `var()` chain and so
15
+ * cannot be overridden. The rendered plot height is styling and reads
16
+ * `--crtr-chart-plot-height`; what stays in TypeScript is the coordinate system's layout
17
+ * arithmetic — the drawing height, margins, tick budget and label metrics are inputs to the
18
+ * geometry this element computes, not declarations a stylesheet could carry.
19
+ *
20
+ * Defaults stay inline at the rule that spends them and no `--crtr-chart-*` component token is
21
+ * ever declared: an unset token is what carries the kit default down the chain.
22
+ */
2
23
  import { registerElement } from '../register.js';
3
24
  import { readSlotConfig } from '../slot-config.js';
4
25
  /** The five chart tokens, cycled when a config declares more than five series. */
@@ -30,36 +51,38 @@ const STYLE = `
30
51
  [part="container"] {
31
52
  display: flex;
32
53
  flex-direction: column;
33
- gap: var(--crtr-space-2);
54
+ gap: var(--crtr-chart-container-gap, var(--crtr-space-2));
34
55
  width: 100%;
35
56
  }
36
57
 
37
58
  [part="title"] {
38
- color: var(--crtr-color-text);
39
- font-weight: 500;
59
+ color: var(--crtr-chart-title-text-color, var(--crtr-color-text));
60
+ font-weight: var(--crtr-chart-title-font-weight, 500);
40
61
  }
41
62
 
42
63
  [part="legend"] {
43
64
  display: flex;
44
65
  flex-wrap: wrap;
45
66
  align-items: center;
46
- gap: var(--crtr-space-1) var(--crtr-space-4);
47
- color: var(--crtr-color-text-muted);
48
- font-size: calc(var(--crtr-font-size) * 0.85);
67
+ gap: var(--crtr-chart-legend-gap, var(--crtr-space-1) var(--crtr-space-4));
68
+ color: var(--crtr-chart-legend-text-color, var(--crtr-color-text-muted));
69
+ font-size: var(--crtr-chart-legend-font-size, 0.875em);
49
70
  }
50
71
 
51
72
  [part="legend-item"] {
52
73
  display: flex;
53
74
  align-items: center;
54
- gap: var(--crtr-space-1);
75
+ gap: var(--crtr-chart-legend-item-gap, var(--crtr-space-1));
55
76
  min-width: 0;
56
77
  }
57
78
 
79
+ /* Sized against the legend's own text, not a spacing token doing a sizing job. One knob:
80
+ the swatch is a square, so its width and height are the same value. */
58
81
  [part="legend-swatch"] {
59
82
  flex: none;
60
- width: calc(var(--crtr-space-2) - 1px);
61
- height: calc(var(--crtr-space-2) - 1px);
62
- border-radius: 2px;
83
+ width: var(--crtr-chart-legend-swatch-size, 0.75em);
84
+ height: var(--crtr-chart-legend-swatch-size, 0.75em);
85
+ border-radius: var(--crtr-chart-legend-swatch-radius, calc(var(--crtr-radius-small) * 0.5));
63
86
  }
64
87
 
65
88
  [part="legend-label"] {
@@ -74,51 +97,91 @@ const STYLE = `
74
97
 
75
98
  [part="chart"] {
76
99
  display: block;
100
+ height: var(--crtr-chart-plot-height, 260px);
77
101
  overflow: visible;
78
102
  }
79
103
 
104
+ /* Waiting for data and having none hold the same space, but each stays in its own scope:
105
+ one scope never names two different parts. */
80
106
  [part="empty"] {
81
107
  display: flex;
82
108
  align-items: center;
83
109
  justify-content: center;
84
- padding: 0 var(--crtr-space-4);
85
- color: var(--crtr-color-text-muted);
86
- border: 1px dashed var(--crtr-color-border);
87
- border-radius: var(--crtr-radius-medium);
110
+ padding: var(--crtr-chart-empty-padding, 0 var(--crtr-space-4));
111
+ color: var(--crtr-chart-empty-text-color, var(--crtr-color-text-muted));
112
+ font-size: var(--crtr-chart-empty-font-size, 0.875em);
113
+ border: var(--crtr-chart-empty-border-width, 1px)
114
+ var(--crtr-chart-empty-border-style, dashed)
115
+ var(--crtr-chart-empty-border-color, var(--crtr-color-border));
116
+ border-radius: var(--crtr-chart-empty-radius, var(--crtr-radius-medium));
88
117
  }
89
118
 
90
119
  [part="status"] {
91
120
  display: flex;
92
121
  align-items: center;
93
122
  justify-content: center;
94
- padding: 0 var(--crtr-space-4);
95
- color: var(--crtr-color-text-muted);
96
- border: 1px dashed var(--crtr-color-border);
97
- border-radius: var(--crtr-radius-medium);
123
+ padding: var(--crtr-chart-status-padding, 0 var(--crtr-space-4));
124
+ color: var(--crtr-chart-status-text-color, var(--crtr-color-text-muted));
125
+ font-size: var(--crtr-chart-status-font-size, 0.875em);
126
+ border: var(--crtr-chart-status-border-width, 1px)
127
+ var(--crtr-chart-status-border-style, dashed)
128
+ var(--crtr-chart-status-border-color, var(--crtr-color-border));
129
+ border-radius: var(--crtr-chart-status-radius, var(--crtr-radius-medium));
98
130
  }
99
131
 
132
+ /* Flat: this sits in the flow of the page. A shadow in this bundle means floating. */
100
133
  [part="unavailable"] {
101
- padding: var(--crtr-space-3);
102
- color: var(--crtr-color-text-muted);
103
- background: var(--crtr-color-surface);
104
- border: 1px solid var(--crtr-color-border);
105
- border-radius: var(--crtr-radius-medium);
106
- box-shadow: var(--crtr-shadow);
134
+ padding: var(--crtr-chart-unavailable-padding, var(--crtr-space-3));
135
+ color: var(--crtr-chart-unavailable-text-color, var(--crtr-color-text-muted));
136
+ background: var(--crtr-chart-unavailable-fill, var(--crtr-color-surface));
137
+ border: var(--crtr-chart-unavailable-border-width, 1px)
138
+ var(--crtr-chart-unavailable-border-style, solid)
139
+ var(--crtr-chart-unavailable-border-color, var(--crtr-color-border));
140
+ border-radius: var(--crtr-chart-unavailable-radius, var(--crtr-radius-medium));
107
141
  }
108
142
 
109
143
  [part="reason"] {
110
- color: var(--crtr-color-text);
111
- font-family: var(--crtr-font-mono);
144
+ color: var(--crtr-chart-reason-text-color, var(--crtr-color-text));
145
+ font-family: var(--crtr-chart-reason-font-family, var(--crtr-font-mono));
112
146
  }
113
147
 
114
148
  .grid {
115
- stroke: var(--crtr-color-border);
116
- stroke-width: 1;
149
+ stroke: var(--crtr-chart-grid-stroke-color, var(--crtr-color-border));
150
+ stroke-width: var(--crtr-chart-grid-stroke-width, 1);
151
+ opacity: var(--crtr-chart-grid-opacity, 0.45);
152
+ }
153
+
154
+ /* The gridline the marks are read against carries more weight than the rest. */
155
+ .grid.baseline {
156
+ opacity: var(--crtr-chart-grid-baseline-opacity, 0.9);
117
157
  }
118
158
 
119
159
  .tick {
120
- fill: var(--crtr-color-text-muted);
121
- font-size: calc(var(--crtr-font-size) * 0.72);
160
+ fill: var(--crtr-chart-tick-text-color, var(--crtr-color-text-muted));
161
+ font-size: var(--crtr-chart-tick-font-size, 0.75em);
162
+ }
163
+
164
+ /* Mark paint. Series colour arrives per node from the theme's chart ramp; everything
165
+ these marks are drawn WITH is a knob, which is why none of it is an SVG attribute. */
166
+ [part="line"] {
167
+ stroke-width: var(--crtr-chart-line-stroke-width, 2);
168
+ stroke-linecap: var(--crtr-chart-line-line-cap, round);
169
+ stroke-linejoin: var(--crtr-chart-line-line-join, round);
170
+ }
171
+
172
+ [part="area"] {
173
+ fill-opacity: var(--crtr-chart-area-fill-opacity, 0.18);
174
+ }
175
+
176
+ [part="point"] {
177
+ r: var(--crtr-chart-point-radius, 2.5);
178
+ }
179
+
180
+ /* A bar never rounds away more than a third of its own width, and --bar-max-radius is
181
+ that width — the one number here the stylesheet cannot know, so the plot writes it onto
182
+ the SVG and the knob is clamped against it. */
183
+ [part="bar"] {
184
+ rx: min(var(--crtr-chart-bar-radius, 2px), var(--bar-max-radius));
122
185
  }
123
186
  `;
124
187
  function normalizeConfig(raw) {
@@ -149,9 +212,6 @@ function normalizeConfig(raw) {
149
212
  if (raw.title !== undefined && typeof raw.title !== 'string') {
150
213
  return { status: 'invalid', reason: 'chart title is not a string' };
151
214
  }
152
- if (raw.source !== undefined && typeof raw.source !== 'string') {
153
- return { status: 'invalid', reason: 'chart source is not a string' };
154
- }
155
215
  return {
156
216
  status: 'ok',
157
217
  config: {
@@ -160,7 +220,6 @@ function normalizeConfig(raw) {
160
220
  y,
161
221
  title: raw.title,
162
222
  data: raw.data,
163
- source: raw.source,
164
223
  },
165
224
  };
166
225
  }
@@ -329,7 +388,7 @@ class CrtrChartElement extends HTMLElement {
329
388
  root.append(style, this.#container);
330
389
  }
331
390
  connectedCallback() {
332
- const generation = ++this.#generation;
391
+ ++this.#generation;
333
392
  this.#config = null;
334
393
  this.#rows = null;
335
394
  const read = readSlotConfig(this);
@@ -345,45 +404,19 @@ class CrtrChartElement extends HTMLElement {
345
404
  this.#config = normalized.config;
346
405
  this.#renderFrame();
347
406
  this.#observe();
348
- const { data, source } = normalized.config;
349
- if (data !== undefined) {
350
- if (!isRows(data)) {
351
- this.#renderUnavailable('chart data is not a list of rows');
352
- return;
353
- }
354
- this.#rows = data;
355
- this.#renderPlot();
407
+ const { data } = normalized.config;
408
+ if (data !== undefined && !isRows(data)) {
409
+ this.#renderUnavailable('chart data is not a list of rows');
356
410
  return;
357
411
  }
358
- if (source === undefined || source === '') {
359
- this.#rows = [];
360
- this.#renderPlot();
361
- return;
362
- }
363
- this.#renderStatus('Loading chart data…');
364
- void this.#resolveSource(source, generation);
412
+ this.#rows = data ?? [];
413
+ this.#renderPlot();
365
414
  }
366
415
  disconnectedCallback() {
367
416
  this.#generation += 1;
368
417
  this.#observer?.disconnect();
369
418
  this.#observer = null;
370
419
  }
371
- /** The host bridge resolves `source`; this element never touches the network. */
372
- async #resolveSource(source, generation) {
373
- const result = await artifactData(source);
374
- if (generation !== this.#generation)
375
- return;
376
- if (result.status !== 'ok') {
377
- this.#renderUnavailable(`chart source "${source}" is ${result.status}: ${result.reason}`);
378
- return;
379
- }
380
- if (!isRows(result.data)) {
381
- this.#renderUnavailable(`chart source "${source}" is not a list of rows`);
382
- return;
383
- }
384
- this.#rows = result.data;
385
- this.#renderPlot();
386
- }
387
420
  #observe() {
388
421
  this.#observer?.disconnect();
389
422
  this.#width = this.#plot.getBoundingClientRect().width;
@@ -409,16 +442,7 @@ class CrtrChartElement extends HTMLElement {
409
442
  box.append('Chart unavailable: ', detail);
410
443
  this.#container.replaceChildren(box);
411
444
  }
412
- /** Holds the plot's height while a source resolves, so the page does not jump. */
413
- #renderStatus(text) {
414
- const box = document.createElement('div');
415
- box.part.add('status');
416
- box.setAttribute('role', 'status');
417
- box.style.height = `${HEIGHT}px`;
418
- box.textContent = text;
419
- this.#plot.replaceChildren(box);
420
- }
421
- /** Title and legend come from the config alone, so they survive a pending source. */
445
+ /** Title and legend come from the config alone. */
422
446
  #renderFrame() {
423
447
  const config = this.#config;
424
448
  if (config === null)
@@ -495,7 +519,7 @@ class CrtrChartElement extends HTMLElement {
495
519
  if (plotted === 0 || rows.length === 0) {
496
520
  const empty = document.createElement('div');
497
521
  empty.part.add('empty');
498
- empty.style.height = `${HEIGHT}px`;
522
+ empty.style.height = 'var(--crtr-chart-plot-height, 260px)';
499
523
  empty.textContent = 'No data to chart';
500
524
  this.#plot.replaceChildren(empty);
501
525
  return;
@@ -505,7 +529,7 @@ class CrtrChartElement extends HTMLElement {
505
529
  // First paint, before the container has been measured: hold the height so
506
530
  // the surrounding document does not reflow when the SVG arrives.
507
531
  const spacer = document.createElement('div');
508
- spacer.style.height = `${HEIGHT}px`;
532
+ spacer.style.height = 'var(--crtr-chart-plot-height, 260px)';
509
533
  this.#plot.replaceChildren(spacer);
510
534
  return;
511
535
  }
@@ -527,13 +551,12 @@ class CrtrChartElement extends HTMLElement {
527
551
  svg.setAttribute('aria-label', `${config.kind} chart of ${series.map((entry) => entry.label).join(', ')} by ${titleCaseHeader(config.x)}`);
528
552
  ticks.forEach((tick, tickIndex) => {
529
553
  const line = svgNode('line');
530
- line.setAttribute('class', 'grid');
554
+ line.setAttribute('class', tick === baselineValue ? 'grid baseline' : 'grid');
531
555
  setAttributes(line, {
532
556
  x1: marginLeft,
533
557
  x2: marginLeft + plotWidth,
534
558
  y1: yOf(tick),
535
559
  y2: yOf(tick),
536
- opacity: tick === baselineValue ? 0.9 : 0.45,
537
560
  });
538
561
  const label = svgNode('text');
539
562
  label.setAttribute('class', 'tick');
@@ -582,6 +605,7 @@ class CrtrChartElement extends HTMLElement {
582
605
  const groupWidth = band * 0.72;
583
606
  const slot = groupWidth / series.length;
584
607
  const barWidth = Math.max(1, slot - (slot > 4 ? 1 : 0));
608
+ svg.style.setProperty('--bar-max-radius', `${barWidth / 3}px`);
585
609
  series.forEach((entry, seriesIndex) => {
586
610
  const group = svgNode('g');
587
611
  for (const point of entry.points) {
@@ -592,7 +616,6 @@ class CrtrChartElement extends HTMLElement {
592
616
  y: Math.min(y, baselineY),
593
617
  width: barWidth,
594
618
  height: Math.max(1, Math.abs(baselineY - y)),
595
- rx: Math.min(2, barWidth / 3),
596
619
  });
597
620
  bar.style.fill = entry.color;
598
621
  bar.append(tooltip(`${entry.label} · ${categories[point.index] ?? point.index}: ${formatExact(point.value)}`));
@@ -614,26 +637,19 @@ class CrtrChartElement extends HTMLElement {
614
637
  const area = svgNode('path', 'area');
615
638
  setAttributes(area, {
616
639
  d: `M ${xOf(first.index)},${baselineY} L ${trace} L ${xOf(last.index)},${baselineY} Z`,
617
- 'fill-opacity': 0.18,
618
640
  });
619
641
  area.style.fill = entry.color;
620
642
  group.append(area);
621
643
  }
622
644
  const line = svgNode('path', 'line');
623
- setAttributes(line, {
624
- d: `M ${trace}`,
625
- fill: 'none',
626
- 'stroke-width': 2,
627
- 'stroke-linecap': 'round',
628
- 'stroke-linejoin': 'round',
629
- });
645
+ setAttributes(line, { d: `M ${trace}`, fill: 'none' });
630
646
  line.style.stroke = entry.color;
631
647
  group.append(line);
632
648
  if (!showDots && segment.length > 1)
633
649
  continue;
634
650
  for (const point of segment) {
635
651
  const dot = svgNode('circle', 'point');
636
- setAttributes(dot, { cx: xOf(point.index), cy: yOf(point.value), r: 2.5 });
652
+ setAttributes(dot, { cx: xOf(point.index), cy: yOf(point.value) });
637
653
  dot.style.fill = entry.color;
638
654
  dot.append(tooltip(`${entry.label} · ${categories[point.index] ?? point.index}: ${formatExact(point.value)}`));
639
655
  group.append(dot);
@@ -17,5 +17,14 @@
17
17
  * Selection is kept in the agent's authored order, never click order, so the response reads
18
18
  * the way the question did. `freetext` is absent rather than empty: the response says whether
19
19
  * the user wrote something, not whether the box existed.
20
+ *
21
+ * Every styling value this element paints is read through a `--crtr-options-*` component
22
+ * token, so a host restyles the question without touching crtr. Paint that the bundle shares —
23
+ * the option controls, the two writing boxes, the focus ring on every button — chains through
24
+ * the `--crtr-control-*` family behind its element token, which is what keeps a comment box
25
+ * here identical to one in `<crtr-text>` unless a host deliberately parts them. Each anatomy
26
+ * part carries its own scope: the option row and the control inside it, the comment trigger
27
+ * and the box it opens, and the two buttons in that box are five things a person can point at,
28
+ * so they are five scopes rather than one shared name meaning two different rectangles.
20
29
  */
21
30
  export {};