@zebradil/docs-kit 0.0.0-stage → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 German Lashevich
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,137 @@
1
- # Temporary Holding Version
1
+ # docs-kit
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Shared kit for generating browsable documentation and a landing page for small OSS projects.
4
+
5
+ - One content contract (`docs/site.yaml` + Diátaxis page tree) across all projects.
6
+ - One layout, swappable designs (theme = CSS tokens).
7
+ - Reference pages generated from code (CLI `--help`, config schema), never handwritten.
8
+ - Reusable GitHub Actions workflow: generate, build, deploy to GitHub Pages.
9
+ - Agent skills (Claude Code plugin): [`docs-audit`](skills/docs-audit/SKILL.md), [`docs-bootstrap`](skills/docs-bootstrap/SKILL.md), [`docs-write`](skills/docs-write/SKILL.md).
10
+
11
+ ## Claude Code plugin
12
+
13
+ This repository is a Claude Code plugin marketplace with one plugin, `docs-kit`, holding the three skills. In a Claude Code session:
14
+
15
+ ```text
16
+ /plugin marketplace add Zebradil/docs-kit
17
+ /plugin install docs-kit@docs-kit
18
+ ```
19
+
20
+ The shell equivalents are `claude plugin marketplace add Zebradil/docs-kit` and `claude plugin install docs-kit@docs-kit`. The skills run as `/docs-kit:docs-audit` and so on, or when a request matches their description.
21
+
22
+ Recommended flow in a consuming project:
23
+
24
+ 1. `docs-audit` writes the gap report `docs/.audit.md`; it never edits docs.
25
+ 2. Review the report: reorder, drop, or fix gaps before any prose lands.
26
+ 3. `docs-bootstrap` sets up `docs/`, `site.yaml`, the workflow, and Renovate, then opens a PR.
27
+ 4. `docs-write` closes one gap per run with one PR. Repeat, re-auditing when the code moves.
28
+
29
+ The plugin carries no `version`, so its version is the commit it was installed from. Third-party marketplaces do not auto-update by default; pull the latest `main` with `claude plugin marketplace update docs-kit && claude plugin update docs-kit@docs-kit`.
30
+
31
+ ## Content contract
32
+
33
+ Every consuming project has a `docs/site.yaml` validated by [`schema/site.schema.json`](schema/site.schema.json); see [`examples/site.yaml`](examples/site.yaml). Validate one locally:
34
+
35
+ ```sh
36
+ npm ci
37
+ node schema/validate.mjs path/to/docs/site.yaml
38
+ ```
39
+
40
+ ## Using the kit
41
+
42
+ The repository root is the npm package [`@zebradil/docs-kit`](https://www.npmjs.com/package/@zebradil/docs-kit), published from each release tag ([ADR 0007](docs/adr/0007-publish-to-npm.md)). A consuming project's `docs/` needs three files besides `site.yaml` and its pages under `src/content/docs/`:
43
+
44
+ <!-- x-release-please-start-version -->
45
+ ```jsonc
46
+ // package.json
47
+ { "private": true, "type": "module", "dependencies": { "@zebradil/docs-kit": "0.10.0" } }
48
+ ```
49
+ <!-- x-release-please-end -->
50
+
51
+ ```js
52
+ // astro.config.mjs
53
+ import docsKit from '@zebradil/docs-kit';
54
+
55
+ export default docsKit({ site: 'site.yaml' });
56
+ ```
57
+
58
+ ```js
59
+ // src/content.config.mjs
60
+ export { collections } from '@zebradil/docs-kit/content';
61
+ ```
62
+
63
+ Build with `npm ci && npx astro build` from `docs/`. The site is served at `https://<owner>.github.io/<repo>/`, derived from `repo:` in `site.yaml`; with `domain:` set, it is served at `https://<domain>/`. [`packages/docs-kit/fixture/`](packages/docs-kit/fixture/) is a complete example.
64
+
65
+ To count visitors, set `analytics:` in `site.yaml`; the script is loaded on every page with the given `data-*` attributes:
66
+
67
+ ```yaml
68
+ analytics:
69
+ script: https://stats.example.dev/app.js
70
+ attributes:
71
+ data-website-id: 00000000-0000-0000-0000-000000000000
72
+ ```
73
+
74
+ For coding agents and LLMs, every site serves [`/llms.txt`](https://llmstxt.org), an index of all pages, and `/llms-full.txt`, all pages in one file. Each page's Markdown source is also served at its URL with `.md` appended (`/guides/configure/` → `/guides/configure.md`), with relative links made absolute. GitHub Pages cannot vary a response on the `Accept` header, so the `.md` URLs are the only Markdown route.
75
+
76
+ ### Publishing with GitHub Actions
77
+
78
+ [`.github/workflows/docs.yml`](.github/workflows/docs.yml) is a reusable workflow. A consuming project calls it from `.github/workflows/docs.yml`, pinned to the same tag as the kit in `docs/package.json`:
79
+
80
+ <!-- x-release-please-start-version -->
81
+ ```yaml
82
+ name: docs
83
+ on:
84
+ push: { branches: [main] }
85
+ pull_request:
86
+ permissions: { contents: read, pages: write, id-token: write }
87
+ jobs:
88
+ docs:
89
+ uses: Zebradil/docs-kit/.github/workflows/docs.yml@v0.10.0
90
+ ```
91
+ <!-- x-release-please-end -->
92
+
93
+ Keep `uses:` on its own indented line: Renovate's github-actions manager finds refs line by line and misses one inside a flow mapping.
94
+
95
+ The caller must grant `pages: write` and `id-token: write`: a called workflow can only narrow the caller's token permissions, never widen them, and the deploy job needs both.
96
+
97
+ On every run it installs `docs/` with `npm ci`, builds the CLI with `reference.cli.build` (run from the repository root) when set, regenerates the CLI reference with `help2md` into `docs/src/content/docs/reference/cli`, and builds the site with `npx astro build` (which validates `site.yaml`). On a pull request it fails if the regenerated reference differs from the committed one and prints the diff. On a push to the default branch it deploys `docs/dist` to GitHub Pages.
98
+
99
+ Inputs, all optional:
100
+
101
+ | Input | Default | Use |
102
+ |---|---|---|
103
+ | `directory` | `docs` | Docs directory, relative to the repository root. |
104
+ | `nix` | `false` | Install Nix first, for `build: nix build` and friends. |
105
+ | `deploy` | `true` | Deploy on pushes to the default branch. |
106
+
107
+ Runs on `ubuntu-latest`, which already has Rust (cargo, rustup) and Go (default version linked into `/usr/bin`; a newer `go` line in `go.mod` makes Go download that toolchain itself); see the [runner image tool list](https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md).
108
+
109
+ One manual step per repository, by its owner: enable Pages with GitHub Actions as the source, in Settings → Pages → Build and deployment → Source: GitHub Actions, or:
110
+
111
+ ```sh
112
+ gh api --method POST repos/<owner>/<repo>/pages -f build_type=workflow
113
+ ```
114
+
115
+ Until then the deploy job fails. This repository builds [the fixture](packages/docs-kit/fixture/) through the workflow ([`pages.yml`](.github/workflows/pages.yml)) and deploys it only when the repository variable `PAGES_ENABLED` is `true`; set it after enabling Pages (`gh variable set PAGES_ENABLED --body true`).
116
+
117
+ Terms used across the kit are defined in [`CONTEXT.md`](CONTEXT.md).
118
+
119
+ Status: pre-release. Kit, workflow and skills are in place; no `v*` tag yet, first pilot pending. See the design map issue (#1).
120
+
121
+ ## refgen/help2md
122
+
123
+ Generates CLI reference pages from `--help` output (clap and cobra), one Starlight page per command:
124
+
125
+ ```sh
126
+ node refgen/help2md.mjs --bin target/release/kasha --out docs/src/content/docs/reference/cli
127
+ ```
128
+
129
+ The kit ships it as the `help2md` binary, so a consuming project runs the version it pins, from `docs/`:
130
+
131
+ ```sh
132
+ npx --no-install help2md --bin ../target/release/kasha --out src/content/docs/reference/cli
133
+ ```
134
+
135
+ `--no-install` matters: without it, a missing kit makes `npx` fetch an unrelated `help2md` package from the npm registry.
136
+
137
+ Pages are named after the command path (`kasha.md`, `kasha-config-set.md`). `help` and cobra's default `completion` are skipped. Tests: `node --test`.
package/package.json CHANGED
@@ -1,6 +1,43 @@
1
1
  {
2
2
  "name": "@zebradil/docs-kit",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "type": "module",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/Zebradil/docs-kit.git"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "exports": {
13
+ ".": "./packages/docs-kit/index.mjs",
14
+ "./content": "./packages/docs-kit/content.mjs"
15
+ },
16
+ "bin": {
17
+ "help2md": "refgen/help2md.mjs"
18
+ },
19
+ "files": [
20
+ "packages/docs-kit",
21
+ "!packages/docs-kit/fixture",
22
+ "schema/site.schema.json",
23
+ "schema/validate.mjs",
24
+ "refgen/help2md.mjs"
25
+ ],
26
+ "scripts": {
27
+ "test": "node --test",
28
+ "validate": "node schema/validate.mjs"
29
+ },
30
+ "dependencies": {
31
+ "@astrojs/starlight": "0.42.10",
32
+ "@fontsource-variable/fraunces": "5.3.0",
33
+ "@fontsource-variable/instrument-sans": "5.3.0",
34
+ "@fontsource-variable/jetbrains-mono": "5.3.0",
35
+ "@fontsource-variable/schibsted-grotesk": "5.3.0",
36
+ "@fontsource/ibm-plex-mono": "5.3.0",
37
+ "@fontsource/outfit": "5.3.0",
38
+ "ajv": "8.20.0",
39
+ "astro": "7.4.7",
40
+ "yaml": "2.9.1"
41
+ },
42
+ "version": "0.10.0"
43
+ }
@@ -0,0 +1,205 @@
1
+ ---
2
+ // The cascade panel: one request falling through ordered tiers of backends, one tab per scenario.
3
+ import { TabItem, Tabs } from '@astrojs/starlight/components';
4
+ import site from 'virtual:docs-kit/site';
5
+ import { escape, inline } from './text.mjs';
6
+
7
+ const cascade = site.cascade;
8
+ const glyph = { hit: '●', miss: '×', down: '○', idle: '·' };
9
+ const word = { hit: 'hit', miss: 'miss', down: 'down', idle: 'not asked' };
10
+ const state = (scenario, id) => scenario.states[id] ?? { state: 'idle' };
11
+ ---
12
+
13
+ <section class="kit-cascade" aria-labelledby="kit-cascade-title">
14
+ <div class="kit-cascade-head">
15
+ <h2 id="kit-cascade-title">{cascade.title ?? 'How a request falls through'}</h2>
16
+ {cascade.request && <code>{cascade.request}</code>}
17
+ </div>
18
+ {
19
+ cascade.hub && (
20
+ <div class="kit-cascade-hub">
21
+ <span class="kit-cascade-hub-name">{cascade.hub.name}</span>
22
+ {cascade.hub.body && <span class="kit-cascade-hub-body" set:html={inline(cascade.hub.body)} />}
23
+ </div>
24
+ )
25
+ }
26
+ <Tabs>
27
+ {
28
+ cascade.scenarios.map((scenario) => (
29
+ <TabItem label={scenario.label}>
30
+ <ol class="kit-cascade-tiers">
31
+ {cascade.tiers.map((tier) => (
32
+ <li class="kit-cascade-tier">
33
+ <div class="kit-cascade-tier-name">
34
+ {tier.label && <span>{tier.label}</span>}
35
+ <strong>{tier.name}</strong>
36
+ </div>
37
+ <ul>
38
+ {tier.backends.map((b) => {
39
+ const s = state(scenario, b.id);
40
+ return (
41
+ <li class="kit-cascade-backend" data-state={s.state}>
42
+ <code>{b.name}</code>
43
+ <span>
44
+ {glyph[s.state]} {word[s.state]}
45
+ {s.text && ` · ${s.text}`}
46
+ </span>
47
+ </li>
48
+ );
49
+ })}
50
+ </ul>
51
+ </li>
52
+ ))}
53
+ </ol>
54
+ {scenario.note && <p class="kit-cascade-note" set:html={inline(scenario.note)} />}
55
+ </TabItem>
56
+ ))
57
+ }
58
+ </Tabs>
59
+ </section>
60
+
61
+ <style is:global>
62
+ .kit-cascade {
63
+ border: 1px solid var(--sl-color-hairline-light);
64
+ border-radius: 1.5rem;
65
+ overflow: hidden;
66
+ }
67
+ .kit-cascade-head {
68
+ display: flex;
69
+ flex-wrap: wrap;
70
+ justify-content: space-between;
71
+ align-items: baseline;
72
+ gap: 0.5rem 1.5rem;
73
+ padding: 1.125rem 1.5rem;
74
+ border-bottom: 1px solid var(--sl-color-hairline-light);
75
+ }
76
+ .kit-landing .kit-cascade-head h2 {
77
+ margin: 0;
78
+ font-family: var(--sl-font-mono);
79
+ font-size: var(--sl-text-xs);
80
+ font-weight: 400;
81
+ letter-spacing: 0.08em;
82
+ text-transform: uppercase;
83
+ color: var(--sl-color-gray-3);
84
+ }
85
+ .kit-cascade-head code {
86
+ padding: 0;
87
+ background: none;
88
+ font-size: var(--sl-text-sm);
89
+ color: var(--sl-color-gray-2);
90
+ }
91
+ .kit-cascade-hub {
92
+ display: flex;
93
+ flex-wrap: wrap;
94
+ align-items: center;
95
+ gap: 0.75rem 1.25rem;
96
+ padding: 1.25rem 1.5rem;
97
+ border-bottom: 1px solid var(--sl-color-hairline-light);
98
+ background-image: radial-gradient(circle, var(--sl-color-gray-5) 1.4px, transparent 1.6px);
99
+ background-size: 12px 12px;
100
+ }
101
+ .kit-cascade-hub-name {
102
+ padding: 0.5rem 0.875rem;
103
+ border-radius: 0.625rem;
104
+ background: var(--sl-color-white);
105
+ color: var(--sl-color-black);
106
+ font-weight: 700;
107
+ }
108
+ .kit-cascade-hub-body {
109
+ padding: 0.125rem 0.375rem;
110
+ border-radius: 0.375rem;
111
+ background: var(--sl-color-black);
112
+ color: var(--sl-color-gray-2);
113
+ }
114
+ /* Starlight's tab strip, inset to line up with the panel's rows. */
115
+ .kit-cascade starlight-tabs {
116
+ display: block;
117
+ }
118
+ .kit-cascade starlight-tabs .tablist-wrapper {
119
+ padding: 0.75rem 1.5rem 0;
120
+ }
121
+ .kit-cascade [role='tabpanel'] {
122
+ margin: 0;
123
+ }
124
+ .kit-cascade-tiers,
125
+ .kit-cascade-tier ul {
126
+ margin: 0;
127
+ padding: 0;
128
+ list-style: none;
129
+ }
130
+ .kit-cascade-tier {
131
+ display: flex;
132
+ flex-wrap: wrap;
133
+ margin: 0;
134
+ border-bottom: 1px dashed var(--sl-color-hairline-light);
135
+ }
136
+ .kit-cascade-tier:last-child {
137
+ border-bottom: 0;
138
+ }
139
+ .kit-cascade-tier-name {
140
+ flex: 1 1 10rem;
141
+ display: flex;
142
+ flex-direction: column;
143
+ gap: 0.25rem;
144
+ padding: 1.375rem 1.5rem;
145
+ }
146
+ .kit-cascade-tier-name span {
147
+ font-family: var(--sl-font-mono);
148
+ font-size: var(--sl-text-xs);
149
+ color: var(--sl-color-gray-3);
150
+ }
151
+ .kit-cascade-tier-name strong {
152
+ font-size: var(--sl-text-lg);
153
+ color: var(--sl-color-white);
154
+ }
155
+ .kit-cascade-tier ul {
156
+ flex: 999 1 30rem;
157
+ display: grid;
158
+ grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
159
+ gap: 0.75rem;
160
+ padding: 1.125rem 1.5rem;
161
+ }
162
+ .kit-cascade-backend {
163
+ display: flex;
164
+ flex-direction: column;
165
+ gap: 0.375rem;
166
+ margin: 0;
167
+ padding: 0.875rem 1rem;
168
+ border: 1px solid var(--sl-color-hairline-light);
169
+ border-radius: 0.875rem;
170
+ font-family: var(--sl-font-mono);
171
+ font-size: var(--sl-text-xs);
172
+ color: var(--sl-color-gray-3);
173
+ }
174
+ .kit-cascade-backend code {
175
+ padding: 0;
176
+ background: none;
177
+ font-size: var(--sl-text-sm);
178
+ overflow-wrap: anywhere;
179
+ color: var(--sl-color-gray-3);
180
+ }
181
+ .kit-cascade-backend[data-state='hit'] {
182
+ border: 1.5px solid var(--sl-color-accent);
183
+ background: var(--sl-color-accent-low);
184
+ color: var(--sl-color-text-accent);
185
+ }
186
+ .kit-cascade-backend[data-state='hit'] code {
187
+ color: var(--sl-color-white);
188
+ }
189
+ .kit-cascade-backend[data-state='down'] {
190
+ border: 1.5px dashed var(--sl-color-orange);
191
+ color: var(--sl-color-orange-high);
192
+ }
193
+ .kit-cascade-backend:is([data-state='down'], [data-state='miss']) code {
194
+ color: var(--sl-color-gray-2);
195
+ }
196
+ .kit-cascade-note {
197
+ margin: 0;
198
+ padding: 1rem 1.5rem;
199
+ border-top: 1px solid var(--sl-color-hairline-light);
200
+ background: var(--sl-color-bg-nav);
201
+ font-size: var(--sl-text-sm);
202
+ line-height: 1.5;
203
+ color: var(--sl-color-gray-2);
204
+ }
205
+ </style>
@@ -0,0 +1,134 @@
1
+ ---
2
+ // The diff panel: a change on one side, the files it changes in each target on the other, one tab per target.
3
+ import { Code, TabItem, Tabs } from '@astrojs/starlight/components';
4
+ import site from 'virtual:docs-kit/site';
5
+ import { inline } from './text.mjs';
6
+
7
+ const diff = site.diff;
8
+ const count = (files, sign) => files.flatMap((f) => f.diff.split('\n')).filter((l) => l.startsWith(sign)).length;
9
+ const summary = (files) =>
10
+ files.length
11
+ ? `${files.length} ${files.length === 1 ? 'file' : 'files'} changed, +${count(files, '+')} −${count(files, '-')}`
12
+ : 'No changes';
13
+ // Expressive Code's own `diff` language leaves a diff with hunk headers unmarked, so the kit turns the
14
+ // +/- column into ins/del line markers, marks the hunk headers, and highlights the file in its own language.
15
+ const file = ({ path, diff }) => {
16
+ const marks = { ins: [], del: [], mark: [] };
17
+ const lines = diff.replace(/\n$/, '').split('\n').map((line, i) => {
18
+ if (line.startsWith('@@')) return marks.mark.push(i + 1) && line;
19
+ if (line[0] === '+') marks.ins.push(i + 1);
20
+ if (line[0] === '-') marks.del.push(i + 1);
21
+ return line.slice(1);
22
+ });
23
+ const meta = Object.entries(marks).filter(([, n]) => n.length).map(([k, n]) => `${k}={${n}}`);
24
+ return { code: lines.join('\n'), lang: path.split('.').pop().replace(/^yml$/, 'yaml'), meta: [`title="${path}"`, ...meta].join(' ') };
25
+ };
26
+ ---
27
+
28
+ <section class="kit-diff" aria-labelledby="kit-diff-title">
29
+ <div class="kit-diff-head">
30
+ <h2 id="kit-diff-title">{diff.title ?? 'What a change looks like'}</h2>
31
+ {diff.intro && <p set:html={inline(diff.intro)} />}
32
+ </div>
33
+ <div class="kit-diff-body">
34
+ {
35
+ diff.change && (
36
+ <div class="kit-diff-change">
37
+ <p class="kit-diff-label">
38
+ {diff.change.label ?? 'The change'} <span>{summary(diff.change.files)}</span>
39
+ </p>
40
+ {diff.change.files.map((f) => (
41
+ <Code {...file(f)} />
42
+ ))}
43
+ </div>
44
+ )
45
+ }
46
+ <div class="kit-diff-result">
47
+ <p class="kit-diff-label">{diff.label ?? 'What it changes'}</p>
48
+ <Tabs>
49
+ {
50
+ diff.tabs.map((t) => (
51
+ <TabItem label={t.label}>
52
+ <p class="kit-diff-summary">{summary(t.files)}</p>
53
+ {t.files.map((f) => (
54
+ <Code {...file(f)} />
55
+ ))}
56
+ </TabItem>
57
+ ))
58
+ }
59
+ </Tabs>
60
+ </div>
61
+ </div>
62
+ </section>
63
+
64
+ <style is:global>
65
+ .kit-landing .kit-diff-head {
66
+ max-width: 44rem;
67
+ }
68
+ .kit-diff-head p {
69
+ margin: 0;
70
+ line-height: 1.55;
71
+ color: var(--sl-color-gray-2);
72
+ }
73
+ .kit-diff-body {
74
+ display: grid;
75
+ grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
76
+ gap: 1.5rem;
77
+ margin-top: 2rem;
78
+ }
79
+ @media (max-width: 60rem) {
80
+ .kit-diff-body {
81
+ grid-template-columns: minmax(0, 1fr);
82
+ }
83
+ }
84
+ .kit-diff-change,
85
+ .kit-diff-result {
86
+ display: flex;
87
+ flex-direction: column;
88
+ gap: 1rem;
89
+ min-width: 0;
90
+ padding: 1.25rem;
91
+ border: 1px solid var(--sl-color-hairline-light);
92
+ border-radius: 1rem;
93
+ background: var(--sl-color-bg-nav);
94
+ }
95
+ .kit-diff-result {
96
+ border-color: var(--sl-color-accent);
97
+ }
98
+ .kit-diff-label {
99
+ display: flex;
100
+ flex-wrap: wrap;
101
+ justify-content: space-between;
102
+ gap: 0.25rem 1rem;
103
+ margin: 0;
104
+ font-family: var(--sl-font-mono);
105
+ font-size: var(--sl-text-xs);
106
+ letter-spacing: 0.06em;
107
+ text-transform: uppercase;
108
+ color: var(--sl-color-gray-3);
109
+ }
110
+ .kit-diff-label span,
111
+ .kit-diff-summary {
112
+ margin: 0;
113
+ font-family: var(--sl-font-mono);
114
+ font-size: var(--sl-text-xs);
115
+ letter-spacing: 0;
116
+ text-transform: none;
117
+ color: var(--sl-color-gray-2);
118
+ }
119
+ .kit-diff starlight-tabs {
120
+ display: block;
121
+ }
122
+ .kit-diff [role='tabpanel'] {
123
+ display: flex;
124
+ flex-direction: column;
125
+ gap: 1rem;
126
+ margin-top: 1rem;
127
+ }
128
+ .kit-diff [role='tabpanel'][hidden] {
129
+ display: none;
130
+ }
131
+ .kit-diff .expressive-code {
132
+ margin: 0;
133
+ }
134
+ </style>