@kaptures/cli 0.0.4 → 0.0.5

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/README.md CHANGED
@@ -5,25 +5,27 @@ one explicit browser environment. It produces a self-contained visual report
5
5
  and can publish a SHA-bound review status to GitHub.
6
6
 
7
7
  Node.js 24 or later is required. Both Storybook builds must register the
8
- matching `@kaptures/storybook@0.0.4` preview adapter. Kapture does not fall back
8
+ matching `@kaptures/storybook@0.0.5` preview adapter. Kapture does not fall back
9
9
  to Storybook private globals, legacy decorators, or Chromatic parameters.
10
10
 
11
11
  ```bash
12
- npx -y @kaptures/cli@0.0.4 --help
13
- npx -y @kaptures/cli@0.0.4 browser install
12
+ npx -y @kaptures/cli@0.0.5 --help
13
+ npx -y @kaptures/cli@0.0.5 browser install
14
14
  ```
15
15
 
16
16
  ## Compare Storybooks
17
17
 
18
18
  ```bash
19
- npx -y @kaptures/cli@0.0.4 test \
19
+ npx -y @kaptures/cli@0.0.5 test \
20
20
  --base-dir .kapture/storybook/base \
21
21
  --head-dir .kapture/storybook/head \
22
22
  --base-revision "$BASE_SHA" \
23
23
  --head-revision "$HEAD_SHA" \
24
+ --changed-files .kapture/changed-files.json \
25
+ --install-browser \
24
26
  --output .kapture
25
27
 
26
- npx -y @kaptures/cli@0.0.4 validate \
28
+ npx -y @kaptures/cli@0.0.5 validate \
27
29
  --report .kapture/report/report.json
28
30
  ```
29
31
 
@@ -34,6 +36,27 @@ The default browser locale and time zone are `en-US` and `UTC`. Override them
34
36
  explicitly with `--locale <bcp47>` and `--timezone <iana-zone>` when the
35
37
  consumer Storybook requires another environment.
36
38
 
39
+ ## Plan affected stories
40
+
41
+ When both Storybook builds register `@kaptures/storybook/preset`, their static
42
+ directories contain a versioned `kapture-dependencies.json`. Pass a JSON array
43
+ of project-relative Git diff paths to select only stories whose base or head
44
+ dependency graph is affected:
45
+
46
+ ```bash
47
+ npx -y @kaptures/cli@0.0.5 plan \
48
+ --base-dir .kapture/storybook/base \
49
+ --head-dir .kapture/storybook/head \
50
+ --changed-files .kapture/changed-files.json \
51
+ --output .kapture/plan.json
52
+ ```
53
+
54
+ The plan always includes added and removed stories. A missing, invalid, or
55
+ incomplete manifest, a configured global input, an unknown changed file, or an
56
+ unmappable Storybook import produces an explicit `full-fallback` plan instead
57
+ of risking a false negative. Files are ignored only when both builds explicitly
58
+ declare the same matching `ignoredInputs` policy.
59
+
37
60
  ## Optional hosted report
38
61
 
39
62
  Kapture does not require a report deployment. The generated `index.html`
@@ -42,7 +65,7 @@ artifact is downloaded. To publish a browser URL from a privileged workflow,
42
65
  rebuild the untrusted artifact with the dashboard embedded in the pinned CLI:
43
66
 
44
67
  ```bash
45
- npx -y @kaptures/cli@0.0.4 report build \
68
+ npx -y @kaptures/cli@0.0.5 report build \
46
69
  --input downloaded-kapture-report \
47
70
  --output trusted-kapture-report
48
71
  ```
@@ -54,62 +77,112 @@ or unreferenced files.
54
77
 
55
78
  ## GitHub
56
79
 
57
- Run every checkout, repository script, Storybook build, and browser capture in
58
- the read-only `pull_request` workflow without secrets. Pass only an immutable
59
- context artifact plus `report.json` and its referenced PNGs to the default
60
- branch's `workflow_run`; intermediate Storybook artifacts stay inside the
61
- read-only run.
62
-
63
- The `workflow_run` resolves exact artifact IDs from the triggering run and
64
- cross-checks their provenance, bounded archive size, full base/head SHAs, and
65
- current open pull request. The actual PR head SHA comes from the immutable
66
- context and live pull request; `workflow_run.head_sha` may be a synthetic merge
67
- commit and is not treated as the PR head. SHA-pinned `download-artifact@v8`
68
- fails closed on an archive digest mismatch, then validates entry paths and
69
- uncompressed limits before extraction. A job without write permission runs
70
- `github verify` and rebuilds the report from strict JSON and validated PNGs
71
- with the pinned CLI. A separate write job publishes only that trusted output.
72
- Neither job checks out PR code or executes artifact code. The `issue_comment`
73
- workflow similarly handles
74
- `/kapture approve <full-head-sha> <report-digest>` without checking out PR
75
- code.
80
+ Use the public Action templates in
81
+ [`examples/github-workflow`](../../examples/github-workflow). Replace every
82
+ `karrot-emu/kapture-action@<FULL_COMMIT_SHA>` with the same 40-character Action
83
+ release commit before enabling them. The Action pins one exact CLI version;
84
+ consumers own only their base/head Storybook build commands and static hosting
85
+ integration.
86
+
87
+ The templates split trust into three workflows:
88
+
89
+ 1. A secret-free, read-only `pull_request` workflow runs `context`, builds the
90
+ exact base and head revisions on separate runners, and captures on a third.
91
+ Context, base/head Storybook, and `report.json`/referenced PNGs cross only
92
+ those runner boundaries as four one-day artifacts. Capture downloads the
93
+ first three by producer-returned artifact ID and records those exact IDs and
94
+ SHA-256 digests in `capture-boundary.json`.
95
+ 2. The default branch's checkout-free `workflow_run` runs `reconcile-run` for
96
+ both `in_progress` and `completed`. On a successful completed capture,
97
+ `prepare-run` resolves the four exact source artifact IDs, verifies the
98
+ Storybook metadata binding, downloads only context/report, validates their
99
+ GitHub SHA-256 digests and bounded ZIP entries, cross-checks the live pull
100
+ request, and rebuilds the dashboard from strict JSON and PNGs using the
101
+ pinned CLI. The same trusted job deploys only that rebuilt directory, passes
102
+ one provider-validated immutable HTTPS deployment URL to `publish-run`, and
103
+ then uses `cleanup` to delete the four exact source artifacts. A separate
104
+ `needs: publish` job runs `finalize-run` under `if: always()` so a failed or
105
+ timed-out publish cannot leave the current revision pending.
106
+ 3. A checkout-free `issue_comment` job runs `approve` for
107
+ `/kapture approve <full-head-sha> <report-digest>` after the workflow and CLI
108
+ verify the reviewer and current report.
109
+
110
+ No trusted job checks out pull request code or executes artifact HTML,
111
+ JavaScript, CSS, fonts, or repository scripts. `workflow_run.head_sha` may be a
112
+ synthetic merge commit, so the CLI derives the real status target from the
113
+ immutable context and live pull request. When GitHub omits fork PR metadata,
114
+ the trusted status path requires one unique live repository/branch match.
115
+ The raw branch ref remains report metadata; a separate collision-resistant
116
+ `preview-alias` is used only where a DNS-safe hosting branch is required.
76
117
 
77
118
  ```bash
78
- npx -y @kaptures/cli@0.0.4 github verify \
119
+ npx -y @kaptures/cli@0.0.5 github reconcile-run \
120
+ --capture-workflow-path .github/workflows/visual-capture.yml \
121
+ --base-branch main \
122
+ --status-context "Kapture Visual Review"
123
+
124
+ npx -y @kaptures/cli@0.0.5 github prepare-run \
125
+ --capture-workflow-path .github/workflows/visual-capture.yml \
126
+ --base-branch main \
127
+ --output "$RUNNER_TEMP/kapture-trusted/report" \
128
+ --receipt "$RUNNER_TEMP/kapture-trusted/receipt.json"
129
+
130
+ npx -y @kaptures/cli@0.0.5 github publish-run \
131
+ --receipt "$RUNNER_TEMP/kapture-trusted/receipt.json" \
132
+ --report "$RUNNER_TEMP/kapture-trusted/report/report.json" \
133
+ --report-url "https://1a2b3c4d.example-kapture.pages.dev/" \
134
+ --status-context "Kapture Visual Review"
135
+
136
+ npx -y @kaptures/cli@0.0.5 github cleanup \
137
+ --receipt "$RUNNER_TEMP/kapture-trusted/receipt.json"
138
+
139
+ npx -y @kaptures/cli@0.0.5 github finalize-run \
140
+ --capture-workflow-path .github/workflows/visual-capture.yml \
141
+ --base-branch main \
142
+ --status-context "Kapture Visual Review"
143
+
144
+ npx -y @kaptures/cli@0.0.5 github verify \
79
145
  --report .kapture/report/report.json
80
146
 
81
- npx -y @kaptures/cli@0.0.4 github report \
147
+ npx -y @kaptures/cli@0.0.5 github report \
82
148
  --report trusted-kapture-report/report.json \
83
- --report-url "https://github.com/OWNER/REPO/actions/runs/RUN_ID/artifacts/ARTIFACT_ID"
149
+ --report-url "https://1a2b3c4d.example-kapture.pages.dev/"
84
150
 
85
- npx -y @kaptures/cli@0.0.4 github approve
151
+ npx -y @kaptures/cli@0.0.5 github approve
86
152
  ```
87
153
 
88
154
  GitHub commands read authentication and event data only from `GITHUB_TOKEN`
89
155
  and `GITHUB_EVENT_PATH`. Do not pass tokens as command-line arguments.
90
- `github verify` and `github report` require the normalized
91
- `kapture.schemaVersion: 1` event created by the trusted example workflow; do
92
- not pass GitHub's raw `workflow_run` payload because its `head_sha` may be a
93
- synthetic merge commit. `github approve` consumes the raw `issue_comment`
94
- event.
95
- `github verify` validates the strict report and its full base/head SHAs against
96
- the current pull request without writing a status or comment. Run it before
97
- deployment. A privileged report job must pass the output of `report build`;
98
- `github report` requires its image-bound `report.json` before writing. Version
99
- 3 approval markers bind the base SHA, head SHA, full report structure, actual
100
- bytes of every referenced PNG, capture run ID and attempt, workflow ID, head
101
- repository ID, head branch, and report URL. Approval rechecks that marker's run
102
- is the latest successful capture run for the same PR head repository and branch.
103
- The current status for the PR head must also be the final approval-ready
104
- `pending` in the selected context and target the same report URL. The transient
105
- publishing status is not approvable. Therefore, a base-branch update, new head
106
- commit, changed report image, or failed rerun at the same SHA prevents an old
107
- marker and digest from restoring success.
156
+ `github reconcile-run`, `github prepare-run`, `github publish-run`,
157
+ `github finalize-run`, and `github cleanup` consume the raw `workflow_run`
158
+ event. `github approve` consumes the raw `issue_comment` event. The lower-level
159
+ `github verify` and `github report` remain available for custom integrations,
160
+ but require a trusted normalized `kapture.schemaVersion: 1` event rather than
161
+ GitHub's raw `workflow_run` payload.
162
+
163
+ Version 3 approval markers bind the base SHA, head SHA, full report structure,
164
+ actual bytes of every referenced PNG, capture run ID and attempt, workflow ID,
165
+ head repository ID, raw head branch, and immutable report URL. Approval
166
+ rechecks that marker's run is the latest successful capture for the same pull
167
+ request head and that its status still targets the same URL. A base update, new
168
+ head commit, changed report image, failed rerun at the same SHA, or incomplete
169
+ publication prevents an old marker and digest from restoring success.
170
+
171
+ Call `github finalize-run` under `if: always()` after the completed trusted
172
+ publish path. It may be the final step of that job or, to survive a publish job
173
+ timeout, a separate `needs: publish` job. It does not read failed-step files.
174
+ Instead it proves the exact completed attempt is still the latest run for the
175
+ event's single current PR, then writes `error` whenever that run has no
176
+ published final marker. This also replaces a stale green status left by an
177
+ earlier run of the same SHA. A published clean or approval-ready marker is preserved, while
178
+ missing/multiple PR metadata, stale runs, and moved heads never cause a status
179
+ write. A non-successful capture is marked `error` after the same exact
180
+ current-head proof even when report preparation never began.
108
181
 
109
182
  The default status context is `Kapture Visual Review`, and report and approval
110
183
  comments default to English. Consumers can set `--status-context <name>` and
111
- `--comment-language en|ko` on both `github report` and `github approve` without
112
- changing the verification boundary.
184
+ `--comment-language en|ko` on publish and approval commands without changing
185
+ the verification boundary.
113
186
 
114
187
  ## License
115
188
 
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-content:""}}}@layer theme{:root,:host{--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-medium:500;--font-weight-semibold:600;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--default-font-family:"Geist Variable", sans-serif;--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:var(--canvas);color:var(--text-primary);font-family:Geist Variable,sans-serif}body{min-width:320px;margin:0}button,summary{-webkit-tap-highlight-color:transparent}button:not(:disabled),summary{cursor:pointer}button:focus-visible,a:focus-visible,summary:focus-visible,input:focus-visible{outline:2px solid var(--accent);outline-offset:2px}::selection{background:var(--accent-muted);color:var(--text-primary)}}@layer components;@layer utilities{.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing) * 0)}.inset-y-0{inset-block:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.top-3{top:calc(var(--spacing) * 3)}.left-3{left:calc(var(--spacing) * 3)}.z-50{z-index:50}.m-0{margin:calc(var(--spacing) * 0)}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-px{margin-top:1px}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.h-auto{height:auto}.h-full{height:100%}.max-h-\[40vh\]{max-height:40vh}.min-h-8{min-height:calc(var(--spacing) * 8)}.min-h-9{min-height:calc(var(--spacing) * 9)}.min-h-10{min-height:calc(var(--spacing) * 10)}.min-h-12{min-height:calc(var(--spacing) * 12)}.min-h-16{min-height:calc(var(--spacing) * 16)}.min-h-72{min-height:calc(var(--spacing) * 72)}.min-h-80{min-height:calc(var(--spacing) * 80)}.min-h-screen{min-height:100vh}.w-full{width:100%}.w-px{width:1px}.max-w-2xl{max-width:var(--container-2xl)}.max-w-\[1800px\]{max-width:1800px}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-y-20{--tw-translate-y:calc(var(--spacing) * -20);translate:var(--tw-translate-x) var(--tw-translate-y)}.rotate-180{rotate:180deg}.cursor-pointer{cursor:pointer}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-3\.5{gap:calc(var(--spacing) * 3.5)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-5{column-gap:calc(var(--spacing) * 5)}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-x-8{column-gap:calc(var(--spacing) * 8)}.gap-y-3{row-gap:calc(var(--spacing) * 3)}.gap-y-4{row-gap:calc(var(--spacing) * 4)}.gap-y-5{row-gap:calc(var(--spacing) * 5)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[var\(--border\)\]{border-color:var(--border)}.border-\[var\(--border-strong\)\]{border-color:var(--border-strong)}.border-\[var\(--status-error-border\)\]{border-color:var(--status-error-border)}.border-\[var\(--text-primary\)\]{border-color:var(--text-primary)}.border-transparent{border-color:#0000}.bg-\[var\(--canvas\)\]{background-color:var(--canvas)}.bg-\[var\(--status-added\)\]{background-color:var(--status-added)}.bg-\[var\(--status-added-muted\)\]{background-color:var(--status-added-muted)}.bg-\[var\(--status-changed\)\]{background-color:var(--status-changed)}.bg-\[var\(--status-changed-muted\)\]{background-color:var(--status-changed-muted)}.bg-\[var\(--status-error\)\]{background-color:var(--status-error)}.bg-\[var\(--status-error-muted\)\]{background-color:var(--status-error-muted)}.bg-\[var\(--status-removed\)\]{background-color:var(--status-removed)}.bg-\[var\(--status-removed-muted\)\]{background-color:var(--status-removed-muted)}.bg-\[var\(--surface\)\]{background-color:var(--surface)}.bg-\[var\(--surface-muted\)\]{background-color:var(--surface-muted)}.bg-\[var\(--surface-selected\)\]{background-color:var(--surface-selected)}.bg-\[var\(--text-primary\)\]{background-color:var(--text-primary)}.bg-\[var\(--text-tertiary\)\]{background-color:var(--text-tertiary)}.bg-transparent{background-color:#0000}.object-contain{object-fit:contain}.object-left-top{object-position:left top}.p-0{padding:calc(var(--spacing) * 0)}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-5{padding-block:calc(var(--spacing) * 5)}.pl-3\.5{padding-left:calc(var(--spacing) * 3.5)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[15px\]{font-size:15px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[-0\.02em\]{--tw-tracking:-.02em;letter-spacing:-.02em}.text-balance{text-wrap:balance}.text-pretty{text-wrap:pretty}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[rgb\(255_255_255\/72\%\)\]{color:#ffffffb8}.text-\[var\(--status-added\)\]{color:var(--status-added)}.text-\[var\(--status-changed\)\]{color:var(--status-changed)}.text-\[var\(--status-error\)\]{color:var(--status-error)}.text-\[var\(--status-removed\)\]{color:var(--status-removed)}.text-\[var\(--surface\)\]{color:var(--surface)}.text-\[var\(--text-primary\)\]{color:var(--text-primary)}.text-\[var\(--text-secondary\)\]{color:var(--text-secondary)}.text-\[var\(--text-tertiary\)\]{color:var(--text-tertiary)}.capitalize{text-transform:capitalize}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.accent-\[var\(--accent\)\]{accent-color:var(--accent)}.shadow-\[0_0_0_1px_rgb\(255_255_255\/70\%\)\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,#ffffffb3);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.group-open\:rotate-180:is(:where(.group):is([open],:popover-open,:open) *){rotate:180deg}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:inset-y-2:before{content:var(--tw-content);inset-block:calc(var(--spacing) * 2)}.before\:left-0:before{content:var(--tw-content);left:calc(var(--spacing) * 0)}.before\:w-0\.5:before{content:var(--tw-content);width:calc(var(--spacing) * .5)}.before\:rounded-full:before{content:var(--tw-content);border-radius:3.40282e38px}.before\:bg-\[var\(--text-primary\)\]:before{content:var(--tw-content);background-color:var(--text-primary)}@media (hover:hover){.hover\:border-\[var\(--border\)\]:hover{border-color:var(--border)}.hover\:bg-\[var\(--surface-hover\)\]:hover{background-color:var(--surface-hover)}.hover\:bg-\[var\(--surface-muted\)\]:hover{background-color:var(--surface-muted)}.hover\:bg-\[var\(--text-primary-hover\)\]:hover{background-color:var(--text-primary-hover)}.hover\:text-\[var\(--text-primary\)\]:hover{color:var(--text-primary)}}.focus\:translate-y-0:focus{--tw-translate-y:calc(var(--spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-35:disabled{opacity:.35}@media (width>=40rem){.sm\:flex{display:flex}.sm\:w-auto{width:auto}.sm\:max-w-\[32rem\]{max-width:32rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-wrap{flex-wrap:wrap}.sm\:items-end{align-items:flex-end}.sm\:gap-x-6{column-gap:calc(var(--spacing) * 6)}.sm\:p-5{padding:calc(var(--spacing) * 5)}.sm\:p-6{padding:calc(var(--spacing) * 6)}.sm\:px-5{padding-inline:calc(var(--spacing) * 5)}.sm\:text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.sm\:text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}}@media (width>=64rem){.lg\:sticky{position:sticky}.lg\:top-0{top:calc(var(--spacing) * 0)}.lg\:block{display:block}.lg\:hidden{display:none}.lg\:h-screen{height:100vh}.lg\:max-h-\[calc\(100vh-168px\)\]{max-height:calc(100vh - 168px)}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-\[288px_minmax\(0\,1fr\)\]{grid-template-columns:288px minmax(0,1fr)}.lg\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.lg\:border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.lg\:p-7{padding:calc(var(--spacing) * 7)}.lg\:px-7{padding-inline:calc(var(--spacing) * 7)}.lg\:py-6{padding-block:calc(var(--spacing) * 6)}}@media (width>=80rem){.xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:grid-cols-\[minmax\(0\,1fr\)_auto\]{grid-template-columns:minmax(0,1fr) auto}.xl\:items-center{align-items:center}.xl\:p-8{padding:calc(var(--spacing) * 8)}}}@font-face{font-family:Geist Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./geist-cyrillic-wght-normal-CHSlOQsW.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Geist Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./geist-latin-ext-wght-normal-DMtmJ5ZE.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Geist Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./geist-latin-wght-normal-Dm3htQBi.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--canvas:#f6f6f6;--surface:#fff;--surface-muted:#f2f2f2;--surface-hover:#eaeaea;--surface-selected:#ececec;--border:#1111111c;--border-strong:#11111138;--text-primary:#111;--text-primary-hover:#2a2a2a;--text-secondary:#5b5b5b;--text-tertiary:#6e6e6e;--accent:#111;--accent-muted:#e9e9e9;--status-changed:#9f3f00;--status-changed-muted:#fff1e7;--status-added:#17653c;--status-added-muted:#eaf6ee;--status-removed:#765000;--status-removed-muted:#fff5d8;--status-error:#a62a20;--status-error-muted:#fff0ee;--status-error-border:#e8b3ae}.checkerboard{background-color:#fff;background-image:linear-gradient(45deg,#ededed 25%,#0000 25%),linear-gradient(-45deg,#ededed 25%,#0000 25%),linear-gradient(45deg,#0000 75%,#ededed 75%),linear-gradient(-45deg,#0000 75%,#ededed 75%);background-position:0 0,0 8px,8px -8px,-8px 0;background-size:16px 16px}.report-image{outline-offset:-1px;outline:1px solid #0000001a}.overflow-wrap-anywhere{overflow-wrap:anywhere}.thin-scrollbar{scrollbar-color:#11111138 transparent;scrollbar-width:thin}@media (hover:hover) and (pointer:fine) and (prefers-reduced-motion:no-preference){.ui-press{transition-property:background-color,border-color,color,opacity,transform;transition-duration:.12s;transition-timing-function:cubic-bezier(.2,0,0,1)}.ui-press:active:not(:disabled){transform:scale(.985)}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}