@kaptures/cli 0.0.4 → 0.0.6

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,124 @@ 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. `prepare-storybook-run` then revalidates the completed run and
102
+ receipt before downloading the exact head Storybook by ID, digest, and size.
103
+ It rejects unsafe paths, symlinks, oversized entries, and excessive archive
104
+ expansion before extracting into the new `storybook/` directory. The same
105
+ trusted job deploys the combined dashboard and Storybook directory once,
106
+ passes one provider-validated immutable HTTPS deployment URL to
107
+ `publish-run`, and then uses `cleanup` to delete the four exact source
108
+ artifacts. A separate
109
+ `needs: publish` job runs `finalize-run` under `if: always()` so a failed or
110
+ timed-out publish cannot leave the current revision pending.
111
+ 3. A checkout-free `issue_comment` job runs `approve` for
112
+ `/kapture approve <full-head-sha> <report-digest>` after the workflow and CLI
113
+ verify the reviewer and current report.
114
+
115
+ No trusted job checks out pull request code or executes artifact HTML,
116
+ JavaScript, CSS, fonts, or repository scripts. `workflow_run.head_sha` may be a
117
+ synthetic merge commit, so the CLI derives the real status target from the
118
+ immutable context and live pull request. When GitHub omits fork PR metadata,
119
+ the trusted status path requires one unique live repository/branch match.
120
+ The raw branch ref remains report metadata; a separate collision-resistant
121
+ `preview-alias` is used only where a DNS-safe hosting branch is required.
76
122
 
77
123
  ```bash
78
- npx -y @kaptures/cli@0.0.4 github verify \
124
+ npx -y @kaptures/cli@0.0.5 github reconcile-run \
125
+ --capture-workflow-path .github/workflows/visual-capture.yml \
126
+ --base-branch main \
127
+ --status-context "Kapture Visual Review"
128
+
129
+ npx -y @kaptures/cli@0.0.5 github prepare-run \
130
+ --capture-workflow-path .github/workflows/visual-capture.yml \
131
+ --base-branch main \
132
+ --output "$RUNNER_TEMP/kapture-trusted/report" \
133
+ --receipt "$RUNNER_TEMP/kapture-trusted/receipt.json" \
134
+ --storybook-url ./storybook/
135
+
136
+ npx -y @kaptures/cli@0.0.5 github prepare-storybook-run \
137
+ --capture-workflow-path .github/workflows/visual-capture.yml \
138
+ --base-branch main \
139
+ --receipt "$RUNNER_TEMP/kapture-trusted/receipt.json" \
140
+ --output "$RUNNER_TEMP/kapture-trusted/report/storybook"
141
+
142
+ npx -y @kaptures/cli@0.0.5 github publish-run \
143
+ --receipt "$RUNNER_TEMP/kapture-trusted/receipt.json" \
144
+ --report "$RUNNER_TEMP/kapture-trusted/report/report.json" \
145
+ --report-url "https://1a2b3c4d.example-kapture.pages.dev/" \
146
+ --status-context "Kapture Visual Review"
147
+
148
+ npx -y @kaptures/cli@0.0.5 github cleanup \
149
+ --receipt "$RUNNER_TEMP/kapture-trusted/receipt.json"
150
+
151
+ npx -y @kaptures/cli@0.0.5 github finalize-run \
152
+ --capture-workflow-path .github/workflows/visual-capture.yml \
153
+ --base-branch main \
154
+ --status-context "Kapture Visual Review"
155
+
156
+ npx -y @kaptures/cli@0.0.5 github verify \
79
157
  --report .kapture/report/report.json
80
158
 
81
- npx -y @kaptures/cli@0.0.4 github report \
159
+ npx -y @kaptures/cli@0.0.5 github report \
82
160
  --report trusted-kapture-report/report.json \
83
- --report-url "https://github.com/OWNER/REPO/actions/runs/RUN_ID/artifacts/ARTIFACT_ID"
161
+ --report-url "https://1a2b3c4d.example-kapture.pages.dev/"
84
162
 
85
- npx -y @kaptures/cli@0.0.4 github approve
163
+ npx -y @kaptures/cli@0.0.5 github approve
86
164
  ```
87
165
 
88
166
  GitHub commands read authentication and event data only from `GITHUB_TOKEN`
89
167
  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.
168
+ `github reconcile-run`, `github prepare-run`, `github prepare-storybook-run`,
169
+ `github publish-run`, `github finalize-run`, and `github cleanup` consume the
170
+ raw `workflow_run` event. `github approve` consumes the raw `issue_comment` event. The lower-level
171
+ `github verify` and `github report` remain available for custom integrations,
172
+ but require a trusted normalized `kapture.schemaVersion: 1` event rather than
173
+ GitHub's raw `workflow_run` payload.
174
+
175
+ Version 3 approval markers bind the base SHA, head SHA, full report structure,
176
+ actual bytes of every referenced PNG, capture run ID and attempt, workflow ID,
177
+ head repository ID, raw head branch, and immutable report URL. Approval
178
+ rechecks that marker's run is the latest successful capture for the same pull
179
+ request head and that its status still targets the same URL. A base update, new
180
+ head commit, changed report image, failed rerun at the same SHA, or incomplete
181
+ publication prevents an old marker and digest from restoring success.
182
+
183
+ Call `github finalize-run` under `if: always()` after the completed trusted
184
+ publish path. It may be the final step of that job or, to survive a publish job
185
+ timeout, a separate `needs: publish` job. It does not read failed-step files.
186
+ Instead it proves the exact completed attempt is still the latest run for the
187
+ event's single current PR, then writes `error` whenever that run has no
188
+ published final marker. This also replaces a stale green status left by an
189
+ earlier run of the same SHA. A published clean or approval-ready marker is preserved, while
190
+ missing/multiple PR metadata, stale runs, and moved heads never cause a status
191
+ write. A non-successful capture is marked `error` after the same exact
192
+ current-head proof even when report preparation never began.
108
193
 
109
194
  The default status context is `Kapture Visual Review`, and report and approval
110
195
  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.
196
+ `--comment-language en|ko` on publish and approval commands without changing
197
+ the verification boundary.
113
198
 
114
199
  ## License
115
200
 
@@ -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:""}