@umriss-ui/schedule 0.41.1 → 0.43.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
@@ -4,9 +4,11 @@ This document describes what changes for **callers** of the package: exports,
4
4
  props, behaviour.
5
5
 
6
6
  **The numbers.** The middle digit rises when something is added; the last one
7
- when something is repaired. As long as the first digit is `0`, no number
8
- promises compatibility — which is why whatever changes existing behaviour stands
9
- under a heading "Changed" of its own, no matter which digit rose.
7
+ when something is repaired. The six packages are released in step, and a rename
8
+ keeps its old name for one further minor, with a warning, before the minor after
9
+ it removes the name ([the upgrade promise, ADR-0066](../../docs/adr/0066-one-number-peers-over-the-minor-a-rename-lives-one-minor.md)).
10
+ Whatever changes existing behaviour stands under a heading "Changed" of its own,
11
+ no matter which digit rose, with a `Migration:` line.
10
12
 
11
13
  From 0.34.0 the packages share one number - five, and six from 0.40.0, when the dashboard joined: they are released together, and a package without a change of its own still gets a heading for it.
12
14
 
@@ -16,12 +18,54 @@ moves from here under the rule above.
16
18
 
17
19
  ---
18
20
 
21
+ ## 0.43.0 – A schedule that fills its frame, and takes a finger (Oct. 2026)
22
+
23
+ ### Added
24
+
25
+ - **`loading`**, as the chart has it: a plan stays, dims after `--u-delay-stale` and starts no drag, tooltip, context menu or key intent until the answer is in; a drag begun before it finishes. With no lanes, placeholder lines stand in the lane column. The plot is `aria-busy`, also in a server's markup.
26
+ - **Touch editing:** a long press on a bar grabs it, and the finger then moves it in time and across lanes as a mouse does, with `canMoveTo`, blocked time and auto-pan; stretching and lead-in/out stay with the mouse, pen and keyboard. A second finger cancels the grab, and the page does not scroll under a grabbed bar (ADR-0070).
27
+ - **`scrollToLane(lane)`, `scrollToSubtask(id)` and `focusSubtask(id)` on `useSchedule`'s return** show a lane or a subtask picked from a list of your own. `scrollToSubtask` brings the subtask's lane and time into view - the span moves to it and keeps its width - and leaves the focus; `focusSubtask` also makes it the Active subtask and focuses the plot. All three return `false` and change nothing for an unknown lane or subtask, a lane inside a folded group (none is unfolded) and a schedule that is not mounted.
28
+ - **`positionAt`, `clientPointOf` and `visibleDomain` on `useSchedule`'s return**, the functions the handle ref carried; the first two return `null` before mount.
29
+
30
+ ### Changed
31
+
32
+ - **Without `height` a schedule fills its frame and never goes below 400 px** (ADR-0050, amended). Alone in a block it is 400 px as before, whatever its lanes; in a frame taller than that it now takes that height.
33
+ - Migration: a schedule that relied on the 400 px default in a taller frame sets `height={400}` or `style={{ height: 400 }}`.
34
+ - **The schedule's `ref` is its root `<div>`** (ADR-0068): `className`, `style`, `id` and `data-*` reach it, `aria-label` and `aria-labelledby` name it, and a caller's `aria-describedby` follows the plot's own summary.
35
+ - Migration: nothing to change for an element ref.
36
+ - **`ScheduleHandle` is deprecated; 0.44.0 removes it.** A handle ref keeps working for this minor and warns once in development on its first call.
37
+ - Migration: replace `ref.current.positionAt(x, y)` with `positionAt(x, y)` from `const { positionAt } = useSchedule()`, and the same for `clientPointOf` and `visibleDomain`.
38
+ - **`ariaLabel` on `Schedule` is renamed `aria-label`.** `ariaLabel` stays as a deprecated alias and warns once in development; 0.44.0 removes it.
39
+ - Migration: write `aria-label`.
40
+ - **A vertical swipe over the plot scrolls the page while every lane fits.** While the lanes overflow, the plot keeps the swipe and scrolls its lanes; the lane names scroll the page.
41
+ - Migration: nothing to change; on a touch device a short plan no longer traps the page's scroll.
42
+ - **The peer ranges on core and charts move to `^0.43.0`.**
43
+ - Migration: install the 0.43 versions of `@umriss-ui/core` and `@umriss-ui/charts` beside it.
44
+
45
+ ## 0.42.0 – A schedule under test, and quiet on a server (Oct. 2026)
46
+
47
+ ### Added
48
+
49
+ - **Loadable in Vitest and Jest** with core's and charts' lines one after the other: the `.` entry carries a `default` condition, the README's "Testing" section says how the two setup files combine, and the release check runs a test of a lane with a bar under both runners.
50
+ - **TypeScript 5.4 or newer**, stated in the Install section (the declarations use `NoInfer`); the release check compiles a strict consumer under 5.4 as well as the current TypeScript.
51
+
52
+ ### Changed
53
+
54
+ - **The peer range on core and charts covers the minor: `^0.42.0`.** It named the exact patch before (`^0.41.1`), so npm refused an install beside an earlier patch of core with `ERESOLVE`; the six packages move under one number and a minor moves the range (ADR-0066).
55
+ - Migration: nothing to change; any 0.42 patch of `@umriss-ui/core` and `@umriss-ui/charts` satisfies the peers.
56
+ - **On a server the schedule's description holds no summary.** A server knows no lanes, so it described "0 lanes, 0 subtasks" for a plan that had both; the summary arrives with the lanes after mount, and the key help stays.
57
+ - Migration: nothing to change; a server-rendered test that read the summary's counts finds the key help only.
58
+ - **A date or time rendered on a server is empty until the page has hydrated** (core 0.42.0, ADR-0067). Only the browser knows the reader's zone, so a server in another zone wrote a different text and React raised hydration error #418; the schedule now shows its dates and times right after hydration.
59
+ - Migration: nothing to change in an application that renders in the browser; a test that renders to a string and expects a date finds an empty text - render it in the DOM instead.
60
+
19
61
  ## 0.41.1 – The documentation runs where the code is (Oct. 2026)
20
62
 
21
63
  ### Changed
22
64
 
23
65
  - **The documentation is no longer hosted.** The site on GitHub Pages is gone, and the package's `homepage` now names its README on GitHub. The running documentation of this version opens from a checkout of the tag `schedule-v0.41.1` with `pnpm install` and `pnpm start`, at `http://localhost:4170/umriss-ui/` - the repository README says how, under "See it running".
66
+ - Migration: nothing to change; a bookmark or link to the old hosted site no longer resolves - open the documentation from a checkout of the tag, as described above.
24
67
  - **`docs/llms-full.md` in the package stands on its own:** a link to another page points at that page's heading in the same file, a link to a place on the site that the file does not hold keeps only its text, and ADR-0032 is linked at this version's tag.
68
+ - Migration: nothing to change; look at any tool that read `docs/llms-full.md` and followed its links to the site, which now find the heading in the same file.
25
69
 
26
70
  ## 0.41.0 – Strict consumers compile (Oct. 2026)
27
71
 
package/README.md CHANGED
@@ -19,17 +19,18 @@ Both `@umriss-ui/core` and `@umriss-ui/charts` are **peer dependencies**
19
19
  (ADR-0022): the schedule takes its styling regime, provider, formats and
20
20
  wording from core, and its time arithmetic — the affine scale, the time steps,
21
21
  the working calendar, the canvas colour resolution — from charts. React 19 or
22
- newer as a peer as well.
22
+ newer as a peer as well. TypeScript 5.4 or newer (the declarations use `NoInfer`).
23
23
 
24
24
  The package ships ES2022 syntax; an application that serves older browsers
25
25
  transpiles it itself.
26
26
 
27
27
  Every entry begins with `"use client"`, the directive a framework
28
- with Server Components reads to treat a module as client code. No test runs
29
- inside such a framework: the
30
- schedule is rendered to a string in a test. On a server it gives its labelled
31
- frame and empty canvases; the lanes, subtasks and the summary's counts arrive
32
- on the client after mount.
28
+ with Server Components reads to treat a module as client code. A schedule is declared by its hook,
29
+ `useSchedule`, so the declaration lives in a Client Component file: a Server Component renders that
30
+ file and hands it the rows and subtasks. On a server a schedule gives its labelled frame and empty
31
+ canvases; the lanes, the subtasks and the summary arrive on the client after mount, and a date or
32
+ time is empty until the page has hydrated, because only the browser knows the reader's zone. No test
33
+ runs inside such a framework: the schedule is rendered to a string in a test.
33
34
 
34
35
  ## The smallest schedule that runs
35
36
 
@@ -49,7 +50,7 @@ const dependencies: Dependency[] = [{ id: "move", from: "cut", to: "mill", lag:
49
50
  export function Plan() {
50
51
  const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(5), at(12)] } });
51
52
  return (
52
- <Schedule ariaLabel="Plan of Tuesday">
53
+ <Schedule aria-label="Plan of Tuesday">
53
54
  <Lane id="saw" label="Saw" />
54
55
  <Lane id="mill" label="Mill" />
55
56
  <Dependencies data={dependencies} />
@@ -135,10 +136,20 @@ A tooltip on a hovered subtask or dependency names the order, the times, lead-in
135
136
  and lead-out and the findings; `tooltip` replaces its content or switches it
136
137
  off. `now` draws the present across the lanes. The wheel over the schedule,
137
138
  lane headers included, scrolls the lanes and releases the page at their end,
138
- Ctrl or ⌘ and a pinch zoom, Shift pans; on a touch screen one finger pans and a
139
- tap selects. The lane headers take at most 40 % of the width, so that on a
140
- phone the plot keeps the larger part; a ref handle turns a client point into a
141
- time and a lane and back.
139
+ Ctrl or ⌘ and a pinch zoom, Shift pans; on a touch screen one finger pans, a
140
+ tap selects and a long press on a bar grabs it (with `"move"` or `"lane"` in `intents`), and a vertical swipe scrolls the page while all lanes fit (when they
141
+ overflow, the lane names scroll the page). The lane headers take at most 40 % of the width, so that on a
142
+ phone the plot keeps the larger part; `positionAt` and `clientPointOf`, on what
143
+ `useSchedule` hands back, turn a client point into a time and a lane and back.
144
+
145
+ ## Its size
146
+
147
+ The width is the host's. Without `height`, a schedule fills its frame - a stretched grid cell, a card the
148
+ grid stretches, a container of definite height - and never goes below 400 px, which is also its height in
149
+ a frame without one: alone in a block it is 400 px however many lanes it holds, and the lanes beyond the
150
+ plot scroll inside it (ADR-0050). A number stays a fixed height. A different floor goes through `style`'s
151
+ `minHeight`, and `style` wins over the schedule's own sizing. A wrapper of your own between the frame and
152
+ the schedule passes the height on with `height: 100%`.
142
153
 
143
154
  ## The view
144
155
 
@@ -148,7 +159,11 @@ reports what the planner does, always the whole view; two schedules keep in
148
159
  step by sending each other what they report through `setView`, which is not
149
160
  reported in turn. Without a span the schedule shows the extent of its subtasks.
150
161
  `view`, `setView`, `setDomain`, `toggleGroup`, `foldAll` and `unfoldAll` stand on what the
151
- hook hands back.
162
+ hook hands back. `setDomain(span)` zooms to a span of two instants; `setDomain(null)` fits the work.
163
+
164
+ The schedule is a composite: its `ref`, `className`, `style`, `id` and `data-*` reach the root `<div>`;
165
+ `aria-label` (required) and `aria-labelledby` name the figure and the plot, and your `aria-describedby`
166
+ is joined to the plot's summary.
152
167
 
153
168
  ## Blocked time
154
169
 
@@ -199,6 +214,14 @@ Done from this list: **blocked time** per lane and **milestones**.
199
214
  * [`../../docs/design-language.md`](../../docs/design-language.md) — the design
200
215
  language all five packages share.
201
216
 
217
+ ## Testing
218
+
219
+ Tested under Vitest 5 and Jest 30 on jsdom. A schedule draws with core and charts, so it needs the
220
+ runner lines and the setup file of [`@umriss-ui/core`'s Testing section](../core/README.md#testing)
221
+ and the setup file of [`@umriss-ui/charts`'](../charts/README.md#testing), one file after the other
222
+ in your `umriss.setup.js`. `check:dist` runs a test of the installed schedule (a lane with a bar)
223
+ with exactly those files.
224
+
202
225
  ## Licence
203
226
 
204
227
  MIT — see [`LICENSE`](LICENSE).
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { CalendarInput } from '@umriss-ui/charts';
2
- import { CSSProperties } from 'react';
2
+ import { HTMLAttributes } from 'react';
3
3
  import { ReactNode } from 'react';
4
4
  import { Ref } from 'react';
5
+ import { RefObject } from 'react';
5
6
 
6
7
  /** The subtask as the intent asks for it. An intent for another subtask leaves
7
8
  it as it is. */
@@ -346,7 +347,8 @@ export declare interface ResolvedAppearance {
346
347
  export declare function ripple(subtasks: readonly Subtask[], dependencies: readonly Dependency[], intent: Intent): MoveIntent[];
347
348
 
348
349
  /** What a schedule offers a caller imperatively: the arithmetic between a
349
- point on the screen and a time on a lane. Everything else is props. */
350
+ point on the screen and a time on a lane. Everything else is props.
351
+ @deprecated since 0.43 - use the functions on `useSchedule`'s return. */
350
352
  export declare interface ScheduleHandle {
351
353
  /** The time and the lane at a client point, or null outside the plot. */
352
354
  positionAt: (clientX: number, clientY: number) => {
@@ -413,43 +415,17 @@ export declare interface ScheduleOptions {
413
415
  onViewChange?: (view: ScheduleView) => void;
414
416
  }
415
417
 
416
- /** What `useSchedule` hands back: the schedule and what is declared inside
417
- it, its view and the setters that change it. */
418
- export declare interface ScheduleParts {
419
- /** The schedule. One per `useSchedule`: a second schedule is a second call. */
420
- Schedule: (props: ScheduleProps) => ReactNode;
421
- Lane: typeof Lane;
422
- LaneGroup: typeof LaneGroup;
423
- Subtasks: typeof Subtasks;
424
- Dependencies: typeof Dependencies;
425
- BlockedTimes: typeof BlockedTimes;
426
- Milestones: typeof Milestones;
427
- /** How the planner is looking at the plan: the span and the folded groups. */
428
- view: ScheduleView;
429
- /** Goes to a whole view; what it leaves out is shown whole again. Not
430
- reported through `onViewChange`: two schedules kept in step by
431
- `onViewChange: (v) => other.setView(v)` in both directions do not answer
432
- each other. A view with the content already shown changes nothing. */
433
- setView: (view: ScheduleView) => void;
434
- /** Puts a span of two wall-clock instants in view; `null` shows the
435
- subtasks' extent. */
436
- setDomain: (span: readonly [number, number] | null) => void;
437
- /** Folds or unfolds one **Lane group**. */
438
- toggleGroup: (id: string) => void;
439
- /** Folds every group. */
440
- foldAll: () => void;
441
- /** Unfolds every group. */
442
- unfoldAll: () => void;
443
- }
444
-
445
- /** The props of `Schedule`. */
446
- export declare interface ScheduleProps {
447
- /** Receives the `ScheduleHandle` - not an element. */
448
- ref?: Ref<ScheduleHandle>;
449
- /** What the schedule shows, for a screen reader: "Plan of week 38". */
450
- ariaLabel: string;
451
- /** Height in CSS pixels, both bands included. The width is the host's.
452
- @default 400 */
418
+ declare interface ScheduleOwnProps extends Omit<HTMLAttributes<HTMLDivElement>, "children" | "aria-label"> {
419
+ /** Receives the root element. A ref to the deprecated `ScheduleHandle` still
420
+ works for one more minor release: the element carries its three
421
+ functions. */
422
+ ref?: Ref<HTMLDivElement> | RefObject<ScheduleHandle | null> | undefined;
423
+ /** Height in CSS pixels, both bands included, fixed. Left out, the schedule
424
+ fills its frame - a stretched grid cell, a card the grid stretches, a
425
+ container of definite height - and never goes below 400 px, which is also
426
+ its height in a frame without one. A different floor goes through
427
+ `style`'s `minHeight` (ADR-0050). The width is the host's.
428
+ @default fills the frame, at least 400 px */
453
429
  height?: number;
454
430
  /** Height of one lane in pixels at the default font size of 16 px; the
455
431
  schedule multiplies it by the root font size over 16 px when that ratio
@@ -545,15 +521,90 @@ export declare interface ScheduleProps {
545
521
  the minute, an instant fixes it there.
546
522
  @default false */
547
523
  now?: boolean | number;
548
- /** Goes to the root element. */
549
- className?: string;
550
- /** Goes to the root element. */
551
- style?: CSSProperties;
524
+ /** The plan is on its way, as the chart's `loading` says (ADR-0042). A plan
525
+ already drawn stays: it dims after a moment and takes no pointer - no new
526
+ drag, no tooltip, no intent by key - until the answer is in; a drag
527
+ begun before finishes and reports. The keys still walk it. With no lanes,
528
+ placeholder lines stand in the lane column. The plot is `aria-busy`
529
+ meanwhile.
530
+ @default false */
531
+ loading?: boolean;
552
532
  /** `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and
553
533
  be drawn. */
554
534
  children?: ReactNode;
555
535
  }
556
536
 
537
+ /** What `useSchedule` hands back: the schedule and what is declared inside
538
+ it, its view and the setters that change it. */
539
+ export declare interface ScheduleParts {
540
+ /** The schedule. One per `useSchedule`: a second schedule is a second call. */
541
+ Schedule: (props: ScheduleProps) => ReactNode;
542
+ Lane: typeof Lane;
543
+ LaneGroup: typeof LaneGroup;
544
+ Subtasks: typeof Subtasks;
545
+ Dependencies: typeof Dependencies;
546
+ BlockedTimes: typeof BlockedTimes;
547
+ Milestones: typeof Milestones;
548
+ /** How the planner is looking at the plan: the span and the folded groups. */
549
+ view: ScheduleView;
550
+ /** Goes to a whole view; what it leaves out is shown whole again. Not
551
+ reported through `onViewChange`: two schedules kept in step by
552
+ `onViewChange: (v) => other.setView(v)` in both directions do not answer
553
+ each other. A view with the content already shown changes nothing. */
554
+ setView: (view: ScheduleView) => void;
555
+ /** Puts a span of two wall-clock instants in view; `null` shows the
556
+ subtasks' extent. */
557
+ setDomain: (span: readonly [number, number] | null) => void;
558
+ /** Folds or unfolds one **Lane group**. */
559
+ toggleGroup: (id: string) => void;
560
+ /** The time and the lane at a client point, or null outside the plot - and
561
+ null while no schedule is mounted. */
562
+ positionAt: (clientX: number, clientY: number) => {
563
+ time: number;
564
+ lane: string | null;
565
+ } | null;
566
+ /** The client point of a time - on the middle of a lane where one is named -
567
+ or null while the schedule is not on screen. */
568
+ clientPointOf: (time: number, lane?: string) => {
569
+ x: number;
570
+ y: number;
571
+ } | null;
572
+ /** The visible span, as two wall-clock instants. */
573
+ visibleDomain: () => readonly [number, number];
574
+ /** Scrolls the lanes until the lane's row is in view, and returns `true`; `false`
575
+ and nothing changed for an unknown lane, one inside a folded **Lane group**
576
+ (none is unfolded), or while no schedule is mounted. */
577
+ scrollToLane: (lane: string) => boolean;
578
+ /** Brings the subtask's lane and time into view, the span moving to it and keeping its
579
+ width as `setDomain` would, and leaves the focus where it is; `false` and nothing
580
+ changed in the cases of `scrollToLane`. */
581
+ scrollToSubtask: (id: string) => boolean;
582
+ /** Does what `scrollToSubtask` does, then makes the subtask the **Active subtask** and
583
+ moves the focus to the plot, where the live region reads it out as the arrow keys do;
584
+ `false` and nothing changed in the cases of `scrollToLane`. */
585
+ focusSubtask: (id: string) => boolean;
586
+ /** Folds every group. */
587
+ foldAll: () => void;
588
+ /** Unfolds every group. */
589
+ unfoldAll: () => void;
590
+ }
591
+
592
+ /** The props of `Schedule`: the attributes of a `<div>` and what the schedule
593
+ reads itself. `ref`, `className`, `style` and the rest reach the root; the
594
+ name (`aria-label`, `aria-labelledby`) reaches the figure root and the plot,
595
+ and a `aria-describedby` of yours is joined to the plot's summary. */
596
+ export declare type ScheduleProps = ScheduleOwnProps & ({
597
+ /** What the schedule shows, for a screen reader: "Plan of week 38". */
598
+ "aria-label": string;
599
+ /** @deprecated since 0.43 - use `aria-label`. */
600
+ ariaLabel?: string;
601
+ } | {
602
+ "aria-label"?: undefined;
603
+ /** What the schedule shows, for a screen reader.
604
+ @deprecated since 0.43 - use `aria-label`. */
605
+ ariaLabel: string;
606
+ });
607
+
557
608
  /** What a tooltip is about: the hovered subtask or dependency, with what the
558
609
  schedule knows about it. */
559
610
  export declare type ScheduleTooltipTarget = {
@@ -698,7 +749,8 @@ export declare interface Task {
698
749
  /** Declares a schedule: hands back `Schedule` and the parts declared inside it
699
750
  - `Lane`, `LaneGroup`, `Subtasks`, `Dependencies`, `BlockedTimes`, `Milestones` -, its
700
751
  `view` and the setters `setView`, `setDomain`, `toggleGroup`, `foldAll` and
701
- `unfoldAll`. A ref on `Schedule` still gives the `ScheduleHandle`. */
752
+ `unfoldAll`, `positionAt`, `clientPointOf` and `visibleDomain`, and `scrollToLane`, `scrollToSubtask` and
753
+ `focusSubtask`. */
702
754
  export declare function useSchedule(options?: ScheduleOptions): ScheduleParts;
703
755
 
704
756
  /** Every dependency whose successor is to be reached before the predecessor's
package/dist/schedule.css CHANGED
@@ -1 +1 @@
1
- @layer umriss.tokens,umriss.base,umriss.components;@layer umriss.base{._text_18806_22{font-family:var(--u-font-sans);font-size:var(--u-text-md);line-height:var(--u-leading-normal);color:var(--u-color-text);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}@media(pointer:fine){._dense_18806_38{--u-control-height-sm: var(--u-control-height-xs)}}._ink_18806_49{--u-color-text: var(--u-color-bg);--u-color-text-secondary: color-mix(in srgb, var(--u-color-bg) 75%, transparent);--u-color-text-muted: color-mix(in srgb, var(--u-color-bg) 60%, transparent)}._extent_18806_75{--_chars: 20;--_extra: 0;--_tracking: 0px;--_chrome: 0px;min-inline-size:0;max-inline-size:100%;contain:inline-size;contain-intrinsic-inline-size:calc((var(--_chars) + var(--_extra)) * (1ch + var(--_tracking)) + var(--_chrome))}._field_18806_90{caret-color:var(--u-color-accent)}._scroll_18806_96{scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--u-color-text) 25%,transparent) transparent}._scroll_18806_96::-webkit-scrollbar{width:10px;height:10px}._scroll_18806_96::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--u-color-text) 22%,transparent);border-radius:var(--u-radius-full);border:3px solid transparent;background-clip:content-box}._scroll_18806_96::-webkit-scrollbar-track{background:transparent}}@layer umriss.components{._ring_18806_125:focus-visible{outline:2px solid transparent;box-shadow:var(--u-focus-ring)}@media(pointer:coarse){._field_18806_90._field_18806_90,._fieldRoot_18806_145._fieldRoot_18806_145{font-size:16px}}._field_18806_90:-webkit-autofill,._field_18806_90:-webkit-autofill:hover,._field_18806_90:-webkit-autofill:focus{-webkit-box-shadow:inset 0 0 0 1000px var(--u-color-surface),0 0 0 1px var(--u-edge-color-strong);-webkit-text-fill-color:var(--u-color-text);caret-color:var(--u-color-accent)}}@layer umriss.components{._root_1g7hg_4,._root_1g7hg_4:before,._root_1g7hg_4:after{box-sizing:border-box}._corner_1g7hg_19,._corner_1g7hg_19:before,._corner_1g7hg_19:after{box-sizing:border-box}._dayBand_1g7hg_23,._dayBand_1g7hg_23:before,._dayBand_1g7hg_23:after{box-sizing:border-box}._tickBand_1g7hg_24,._tickBand_1g7hg_24:before,._tickBand_1g7hg_24:after{box-sizing:border-box}._day_1g7hg_23,._day_1g7hg_23:before,._day_1g7hg_23:after{box-sizing:border-box}._dayLabel_1g7hg_50,._dayLabel_1g7hg_50:before,._dayLabel_1g7hg_50:after{box-sizing:border-box}._tick_1g7hg_24,._tick_1g7hg_24:before,._tick_1g7hg_24:after{box-sizing:border-box}._tickLabel_1g7hg_71,._tickLabel_1g7hg_71:before,._tickLabel_1g7hg_71:after{box-sizing:border-box}._headers_1g7hg_79,._headers_1g7hg_79:before,._headers_1g7hg_79:after{box-sizing:border-box}._header_1g7hg_79,._header_1g7hg_79:before,._header_1g7hg_79:after{box-sizing:border-box}._headerLabel_1g7hg_97,._headerLabel_1g7hg_97:before,._headerLabel_1g7hg_97:after{box-sizing:border-box}._headerCount_1g7hg_133,._headerCount_1g7hg_133:before,._headerCount_1g7hg_133:after{box-sizing:border-box}._chevron_1g7hg_142,._chevron_1g7hg_142:before,._chevron_1g7hg_142:after{box-sizing:border-box}._plot_1g7hg_197,._plot_1g7hg_197:before,._plot_1g7hg_197:after{box-sizing:border-box}._focusRing_1g7hg_204,._focusRing_1g7hg_204:before,._focusRing_1g7hg_204:after{box-sizing:border-box}._layer_1g7hg_222,._layer_1g7hg_222:before,._layer_1g7hg_222:after{box-sizing:border-box}._grip_1g7hg_231,._grip_1g7hg_231:before,._grip_1g7hg_231:after{box-sizing:border-box}._ghostLabel_1g7hg_241,._ghostLabel_1g7hg_241:before,._ghostLabel_1g7hg_241:after{box-sizing:border-box}._finding_1g7hg_254,._finding_1g7hg_254:before,._finding_1g7hg_254:after{box-sizing:border-box}._refusal_1g7hg_262,._refusal_1g7hg_262:before,._refusal_1g7hg_262:after{box-sizing:border-box}._tooltip_1g7hg_266,._tooltip_1g7hg_266:before,._tooltip_1g7hg_266:after{box-sizing:border-box}._tooltipHead_1g7hg_285,._tooltipHead_1g7hg_285:before,._tooltipHead_1g7hg_285:after{box-sizing:border-box}._tooltipTimes_1g7hg_290,._tooltipTimes_1g7hg_290:before,._tooltipTimes_1g7hg_290:after{box-sizing:border-box}._now_1g7hg_299,._now_1g7hg_299:before,._now_1g7hg_299:after{box-sizing:border-box}._barLabel_1g7hg_313,._barLabel_1g7hg_313:before,._barLabel_1g7hg_313:after{box-sizing:border-box}._barLabelText_1g7hg_326,._barLabelText_1g7hg_326:before,._barLabelText_1g7hg_326:after{box-sizing:border-box}._root_1g7hg_4{display:grid;grid-template-rows:28px minmax(0,1fr) 28px;width:100%;font-size:var(--u-text-sm);background:var(--u-color-surface);outline:1px solid transparent;box-shadow:var(--u-edge);border-radius:var(--u-radius-md);corner-shape:squircle;overflow:hidden;font-variant-numeric:tabular-nums;user-select:none}._corner_1g7hg_19{background:var(--u-color-surface)}._dayBand_1g7hg_23,._tickBand_1g7hg_24{position:relative;overflow:hidden;color:var(--u-color-text-muted);font-size:var(--u-text-xs)}._dayBand_1g7hg_23{border-bottom:1px solid var(--u-hairline-strong)}._tickBand_1g7hg_24{border-top:1px solid var(--u-hairline-strong)}._day_1g7hg_23{position:absolute;top:0;bottom:0;border-left:1px solid var(--u-hairline-strong);overflow:hidden}._dayLabel_1g7hg_50{position:absolute;z-index:1;left:var(--u-space-1);padding:0 var(--u-space-1);background:var(--u-color-surface);top:50%;transform:translateY(-50%);white-space:nowrap;color:var(--u-color-text);font-weight:var(--u-weight-medium)}._tick_1g7hg_24{position:absolute;top:0;bottom:0;width:1px;background:var(--u-hairline)}._tickLabel_1g7hg_71{position:absolute;top:50%;left:0;transform:translate(-50%,-50%);white-space:nowrap}._headers_1g7hg_79{position:relative;overflow:hidden;border-right:1px solid var(--u-hairline-strong)}._header_1g7hg_79{display:flex;align-items:center;gap:var(--u-space-2);padding-right:var(--u-space-3);border-bottom:1px solid var(--u-hairline);overflow:hidden;white-space:nowrap}._headerLabel_1g7hg_97{min-width:0;overflow:hidden;text-overflow:ellipsis}._header_1g7hg_79[data-row=lane],._header_1g7hg_79[data-row=miniature]{container:lane-header / size}@container lane-header (height >= 2.5rem){._headerLabel_1g7hg_97:not(:has(*)){display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;white-space:normal;text-wrap:balance}}._header_1g7hg_79[data-row=groupHead],._header_1g7hg_79[data-row=miniature]{font-weight:var(--u-weight-medium)}._headerCount_1g7hg_133{flex:none;color:var(--u-color-text-muted);font-size:var(--u-text-xs);font-variant-numeric:tabular-nums}._chevron_1g7hg_142{flex:none;display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;border-radius:var(--u-radius-xs);corner-shape:squircle;background:transparent;color:var(--u-color-text-secondary);cursor:pointer;transition:background-color var(--u-transition),color var(--u-transition)}._chevron_1g7hg_142:hover{background:var(--u-color-surface-sunken);color:var(--u-color-text)}._chevron_1g7hg_142:active{background:var(--u-color-surface-pressed)}._chevron_1g7hg_142:focus-visible{outline:2px solid transparent;box-shadow:var(--u-focus-ring)}._chevron_1g7hg_142 svg{box-sizing:border-box}._chevron_1g7hg_142 svg{transition:transform var(--u-transition-path)}._chevron_1g7hg_142 svg[data-open]{box-sizing:border-box}._chevron_1g7hg_142 svg[data-open]{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){._chevron_1g7hg_142 svg{transition:none}}._header_1g7hg_79[data-refused]{color:var(--u-color-text-muted)}._plot_1g7hg_197{position:relative;overflow:hidden;touch-action:none}._plot_1g7hg_197:focus{outline:none}._focusRing_1g7hg_204{position:absolute;inset:2px;border-radius:var(--u-radius-md);corner-shape:squircle;pointer-events:none}._plot_1g7hg_197:focus-visible>._focusRing_1g7hg_204{outline:2px solid transparent;box-shadow:var(--u-focus-ring)}._layer_1g7hg_222{position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none}._grip_1g7hg_231{position:absolute;width:9px;margin-left:-4px;border-radius:var(--u-radius-xs);corner-shape:squircle;background:var(--u-color-surface);box-shadow:inset 0 0 0 1.5px var(--u-color-text);cursor:ew-resize}._ghostLabel_1g7hg_241{position:absolute;display:inline-flex;gap:var(--u-space-2);padding:1px var(--u-space-2);border-radius:var(--u-radius-sm);corner-shape:squircle;background:var(--u-color-text);color:var(--u-color-surface);font-size:var(--u-text-xs);white-space:nowrap;pointer-events:none}._finding_1g7hg_254{font-weight:var(--u-weight-semibold);color:var(--u-color-danger-subtle)}._refusal_1g7hg_262{font-weight:var(--u-weight-semibold)}._tooltip_1g7hg_266{position:absolute;z-index:1;display:flex;flex-direction:column;gap:1px;max-width:260px;padding:var(--u-space-2) var(--u-space-3);border-radius:var(--u-radius-sm);corner-shape:squircle;background:var(--u-color-surface);outline:1px solid transparent;box-shadow:var(--u-shadow-overlay);color:var(--u-color-text-secondary);font-size:var(--u-text-xs);line-height:var(--u-leading-tight);pointer-events:none;white-space:nowrap}._tooltipHead_1g7hg_285{color:var(--u-color-text);font-weight:var(--u-weight-semibold)}._tooltipTimes_1g7hg_290{color:var(--u-color-text)}._tooltip_1g7hg_266 ._finding_1g7hg_254{color:var(--u-color-danger-text)}._now_1g7hg_299{position:absolute;top:0;width:0;height:0;margin-left:-4px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:6px solid var(--u-color-accent)}._barLabel_1g7hg_313{position:absolute;display:flex;align-items:center;padding:0 var(--u-space-1);overflow:hidden;font-size:var(--u-text-xs);line-height:var(--u-leading-tight);pointer-events:none}._barLabelText_1g7hg_326{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}._barLabel_1g7hg_313[data-on=dark]{color:var(--u-color-on-accent)}._barLabel_1g7hg_313[data-on=light]{color:var(--u-color-text)}@media(forced-colors:active){._grip_1g7hg_231{outline:2px solid CanvasText;outline-offset:-2px}._ghostLabel_1g7hg_241{outline:1px solid CanvasText}}}
1
+ @layer umriss.tokens,umriss.base,umriss.components;@layer umriss.base{._text_18806_22{font-family:var(--u-font-sans);font-size:var(--u-text-md);line-height:var(--u-leading-normal);color:var(--u-color-text);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}@media(pointer:fine){._dense_18806_38{--u-control-height-sm: var(--u-control-height-xs)}}._ink_18806_49{--u-color-text: var(--u-color-bg);--u-color-text-secondary: color-mix(in srgb, var(--u-color-bg) 75%, transparent);--u-color-text-muted: color-mix(in srgb, var(--u-color-bg) 60%, transparent)}._extent_18806_75{--_chars: 20;--_extra: 0;--_tracking: 0px;--_chrome: 0px;min-inline-size:0;max-inline-size:100%;contain:inline-size;contain-intrinsic-inline-size:calc((var(--_chars) + var(--_extra)) * (1ch + var(--_tracking)) + var(--_chrome))}._field_18806_90{caret-color:var(--u-color-accent)}._scroll_18806_96{scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--u-color-text) 25%,transparent) transparent}._scroll_18806_96::-webkit-scrollbar{width:10px;height:10px}._scroll_18806_96::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--u-color-text) 22%,transparent);border-radius:var(--u-radius-full);border:3px solid transparent;background-clip:content-box}._scroll_18806_96::-webkit-scrollbar-track{background:transparent}}@layer umriss.components{._ring_18806_125:focus-visible{outline:2px solid transparent;box-shadow:var(--u-focus-ring)}@media(pointer:coarse){._field_18806_90._field_18806_90,._fieldRoot_18806_145._fieldRoot_18806_145{font-size:16px}}._field_18806_90:-webkit-autofill,._field_18806_90:-webkit-autofill:hover,._field_18806_90:-webkit-autofill:focus{-webkit-box-shadow:inset 0 0 0 1000px var(--u-color-surface),0 0 0 1px var(--u-edge-color-strong);-webkit-text-fill-color:var(--u-color-text);caret-color:var(--u-color-accent)}}@layer umriss.components{._root_mm9nj_4,._root_mm9nj_4:before,._root_mm9nj_4:after{box-sizing:border-box}._corner_mm9nj_19,._corner_mm9nj_19:before,._corner_mm9nj_19:after{box-sizing:border-box}._dayBand_mm9nj_23,._dayBand_mm9nj_23:before,._dayBand_mm9nj_23:after{box-sizing:border-box}._tickBand_mm9nj_24,._tickBand_mm9nj_24:before,._tickBand_mm9nj_24:after{box-sizing:border-box}._day_mm9nj_23,._day_mm9nj_23:before,._day_mm9nj_23:after{box-sizing:border-box}._dayLabel_mm9nj_50,._dayLabel_mm9nj_50:before,._dayLabel_mm9nj_50:after{box-sizing:border-box}._tick_mm9nj_24,._tick_mm9nj_24:before,._tick_mm9nj_24:after{box-sizing:border-box}._tickLabel_mm9nj_71,._tickLabel_mm9nj_71:before,._tickLabel_mm9nj_71:after{box-sizing:border-box}._headers_mm9nj_81,._headers_mm9nj_81:before,._headers_mm9nj_81:after{box-sizing:border-box}._header_mm9nj_81,._header_mm9nj_81:before,._header_mm9nj_81:after{box-sizing:border-box}._headerLabel_mm9nj_100,._headerLabel_mm9nj_100:before,._headerLabel_mm9nj_100:after{box-sizing:border-box}._headerCount_mm9nj_136,._headerCount_mm9nj_136:before,._headerCount_mm9nj_136:after{box-sizing:border-box}._chevron_mm9nj_145,._chevron_mm9nj_145:before,._chevron_mm9nj_145:after{box-sizing:border-box}._plot_mm9nj_223,._plot_mm9nj_223:before,._plot_mm9nj_223:after{box-sizing:border-box}._focusRing_mm9nj_237,._focusRing_mm9nj_237:before,._focusRing_mm9nj_237:after{box-sizing:border-box}._layer_mm9nj_255,._layer_mm9nj_255:before,._layer_mm9nj_255:after{box-sizing:border-box}._grip_mm9nj_282,._grip_mm9nj_282:before,._grip_mm9nj_282:after{box-sizing:border-box}._ghostLabel_mm9nj_292,._ghostLabel_mm9nj_292:before,._ghostLabel_mm9nj_292:after{box-sizing:border-box}._finding_mm9nj_305,._finding_mm9nj_305:before,._finding_mm9nj_305:after{box-sizing:border-box}._refusal_mm9nj_313,._refusal_mm9nj_313:before,._refusal_mm9nj_313:after{box-sizing:border-box}._tooltip_mm9nj_317,._tooltip_mm9nj_317:before,._tooltip_mm9nj_317:after{box-sizing:border-box}._tooltipHead_mm9nj_336,._tooltipHead_mm9nj_336:before,._tooltipHead_mm9nj_336:after{box-sizing:border-box}._tooltipTimes_mm9nj_341,._tooltipTimes_mm9nj_341:before,._tooltipTimes_mm9nj_341:after{box-sizing:border-box}._now_mm9nj_350,._now_mm9nj_350:before,._now_mm9nj_350:after{box-sizing:border-box}._barLabel_mm9nj_364,._barLabel_mm9nj_364:before,._barLabel_mm9nj_364:after{box-sizing:border-box}._barLabelText_mm9nj_377,._barLabelText_mm9nj_377:before,._barLabelText_mm9nj_377:after{box-sizing:border-box}._root_mm9nj_4{display:grid;grid-template-rows:28px minmax(0,1fr) 28px;width:100%;font-size:var(--u-text-sm);background:var(--u-color-surface);outline:1px solid transparent;box-shadow:var(--u-edge);border-radius:var(--u-radius-md);corner-shape:squircle;overflow:hidden;font-variant-numeric:tabular-nums;user-select:none}._corner_mm9nj_19{background:var(--u-color-surface)}._dayBand_mm9nj_23,._tickBand_mm9nj_24{position:relative;overflow:hidden;color:var(--u-color-text-muted);font-size:var(--u-text-xs)}._dayBand_mm9nj_23{border-bottom:1px solid var(--u-hairline-strong)}._tickBand_mm9nj_24{border-top:1px solid var(--u-hairline-strong)}._day_mm9nj_23{position:absolute;top:0;bottom:0;border-left:1px solid var(--u-hairline-strong);overflow:hidden}._dayLabel_mm9nj_50{position:absolute;z-index:1;left:var(--u-space-1);padding:0 var(--u-space-1);background:var(--u-color-surface);top:50%;transform:translateY(-50%);white-space:nowrap;color:var(--u-color-text);font-weight:var(--u-weight-medium)}._tick_mm9nj_24{position:absolute;top:0;bottom:0;width:1px;background:var(--u-hairline)}._tickLabel_mm9nj_71{position:absolute;top:50%;left:0;transform:translate(-50%,-50%);white-space:nowrap}._headers_mm9nj_81{contain:size;position:relative;overflow:hidden;border-right:1px solid var(--u-hairline-strong)}._header_mm9nj_81{display:flex;align-items:center;gap:var(--u-space-2);padding-right:var(--u-space-3);border-bottom:1px solid var(--u-hairline);overflow:hidden;white-space:nowrap}._headerLabel_mm9nj_100{min-width:0;overflow:hidden;text-overflow:ellipsis}._header_mm9nj_81[data-row=lane],._header_mm9nj_81[data-row=miniature]{container:lane-header / size}@container lane-header (height >= 2.5rem){._headerLabel_mm9nj_100:not(:has(*)){display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;white-space:normal;text-wrap:balance}}._header_mm9nj_81[data-row=groupHead],._header_mm9nj_81[data-row=miniature]{font-weight:var(--u-weight-medium)}._headerCount_mm9nj_136{flex:none;color:var(--u-color-text-muted);font-size:var(--u-text-xs);font-variant-numeric:tabular-nums}._chevron_mm9nj_145{flex:none;display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;border-radius:var(--u-radius-xs);corner-shape:squircle;background:transparent;color:var(--u-color-text-secondary);cursor:pointer;transition:background-color var(--u-transition),color var(--u-transition)}._chevron_mm9nj_145:hover{background:var(--u-color-surface-sunken);color:var(--u-color-text)}._chevron_mm9nj_145:active{background:var(--u-color-surface-pressed)}._chevron_mm9nj_145:focus-visible{outline:2px solid transparent;box-shadow:var(--u-focus-ring)}._chevron_mm9nj_145 svg{box-sizing:border-box}._chevron_mm9nj_145 svg{transition:transform var(--u-transition-path)}._chevron_mm9nj_145 svg[data-open]{box-sizing:border-box}._chevron_mm9nj_145 svg[data-open]{transform:rotate(90deg)}@media(pointer:coarse){._chevron_mm9nj_145{position:relative}._chevron_mm9nj_145:after{content:"";position:absolute;inset:-4px}._header_mm9nj_81[data-row=groupHead]{overflow:clip;overflow-clip-margin:2px}}@media(prefers-reduced-motion:reduce){._chevron_mm9nj_145 svg{transition:none}}._header_mm9nj_81[data-refused]{color:var(--u-color-text-muted)}._plot_mm9nj_223{contain:size;position:relative;overflow:hidden;touch-action:none;-webkit-touch-callout:none;user-select:none}._plot_mm9nj_223:focus{outline:none}._focusRing_mm9nj_237{position:absolute;inset:2px;border-radius:var(--u-radius-md);corner-shape:squircle;pointer-events:none}._plot_mm9nj_223:focus-visible>._focusRing_mm9nj_237{outline:2px solid transparent;box-shadow:var(--u-focus-ring)}._layer_mm9nj_255{position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none}._plot_mm9nj_223[data-stale]{pointer-events:none}._plot_mm9nj_223[data-stale]>:not(._focusRing_mm9nj_237){opacity:.5;transition:opacity var(--u-transition, .12s cubic-bezier(.22, 1, .36, 1)) var(--u-delay-stale, .2s)}@media(prefers-reduced-motion:reduce){._plot_mm9nj_223[data-stale]>:not(._focusRing_mm9nj_237){transition-duration:0s}}._grip_mm9nj_282{position:absolute;width:9px;margin-left:-4px;border-radius:var(--u-radius-xs);corner-shape:squircle;background:var(--u-color-surface);box-shadow:inset 0 0 0 1.5px var(--u-color-text);cursor:ew-resize}._ghostLabel_mm9nj_292{position:absolute;display:inline-flex;gap:var(--u-space-2);padding:1px var(--u-space-2);border-radius:var(--u-radius-sm);corner-shape:squircle;background:var(--u-color-text);color:var(--u-color-surface);font-size:var(--u-text-xs);white-space:nowrap;pointer-events:none}._finding_mm9nj_305{font-weight:var(--u-weight-semibold);color:var(--u-color-danger-subtle)}._refusal_mm9nj_313{font-weight:var(--u-weight-semibold)}._tooltip_mm9nj_317{position:absolute;z-index:1;display:flex;flex-direction:column;gap:1px;max-width:260px;padding:var(--u-space-2) var(--u-space-3);border-radius:var(--u-radius-sm);corner-shape:squircle;background:var(--u-color-surface);outline:1px solid transparent;box-shadow:var(--u-shadow-overlay);color:var(--u-color-text-secondary);font-size:var(--u-text-xs);line-height:var(--u-leading-tight);pointer-events:none;white-space:nowrap}._tooltipHead_mm9nj_336{color:var(--u-color-text);font-weight:var(--u-weight-semibold)}._tooltipTimes_mm9nj_341{color:var(--u-color-text)}._tooltip_mm9nj_317 ._finding_mm9nj_305{color:var(--u-color-danger-text)}._now_mm9nj_350{position:absolute;top:0;width:0;height:0;margin-left:-4px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:6px solid var(--u-color-accent)}._barLabel_mm9nj_364{position:absolute;display:flex;align-items:center;padding:0 var(--u-space-1);overflow:hidden;font-size:var(--u-text-xs);line-height:var(--u-leading-tight);pointer-events:none}._barLabelText_mm9nj_377{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}._barLabel_mm9nj_364[data-on=dark]{color:var(--u-color-on-accent)}._barLabel_mm9nj_364[data-on=light]{color:var(--u-color-text)}@media(forced-colors:active){._grip_mm9nj_282{outline:2px solid CanvasText;outline-offset:-2px}._ghostLabel_mm9nj_292{outline:1px solid CanvasText}}}