@umriss-ui/charts 0.3.2 → 0.4.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.
package/CHANGELOG.md CHANGED
@@ -29,6 +29,213 @@ interface was still expected to move before `0.3.0`.
29
29
 
30
30
  ---
31
31
 
32
+ ## 0.4.0 – The charts examined (Sep. 2026)
33
+
34
+ The result of a review of the whole package (`.scratch/charts-review/spec.md`),
35
+ delivered in three parts: the bugs it found and the removal of `Span`
36
+ (`charts-fixes`), what a plant screen expects of a chart
37
+ (`charts-essentials`), and long courses (`charts-long-series`). **`Span` is
38
+ gone** - occupancy is drawn by `@umriss-ui/schedule` (ADR-0026).
39
+
40
+ ### Changed
41
+
42
+ - **`Span` is removed** (breaking, ADR-0026). Occupancy - jobs on machines,
43
+ idle time, double bookings - is drawn by `@umriss-ui/schedule`, with lanes,
44
+ groups and editing. With it go `SpanProps`, `SpanSeriesConfig`, the series
45
+ kind `"span"`, the second x channel `x1` of `MaterializedSeries` and
46
+ `open` in a tooltip point's `segment`.
47
+ - **A state band and a matrix take no palette colour.** They colour themselves,
48
+ and each used up a place of the palette all the same: a line after a state
49
+ band came out in the palette's second colour, after three bands in its
50
+ fourth. It now gets the first. A series without a `name` counts its position
51
+ among the series that take a colour.
52
+ - **The operating-time axis labels in en-GB by level.** Without a
53
+ `tickFormat` it wrote every tick as `dd.MM. HH:mm`; it now labels as the
54
+ time axis does - `15:00`, and the date on the first tick of a new day,
55
+ `17 Mar 06:00` - and the tooltip's x value as `17 Mar 15:23`. Its ticks
56
+ stand on the same local boundaries, across a clock change too.
57
+ - **Lines and areas downsample on their own.** Above two points per pixel
58
+ column of the plot they draw four per column - where the course entered it,
59
+ its lowest and highest value, where it left - and a gap in a column stays a
60
+ gap. They draw only the window of the x domain, and one point beyond each
61
+ edge. The picture is the same; three lines of 1,000,000 points draw in about
62
+ 8 ms instead of 47. Bars and scatters are never thinned, and the tooltip
63
+ still searches every point.
64
+ - **A caller's colour is resolved for the canvas.** A series' `color`, a
65
+ state's, a limit's and a gradient stop reached the canvas as the text they
66
+ were given: `var(--…)` or `light-dark(…)` drew nothing, or in the colour
67
+ drawn before. They now go through the theme's probe as the palette does,
68
+ and are resolved anew when the colour scheme changes.
69
+ - **A state band's last state ends at the latest reading.** It ran to the end
70
+ of the x domain - with `domain="nice"` a rounding of the axis, and with
71
+ `domain="data"` nothing at all. It now ends at the last x of any visible
72
+ series on its x axis; where the band reports last, one median step of its
73
+ own x values after its last point; never beyond the domain. The band's x
74
+ extent reaches that step too. The last state is no longer hit beyond it.
75
+ - **The first tick of a time axis carries its date.** A clock tick names the
76
+ day, a day tick the year - a zoomed axis whose first tick is a midnight, or
77
+ that crosses none, named no day at all.
78
+
79
+ ### Added
80
+
81
+ - **`TooltipPoint.xValue`**: a point's own x value. With several x axes it can
82
+ differ from the hit's.
83
+ - **`localOffset(instant)`**: the time zone's offset at an instant, as the
84
+ shift of a tick grid onto local time. It moved here from
85
+ `@umriss-ui/schedule`, which takes it from here now.
86
+ - **`XAxis time`**: the values are instants. Ticks on local boundaries from
87
+ the minute to the month, labels by level in en-GB with a 24-hour clock -
88
+ `15:00`, `17 Mar`, `Mar 2026` - and the date on the first tick of a new
89
+ day. `domain="nice"` widens to the step's boundaries. A `tickFormat` is
90
+ handed the instant, which is how the axis speaks German. `calendar` implies
91
+ `time`.
92
+ - **`format` on `Line`, `Area`, `Bar`, `Scatter`, `Matrix` and
93
+ `ControlChart`**: `(value: number) => string`, the value as the tooltip
94
+ writes it - "806.4 °C" without a render prop. Without it the y axis'
95
+ `tickFormat`, then the default; a matrix' value has no axis format and goes
96
+ to the default. `ControlChart` passes it on to its line and its violations.
97
+ - **`Line step`**: sample-and-hold. Each value holds as a horizontal until
98
+ the next sample and jumps there - a set point, a digital signal. A gap ends
99
+ the hold at its x. The tooltip reports the sample the hold began with, not
100
+ the nearer one after it.
101
+ - **`hidden` on `Line`, `Area`, `Bar`, `Scatter`, `StateBand` and `Matrix`**,
102
+ controlled: a hidden series is not drawn, not hit and does not count for its
103
+ axes' extent - a fixed `domain` keeps the axis still. Its legend entry stays,
104
+ struck through with a faint chip. A hidden bar leaves no empty place in its
105
+ group.
106
+ - **`Legend onToggle(name)`**: with it every entry is a button
107
+ (`aria-pressed`) that hands the caller the series' name, or a state's label.
108
+ Without it the legend is not clickable, as before.
109
+ - **`Chart empty`**: what the plot area says when no visible series has a
110
+ point to show - no data, only gaps, or every series hidden. Default
111
+ `"No data"`, centred; axes and frame stay. Before, such a chart drew an
112
+ empty frame on [0, 1] and said nothing. A time axis over less than a minute
113
+ - the [0, 1] of an axis without data - draws no ticks.
114
+ - **`tone` on `Area`, `Bar` and `ControlChart`**, as on `Line` and
115
+ `Scatter`: a role the theme resolves. On `ControlChart` it colours the line;
116
+ the violations stay "alarm".
117
+ - **`Area dash`**: a dash pattern for the outline, in CSS pixels; the fill
118
+ stays whole.
119
+ - Every size prop's comment names its unit (CSS pixels, a fraction of the
120
+ step, domain units of the axis).
121
+ - **`XAxis onDomainChange`**: zoom and pan, controlled. Ctrl or ⌘ with the
122
+ wheel - and a pinch - zoom around the pointer; a drag, a horizontal wheel or
123
+ Shift with the wheel pan; a double click proposes the whole data range. The
124
+ axis only proposes a domain in its own units; the caller passes it back as
125
+ `domain`, clamped as it likes. Without a handler nothing zooms, and the
126
+ plain wheel always scrolls the page.
127
+ - **`YAxis domain="visible"`**: the extent of what the series show inside
128
+ their x axis' domain, widened to ticks as `"nice"` is - a zoomed hour gets
129
+ the hour's range, not the week's. A fixed foot (area, bar) and the limits
130
+ count as before; where the x domain is not fixed, every point is shown and
131
+ counts.
132
+ - **`Chart syncId`**: charts with the same id share the pointer's x
133
+ position, in domain units. Each draws its crosshair there, on its x axis of
134
+ the same id or its first; the tooltip stays with the chart under the
135
+ pointer. Zoom is not shared - pass every chart the same controlled
136
+ `domain`.
137
+ - **`YAxis alignTicks`**: on a further y axis, take the first y axis' tick
138
+ count and widen this axis' domain until its ticks stand on that one's grid
139
+ lines, the steps still 1, 2 or 5. One grid then serves two quantities. The
140
+ DEV warning about several grids names it.
141
+
142
+ ### Fixed
143
+
144
+ - **The sortedness check sees every series.** In DEV it ran for the first
145
+ series only, and warned falsely where that was a matrix, whose cells run
146
+ row-major. It now checks every series but the matrix, once per change of its
147
+ data, and names the series it warns about.
148
+ - **A matrix explains its own colours.** Its legend entry showed a palette
149
+ colour it never draws; it now shows the gradient's steps or the limit set's
150
+ three colours, and the tooltip's chip shows the colour of the cell.
151
+ - **A state several bands share highlights all of them.** Hovering "Fault" in
152
+ the legend of three machines highlighted the first band only.
153
+ - **The tooltip writes a value in its axis' format.** It formatted every value
154
+ with a fixed default, so beside ticks reading "40 %" the tooltip wrote a
155
+ bare "42". A value now takes its y axis' `tickFormat`, and the default only
156
+ without one. A point on another x axis than the header's names its own x
157
+ value, in its own axis' format, beside its name.
158
+ - **An infinity is a gap.** `±Infinity` out of any accessor - y, baseline,
159
+ a matrix' value, x - entered the extent, which was then no longer finite, and
160
+ the axis fell back to [0, 1] with every other value pressed against its edge.
161
+ It is now treated like `null` or `NaN`: a gap, outside the extent. An x
162
+ that is no number - an infinity or `NaN` - takes the place of the point
163
+ before it, so that the x values stay ascending; in the middle of a series,
164
+ or as `-Infinity`, it used to raise a false DEV warning about unsorted data
165
+ and mislead the hit test.
166
+ - **A point between two gaps is drawn.** On a line it was a lone move of the
167
+ pen and drew nothing, and above 60 points `markers="auto"` drew no marker for
168
+ it either - a reading a gap isolates vanished. It now always keeps its marker;
169
+ only `markers="never"` drops it. On an area it is a stroke from its foot to
170
+ its value, with or without an outline.
171
+ - **A control chart reports its violations once per change.** An inline
172
+ `accessor` or `origin` recomputed the limits on every render, and
173
+ `onViolations` was called after each - a caller that kept the violations in
174
+ state rendered forever. The accessor is now compared by its source text, the
175
+ origin by its values, and `onViolations` is called only when the violations
176
+ differ in content.
177
+ - **A limit on the x axis finds its axis.** `LimitLine` and `LimitBand` with
178
+ `orientation="x"` and no `axisId` looked for an axis "y" among the x axes,
179
+ found none and drew nothing, silently. Without an `axisId` a limit now binds
180
+ to the first axis of its orientation - an `<XAxis id="time">` too - and an
181
+ unknown `axisId` is a DEV error, as it is for a series.
182
+ - **The operating-time axis stands on the local clock.** Its day and half-day
183
+ ticks fell on UTC's midnight and were labelled in local time - "01:00"
184
+ where a day begins, in CET. They now fall on local midnight and noon. Explicit
185
+ `ticks` and the value of an x limit are named on the wall clock, like the
186
+ data, and mapped into operating time as the data are; before, both were taken
187
+ as operating time and landed far off, or pulled the axis out of shape.
188
+ - **Hit testing where areas and points meet.** Under `mode="nearest"` a state
189
+ band or a matrix cell under the pointer counted as distance zero and beat
190
+ every point; a point within 12 px of the pointer now wins, and the area
191
+ answers where none is. A chart of bands or cells only pinned crosshair and
192
+ tooltip to the beginning of the section; they now stay with the pointer. And
193
+ a scatter under `"nearest"` was hit by x alone - the sample straight above
194
+ the pointer beat the one beside it; it is now measured in x and y.
195
+ - **Change detection.** An inline `calendar` array is new on every render, and
196
+ was compared by reference: every render mapped every point again. It is now
197
+ compared by its intervals. Functions are compared by their source text, and
198
+ every native or bound function reads the same - two bound
199
+ `Intl.NumberFormat#format` counted as equal, and swapping one for the other
200
+ left the axis in the old format. Such a function is now compared by identity.
201
+ The known limit stays and is now documented at the props: two functions of
202
+ the same text that read different captured values count as equal.
203
+ - **A control chart over a constant reference window finds no outliers.**
204
+ Sigma is 0 there, the limits lie on the centre line, and every value off it
205
+ was an outlier - and two of three beyond "two sigma". Both rules now find
206
+ nothing without a spread, and DEV warns that the limits are degenerate - for
207
+ a given sigma of 0 or below as well, where the rules find nothing either.
208
+ - **`Chart.height` says its default.** The comment promised the host's height;
209
+ the default is and was 300.
210
+ - **A matrix buckets its cells once per change**, not on every redraw of the
211
+ series layer - a legend hover redraws it - and its tooltip chip no longer
212
+ scans every cell on each pointer move.
213
+ - **Hovering a hidden series' legend entry dims nothing.** It highlighted the
214
+ series that is not drawn, and every visible one was dimmed.
215
+ - **A time axis over years labels a year as `2026`**, by level, not as
216
+ `Jan 2026`.
217
+ - **The legend's focus ring couples through `--uc-focus-ring`**, like every
218
+ other value of the stylesheet, with `--u-focus-ring` and a literal behind
219
+ it.
220
+ - **A downsampled course keeps a gap at the end of a pixel column.** Only the
221
+ first gap of a column was kept: a column running gap - points - gap lost the
222
+ second, and the line bridged to data far away.
223
+ - **The cursor sync.** A chart without a `Tooltip` shared no position; it now
224
+ shares the pointer's x. A chart that leaves its group - another `syncId`, or
225
+ unmounted - no longer keeps the crosshair the group last sent it.
226
+ - **An x limit's label stays inside the container** at the right edge, as a
227
+ tick label does; it ran past it.
228
+ - **No hover marker outside the plot.** At a zoomed edge the nearest reading
229
+ can lie beyond it, and its marker stood on the axis.
230
+ - **The tooltip header on a time axis carries the seconds** where the
231
+ readings under the pointer lie less than a minute apart - readings a second
232
+ apart shared one header. Otherwise it stays `17 Mar 15:23`.
233
+ - **A double click proposes no domain without width.** Over a single point
234
+ the data range is one value; the double click handed it to
235
+ `onDomainChange` all the same, where a wheel step checks for that.
236
+
237
+ ---
238
+
32
239
  ## 0.3.2 – Phones, touch and a review (Sep. 2026)
33
240
 
34
241
  ### Fixed
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @umriss-ui/charts
2
2
 
3
3
  Canvas-based charts for data-dense applications: few chart kinds, each one drawn
4
- properly. Lines, areas, bars, scatters, state bands, matrices and spans compose
5
- into one chart on shared axes — together with the instruments a plant screen is
4
+ properly. Lines, areas, bars, scatters, state bands and matrices compose into
5
+ one chart on shared axes — together with the instruments a plant screen is
6
6
  made of: limit lines and bands, a control chart, a Pareto and an operating-time
7
7
  axis.
8
8
 
@@ -74,8 +74,9 @@ loaded: Geist when the application has it, the system fonts otherwise.
74
74
 
75
75
  ## What it can do
76
76
 
77
- * **Seven series kinds** in one chart on shared axes: `Line`, `Area`, `Bar`,
78
- `Scatter`, `StateBand`, `Matrix`, `Span`.
77
+ * **Six series kinds** in one chart on shared axes: `Line`, `Area`, `Bar`,
78
+ `Scatter`, `StateBand`, `Matrix`. Occupancy — jobs on machines, idle time,
79
+ double bookings — is `@umriss-ui/schedule`'s (ADR-0026).
79
80
  * **Several axes per orientation**, each with its own extent; only the first
80
81
  registered axis per orientation draws a grid.
81
82
  * **The instruments**: `LimitLine` and `LimitBand`, `ControlChart` with its four
package/dist/charts.css CHANGED
@@ -1 +1 @@
1
- @layer umriss.tokens,umriss.base,umriss.components;@layer umriss.components{.uc-root,.uc-root:before,.uc-root:after{box-sizing:border-box}.uc-plot,.uc-plot:before,.uc-plot:after{box-sizing:border-box}.uc-axes,.uc-axes:before,.uc-axes:after{box-sizing:border-box}.uc-axis,.uc-axis:before,.uc-axis:after{box-sizing:border-box}.uc-axis-line,.uc-axis-line:before,.uc-axis-line:after{box-sizing:border-box}.uc-axis-y,.uc-axis-y:before,.uc-axis-y:after{box-sizing:border-box}.uc-axis-left,.uc-axis-left:before,.uc-axis-left:after{box-sizing:border-box}.uc-axis-right,.uc-axis-right:before,.uc-axis-right:after{box-sizing:border-box}.uc-axis-x,.uc-axis-x:before,.uc-axis-x:after{box-sizing:border-box}.uc-axis-bottom,.uc-axis-bottom:before,.uc-axis-bottom:after{box-sizing:border-box}.uc-axis-top,.uc-axis-top:before,.uc-axis-top:after{box-sizing:border-box}.uc-tick,.uc-tick:before,.uc-tick:after{box-sizing:border-box}.uc-tick-mark,.uc-tick-mark:before,.uc-tick-mark:after{box-sizing:border-box}.uc-tick-label,.uc-tick-label:before,.uc-tick-label:after{box-sizing:border-box}.uc-axis-title,.uc-axis-title:before,.uc-axis-title:after{box-sizing:border-box}.uc-legend,.uc-legend:before,.uc-legend:after{box-sizing:border-box}.uc-legend-top,.uc-legend-top:before,.uc-legend-top:after{box-sizing:border-box}.uc-legend-bottom,.uc-legend-bottom:before,.uc-legend-bottom:after{box-sizing:border-box}.uc-legend-item,.uc-legend-item:before,.uc-legend-item:after{box-sizing:border-box}.uc-legend-chip,.uc-legend-chip:before,.uc-legend-chip:after{box-sizing:border-box}.uc-tooltip,.uc-tooltip:before,.uc-tooltip:after{box-sizing:border-box}.uc-tooltip-head,.uc-tooltip-head:before,.uc-tooltip-head:after{box-sizing:border-box}.uc-tooltip-list,.uc-tooltip-list:before,.uc-tooltip-list:after{box-sizing:border-box}.uc-tooltip-row,.uc-tooltip-row:before,.uc-tooltip-row:after{box-sizing:border-box}.uc-tooltip-chip,.uc-tooltip-chip:before,.uc-tooltip-chip:after{box-sizing:border-box}.uc-tooltip-name,.uc-tooltip-name:before,.uc-tooltip-name:after{box-sizing:border-box}.uc-tooltip-value,.uc-tooltip-value:before,.uc-tooltip-value:after{box-sizing:border-box}.uc-measure,.uc-measure:before,.uc-measure:after{box-sizing:border-box}.uc-limit-label,.uc-limit-label:before,.uc-limit-label:after{box-sizing:border-box}.uc-break,.uc-break:before,.uc-break:after{box-sizing:border-box}.uc-root{--uc-color-axis: var(--u-edge-color-strong, rgba(23, 23, 23, .17));--uc-color-grid: var(--u-hairline, rgba(23, 23, 23, .06));--uc-color-text: var(--u-color-text-muted, #71717a);--uc-color-bg: var(--u-color-surface, #ffffff);--uc-font: var( --u-font-sans, "Geist Sans", "Geist", -apple-system, "Segoe UI", system-ui, sans-serif );--uc-font-mono: var( --u-font-mono, "Geist Mono", ui-monospace, "Cascadia Mono", "Consolas", monospace );--uc-color-warning: var(--u-color-warning, #8a5c00);--uc-color-alarm: var(--u-color-danger, #b13636);--uc-color-ok: var(--u-color-success, #217a4b);--uc-series-1: var(--u-chart-1, #2563eb);--uc-series-2: var(--u-chart-2, #db2777);--uc-series-3: var(--u-chart-3, #059669);--uc-series-4: var(--u-chart-4, #d97706);--uc-series-5: var(--u-chart-5, #7c3aed);--uc-series-6: var(--u-chart-6, #0891b2);--uc-size-tick: 11.5px;--uc-size-title: 12px;--uc-size-legend: 12.5px;--uc-radius: 6px;--uc-shadow: 0 1px 2px rgba(0, 0, 0, .06), 0 4px 12px rgba(0, 0, 0, .08);position:relative;display:flex;flex-direction:column;font-family:var(--uc-font);color:var(--uc-color-text);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}.uc-plot{position:relative;flex:1 1 auto;min-height:0;min-width:0}.uc-plot>canvas{box-sizing:border-box}.uc-plot>canvas{position:absolute;top:0;right:0;bottom:0;left:0;display:block;pointer-events:none}.uc-axes{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.uc-axis{position:absolute}.uc-axis-line{position:absolute;background:var(--uc-color-axis)}.uc-axis-y>.uc-axis-line{top:0;width:1px;height:100%}.uc-axis-left>.uc-axis-line{right:0}.uc-axis-right>.uc-axis-line{left:0}.uc-axis-x>.uc-axis-line{left:0;width:100%;height:1px}.uc-axis-bottom>.uc-axis-line{top:0}.uc-axis-top>.uc-axis-line{bottom:0}.uc-tick{position:absolute}.uc-axis-y>.uc-tick{left:0;right:0;height:1px}.uc-axis-x>.uc-tick{top:0;bottom:0;width:1px}.uc-tick-mark{position:absolute;background:var(--uc-color-axis)}.uc-axis-y>.uc-tick>.uc-tick-mark{top:0;width:5px;height:1px}.uc-axis-left>.uc-tick>.uc-tick-mark{right:0}.uc-axis-right>.uc-tick>.uc-tick-mark{left:0}.uc-axis-x>.uc-tick>.uc-tick-mark{left:0;width:1px;height:5px}.uc-axis-bottom>.uc-tick>.uc-tick-mark{top:0}.uc-axis-top>.uc-tick>.uc-tick-mark{bottom:0}.uc-tick-label{position:absolute;white-space:pre;font-size:var(--uc-size-tick);line-height:1.25;letter-spacing:.005em;color:var(--uc-color-text)}.uc-axis-y>.uc-tick>.uc-tick-label{top:50%;transform:translateY(-50%)}.uc-axis-left>.uc-tick>.uc-tick-label{text-align:right}.uc-axis-right>.uc-tick>.uc-tick-label{text-align:left}.uc-axis-title{position:absolute;white-space:pre;font-size:var(--uc-size-title);line-height:1.25;letter-spacing:.01em;color:var(--uc-color-text)}.uc-axis-x>.uc-axis-title{left:0;right:0;text-align:center}.uc-axis-bottom>.uc-axis-title{bottom:0}.uc-axis-top>.uc-axis-title{top:0}.uc-axis-y>.uc-axis-title{top:50%;writing-mode:vertical-rl}.uc-axis-left>.uc-axis-title{left:0;transform:translateY(-50%) rotate(180deg)}.uc-axis-right>.uc-axis-title{right:0;transform:translateY(-50%)}.uc-legend{display:flex;flex-wrap:wrap;gap:4px 14px;font-size:var(--uc-size-legend);line-height:1.35;color:var(--uc-color-text)}.uc-legend-top{order:-1;padding-bottom:8px}.uc-legend-bottom{order:1;padding-top:8px}.uc-legend-item{display:inline-flex;align-items:center;gap:6px;cursor:default}.uc-legend-chip{display:inline-block;width:10px;height:10px;border-radius:2px;corner-shape:squircle}.uc-tooltip{position:absolute;top:0;left:0;z-index:2;pointer-events:none;opacity:0;transition:opacity 80ms ease-out;min-width:96px;padding:7px 9px;border:1px solid var(--uc-color-axis);border-radius:var(--uc-radius);corner-shape:squircle;background:var(--uc-color-bg);box-shadow:var(--uc-shadow);font-size:12px;line-height:1.35;color:var(--uc-color-text)}.uc-tooltip-head{font-family:var(--uc-font-mono);font-size:11.5px;letter-spacing:.01em;padding-bottom:5px;margin-bottom:5px;border-bottom:1px solid var(--uc-color-grid)}.uc-tooltip-list{display:grid;grid-template-columns:auto 1fr auto;gap:3px 8px;align-items:center}.uc-tooltip-row{display:contents}.uc-tooltip-chip{width:8px;height:8px;border-radius:2px;corner-shape:squircle}.uc-tooltip-name{white-space:nowrap}.uc-tooltip-value{font-family:var(--uc-font-mono);text-align:right;white-space:nowrap}@media(prefers-reduced-motion:reduce){.uc-tooltip{transition:none}}.uc-measure{position:absolute;top:0;left:0;right:auto;bottom:auto;transform:none;visibility:hidden;pointer-events:none;white-space:pre;writing-mode:horizontal-tb}.uc-limit-label{position:absolute;font-size:var(--uc-size-tick);line-height:1.25;white-space:nowrap;font-variant-numeric:tabular-nums;background:var(--uc-color-bg);padding:0 2px}.uc-limit-label[data-severity=warning]{color:var(--uc-color-warning)}.uc-limit-label[data-severity=alarm]{color:var(--uc-color-alarm)}.uc-limit-label[data-role=control],.uc-limit-label[data-role=zone]{color:var(--uc-color-text)}.uc-axis-y .uc-limit-label{transform:translateY(-50%)}.uc-axis-left .uc-limit-label{right:9px}.uc-axis-right .uc-limit-label{left:9px}.uc-break{position:absolute;top:0;width:7px;height:9px;margin-left:-3.5px;color:var(--uc-color-text)}.uc-break:before,.uc-break:after{content:"";position:absolute;top:0;width:1px;height:9px;background:currentColor;opacity:.55;transform:skew(-20deg)}.uc-break:before{left:1px}.uc-break:after{left:4px}}
1
+ @layer umriss.tokens,umriss.base,umriss.components;@layer umriss.components{.uc-root,.uc-root:before,.uc-root:after{box-sizing:border-box}.uc-plot,.uc-plot:before,.uc-plot:after{box-sizing:border-box}.uc-axes,.uc-axes:before,.uc-axes:after{box-sizing:border-box}.uc-axis,.uc-axis:before,.uc-axis:after{box-sizing:border-box}.uc-axis-line,.uc-axis-line:before,.uc-axis-line:after{box-sizing:border-box}.uc-axis-y,.uc-axis-y:before,.uc-axis-y:after{box-sizing:border-box}.uc-axis-left,.uc-axis-left:before,.uc-axis-left:after{box-sizing:border-box}.uc-axis-right,.uc-axis-right:before,.uc-axis-right:after{box-sizing:border-box}.uc-axis-x,.uc-axis-x:before,.uc-axis-x:after{box-sizing:border-box}.uc-axis-bottom,.uc-axis-bottom:before,.uc-axis-bottom:after{box-sizing:border-box}.uc-axis-top,.uc-axis-top:before,.uc-axis-top:after{box-sizing:border-box}.uc-tick,.uc-tick:before,.uc-tick:after{box-sizing:border-box}.uc-tick-mark,.uc-tick-mark:before,.uc-tick-mark:after{box-sizing:border-box}.uc-tick-label,.uc-tick-label:before,.uc-tick-label:after{box-sizing:border-box}.uc-axis-title,.uc-axis-title:before,.uc-axis-title:after{box-sizing:border-box}.uc-empty,.uc-empty:before,.uc-empty:after{box-sizing:border-box}.uc-legend,.uc-legend:before,.uc-legend:after{box-sizing:border-box}.uc-legend-top,.uc-legend-top:before,.uc-legend-top:after{box-sizing:border-box}.uc-legend-bottom,.uc-legend-bottom:before,.uc-legend-bottom:after{box-sizing:border-box}.uc-legend-item,.uc-legend-item:before,.uc-legend-item:after{box-sizing:border-box}.uc-legend-chip,.uc-legend-chip:before,.uc-legend-chip:after{box-sizing:border-box}.uc-tooltip,.uc-tooltip:before,.uc-tooltip:after{box-sizing:border-box}.uc-tooltip-head,.uc-tooltip-head:before,.uc-tooltip-head:after{box-sizing:border-box}.uc-tooltip-list,.uc-tooltip-list:before,.uc-tooltip-list:after{box-sizing:border-box}.uc-tooltip-row,.uc-tooltip-row:before,.uc-tooltip-row:after{box-sizing:border-box}.uc-tooltip-chip,.uc-tooltip-chip:before,.uc-tooltip-chip:after{box-sizing:border-box}.uc-tooltip-name,.uc-tooltip-name:before,.uc-tooltip-name:after{box-sizing:border-box}.uc-tooltip-x,.uc-tooltip-x:before,.uc-tooltip-x:after{box-sizing:border-box}.uc-tooltip-value,.uc-tooltip-value:before,.uc-tooltip-value:after{box-sizing:border-box}.uc-measure,.uc-measure:before,.uc-measure:after{box-sizing:border-box}.uc-limit-label,.uc-limit-label:before,.uc-limit-label:after{box-sizing:border-box}.uc-break,.uc-break:before,.uc-break:after{box-sizing:border-box}.uc-root{--uc-color-axis: var(--u-edge-color-strong, rgba(23, 23, 23, .17));--uc-color-grid: var(--u-hairline, rgba(23, 23, 23, .06));--uc-color-text: var(--u-color-text-muted, #71717a);--uc-color-bg: var(--u-color-surface, #ffffff);--uc-font: var( --u-font-sans, "Geist Sans", "Geist", -apple-system, "Segoe UI", system-ui, sans-serif );--uc-font-mono: var( --u-font-mono, "Geist Mono", ui-monospace, "Cascadia Mono", "Consolas", monospace );--uc-color-warning: var(--u-color-warning, #8a5c00);--uc-color-alarm: var(--u-color-danger, #b13636);--uc-color-ok: var(--u-color-success, #217a4b);--uc-series-1: var(--u-chart-1, #2563eb);--uc-series-2: var(--u-chart-2, #db2777);--uc-series-3: var(--u-chart-3, #059669);--uc-series-4: var(--u-chart-4, #d97706);--uc-series-5: var(--u-chart-5, #7c3aed);--uc-series-6: var(--u-chart-6, #0891b2);--uc-size-tick: 11.5px;--uc-size-title: 12px;--uc-size-legend: 12.5px;--uc-radius: 6px;--uc-shadow: 0 1px 2px rgba(0, 0, 0, .06), 0 4px 12px rgba(0, 0, 0, .08);--uc-focus-ring: var(--u-focus-ring, 0 0 0 2px #0e7d72);position:relative;display:flex;flex-direction:column;font-family:var(--uc-font);color:var(--uc-color-text);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}.uc-plot{position:relative;flex:1 1 auto;min-height:0;min-width:0}.uc-plot>canvas{box-sizing:border-box}.uc-plot>canvas{position:absolute;top:0;right:0;bottom:0;left:0;display:block;pointer-events:none}.uc-axes{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.uc-axis{position:absolute}.uc-axis-line{position:absolute;background:var(--uc-color-axis)}.uc-axis-y>.uc-axis-line{top:0;width:1px;height:100%}.uc-axis-left>.uc-axis-line{right:0}.uc-axis-right>.uc-axis-line{left:0}.uc-axis-x>.uc-axis-line{left:0;width:100%;height:1px}.uc-axis-bottom>.uc-axis-line{top:0}.uc-axis-top>.uc-axis-line{bottom:0}.uc-tick{position:absolute}.uc-axis-y>.uc-tick{left:0;right:0;height:1px}.uc-axis-x>.uc-tick{top:0;bottom:0;width:1px}.uc-tick-mark{position:absolute;background:var(--uc-color-axis)}.uc-axis-y>.uc-tick>.uc-tick-mark{top:0;width:5px;height:1px}.uc-axis-left>.uc-tick>.uc-tick-mark{right:0}.uc-axis-right>.uc-tick>.uc-tick-mark{left:0}.uc-axis-x>.uc-tick>.uc-tick-mark{left:0;width:1px;height:5px}.uc-axis-bottom>.uc-tick>.uc-tick-mark{top:0}.uc-axis-top>.uc-tick>.uc-tick-mark{bottom:0}.uc-tick-label{position:absolute;white-space:pre;font-size:var(--uc-size-tick);line-height:1.25;letter-spacing:.005em;color:var(--uc-color-text)}.uc-axis-y>.uc-tick>.uc-tick-label{top:50%;transform:translateY(-50%)}.uc-axis-left>.uc-tick>.uc-tick-label{text-align:right}.uc-axis-right>.uc-tick>.uc-tick-label{text-align:left}.uc-axis-title{position:absolute;white-space:pre;font-size:var(--uc-size-title);line-height:1.25;letter-spacing:.01em;color:var(--uc-color-text)}.uc-axis-x>.uc-axis-title{left:0;right:0;text-align:center}.uc-axis-bottom>.uc-axis-title{bottom:0}.uc-axis-top>.uc-axis-title{top:0}.uc-axis-y>.uc-axis-title{top:50%;writing-mode:vertical-rl}.uc-axis-left>.uc-axis-title{left:0;transform:translateY(-50%) rotate(180deg)}.uc-axis-right>.uc-axis-title{right:0;transform:translateY(-50%)}.uc-empty{position:absolute;display:flex;align-items:center;justify-content:center;text-align:center;font-size:var(--uc-size-legend);color:var(--uc-color-text)}.uc-legend{display:flex;flex-wrap:wrap;gap:4px 14px;font-size:var(--uc-size-legend);line-height:1.35;color:var(--uc-color-text)}.uc-legend-top{order:-1;padding-bottom:8px}.uc-legend-bottom{order:1;padding-top:8px}.uc-legend-item{display:inline-flex;align-items:center;gap:6px;cursor:default}.uc-legend-chip{display:inline-block;width:10px;height:10px;border-radius:2px;corner-shape:squircle}button.uc-legend-item{box-sizing:border-box}button.uc-legend-item{padding:0;border:0;border-radius:2px;corner-shape:squircle;background:none;font:inherit;color:inherit;cursor:pointer}button.uc-legend-item:focus-visible{box-sizing:border-box}button.uc-legend-item:focus-visible{outline:none;box-shadow:var(--uc-focus-ring)}.uc-legend-item[data-hidden]{text-decoration:line-through}.uc-legend-item[data-hidden]>.uc-legend-chip{opacity:.3}.uc-tooltip{position:absolute;top:0;left:0;z-index:2;pointer-events:none;opacity:0;transition:opacity 80ms ease-out;min-width:96px;padding:7px 9px;border:1px solid var(--uc-color-axis);border-radius:var(--uc-radius);corner-shape:squircle;background:var(--uc-color-bg);box-shadow:var(--uc-shadow);font-size:12px;line-height:1.35;color:var(--uc-color-text)}.uc-tooltip-head{font-family:var(--uc-font-mono);font-size:11.5px;letter-spacing:.01em;padding-bottom:5px;margin-bottom:5px;border-bottom:1px solid var(--uc-color-grid)}.uc-tooltip-list{display:grid;grid-template-columns:auto 1fr auto;gap:3px 8px;align-items:center}.uc-tooltip-row{display:contents}.uc-tooltip-chip{width:8px;height:8px;border-radius:2px;corner-shape:squircle}.uc-tooltip-name{white-space:nowrap}.uc-tooltip-x{margin-left:6px;font-family:var(--uc-font-mono)}.uc-tooltip-value{font-family:var(--uc-font-mono);text-align:right;white-space:nowrap}@media(prefers-reduced-motion:reduce){.uc-tooltip{transition:none}}.uc-measure{position:absolute;top:0;left:0;right:auto;bottom:auto;transform:none;visibility:hidden;pointer-events:none;white-space:pre;writing-mode:horizontal-tb}.uc-limit-label{position:absolute;font-size:var(--uc-size-tick);line-height:1.25;white-space:nowrap;font-variant-numeric:tabular-nums;background:var(--uc-color-bg);padding:0 2px}.uc-limit-label[data-severity=warning]{color:var(--uc-color-warning)}.uc-limit-label[data-severity=alarm]{color:var(--uc-color-alarm)}.uc-limit-label[data-role=control],.uc-limit-label[data-role=zone]{color:var(--uc-color-text)}.uc-axis-y .uc-limit-label{transform:translateY(-50%)}.uc-axis-left .uc-limit-label{right:9px}.uc-axis-right .uc-limit-label{left:9px}.uc-break{position:absolute;top:0;width:7px;height:9px;margin-left:-3.5px;color:var(--uc-color-text)}.uc-break:before,.uc-break:after{content:"";position:absolute;top:0;width:1px;height:9px;background:currentColor;opacity:.55;transform:skew(-20deg)}.uc-break:before{left:1px}.uc-break:after{left:4px}}