@kaptures/cli 0.0.2 → 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
@@ -4,30 +4,59 @@ Kapture compares Storybook builds from an exact base commit and head commit in
4
4
  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
- Node.js 24 or later is required.
7
+ Node.js 24 or later is required. Both Storybook builds must register the
8
+ matching `@kaptures/storybook@0.0.5` preview adapter. Kapture does not fall back
9
+ to Storybook private globals, legacy decorators, or Chromatic parameters.
8
10
 
9
11
  ```bash
10
- npx -y @kaptures/cli@0.0.2 --help
11
- npx -y @kaptures/cli@0.0.2 browser install
12
+ npx -y @kaptures/cli@0.0.5 --help
13
+ npx -y @kaptures/cli@0.0.5 browser install
12
14
  ```
13
15
 
14
16
  ## Compare Storybooks
15
17
 
16
18
  ```bash
17
- npx -y @kaptures/cli@0.0.2 test \
19
+ npx -y @kaptures/cli@0.0.5 test \
18
20
  --base-dir .kapture/storybook/base \
19
21
  --head-dir .kapture/storybook/head \
20
22
  --base-revision "$BASE_SHA" \
21
23
  --head-revision "$HEAD_SHA" \
24
+ --changed-files .kapture/changed-files.json \
25
+ --install-browser \
22
26
  --output .kapture
23
27
 
24
- npx -y @kaptures/cli@0.0.2 validate \
28
+ npx -y @kaptures/cli@0.0.5 validate \
25
29
  --report .kapture/report/report.json
26
30
  ```
27
31
 
28
32
  Visual changes are a review result, not an execution failure. Capture and
29
33
  comparison errors exit with code 2.
30
34
 
35
+ The default browser locale and time zone are `en-US` and `UTC`. Override them
36
+ explicitly with `--locale <bcp47>` and `--timezone <iana-zone>` when the
37
+ consumer Storybook requires another environment.
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
+
31
60
  ## Optional hosted report
32
61
 
33
62
  Kapture does not require a report deployment. The generated `index.html`
@@ -36,7 +65,7 @@ artifact is downloaded. To publish a browser URL from a privileged workflow,
36
65
  rebuild the untrusted artifact with the dashboard embedded in the pinned CLI:
37
66
 
38
67
  ```bash
39
- npx -y @kaptures/cli@0.0.2 report build \
68
+ npx -y @kaptures/cli@0.0.5 report build \
40
69
  --input downloaded-kapture-report \
41
70
  --output trusted-kapture-report
42
71
  ```
@@ -48,41 +77,112 @@ or unreferenced files.
48
77
 
49
78
  ## GitHub
50
79
 
51
- Use isolated jobs in the default branch's `workflow_run`. The base and head
52
- jobs may run repository code, but must have no write permission or secrets.
53
- The capture job does not check out the PR or run repository scripts; it runs
54
- the pinned CLI against the two static Storybook builds without write
55
- permission or secrets. Storybook JavaScript is evaluated only inside that
56
- unprivileged browser boundary.
57
-
58
- Before using deployment credentials, the report job performs a read-only
59
- preflight. It must not check out PR code or execute artifact code. It rebuilds
60
- the hosted report from strict JSON and validated PNGs with the pinned CLI, then
61
- updates the PR. The `issue_comment` workflow similarly handles
62
- `/kapture approve <full-head-sha> <report-digest>` without checking out PR
63
- 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.
64
117
 
65
118
  ```bash
66
- npx -y @kaptures/cli@0.0.2 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 \
67
145
  --report .kapture/report/report.json
68
146
 
69
- npx -y @kaptures/cli@0.0.2 github report \
147
+ npx -y @kaptures/cli@0.0.5 github report \
70
148
  --report trusted-kapture-report/report.json \
71
- --report-url "https://github.com/OWNER/REPO/actions/runs/RUN_ID"
149
+ --report-url "https://1a2b3c4d.example-kapture.pages.dev/"
72
150
 
73
- npx -y @kaptures/cli@0.0.2 github approve
151
+ npx -y @kaptures/cli@0.0.5 github approve
74
152
  ```
75
153
 
76
154
  GitHub commands read authentication and event data only from `GITHUB_TOKEN`
77
155
  and `GITHUB_EVENT_PATH`. Do not pass tokens as command-line arguments.
78
- `github verify` validates the strict report and its full base/head SHAs against
79
- the current pull request without writing a status or comment. Run it before
80
- deployment. A privileged report job must pass the output of `report build`;
81
- `github report` requires its image-bound `report.json` before writing. Approval
82
- markers bind the base SHA, head SHA, full report
83
- structure, and the actual bytes of every referenced PNG. The approval command
84
- must contain that exact report digest, so a base-branch update, new head commit,
85
- or changed report image requires a new comparison.
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.
181
+
182
+ The default status context is `Kapture Visual Review`, and report and approval
183
+ comments default to English. Consumers can set `--status-context <name>` and
184
+ `--comment-language en|ko` on publish and approval commands without changing
185
+ the verification boundary.
86
186
 
87
187
  ## License
88
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:""}