fertig 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,99 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. This project follows
4
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The public surface
5
+ is the token names, the class names (the seven, plus the layout utilities),
6
+ and the ARIA attributes the component layer reads — changes to any of those
7
+ are breaking.
8
+
9
+ ## [1.0.0] — 2026-08-30
10
+
11
+ First release. The project, the repo and the stylesheet are called
12
+ `fertig.css`; the npm package is `fertig`, and the cascade layer is
13
+ `@layer fertig` — a dot in a layer name would declare a sub-layer.
14
+
15
+ ### Added
16
+
17
+ - Classless styling for the full semantic element set: headings, prose, lists,
18
+ description lists, quotes, rules, code, tables, every form control,
19
+ fieldsets, buttons, details, dialog, figures, media and asides.
20
+ - Layout model where direct children of `<body>` are containers — `<nav>` is a
21
+ full-bleed toolbar with a vibrancy blur, and
22
+ `header`/`main`/`footer` are the page.
23
+ - Light and dark themes from a single `light-dark()` token block, with
24
+ `data-theme="light|dark"` to override the OS preference.
25
+ - Elevation scale (`--up`, `--up2`, `--dn`) whose shadow alphas step up in dark
26
+ mode, since a shadow on a dark ground reads as nothing on its own. The
27
+ shadows come off a real colour token (`--sh`) through relative colour syntax,
28
+ not an HSL triplet you could not use directly.
29
+ - Component layer addressed by ARIA rather than by class: segmented controls
30
+ (`role="group"`), tabs (`role="tablist"`), switches (`role="switch"`),
31
+ `[popover]` menus anchored to their invoker, breadcrumbs, `<dialog>` with an
32
+ entrance transition, `aria-busy` spinners and `data-tooltip`.
33
+ - Button variants (`data-variant`, `data-size`, `data-icon`, `data-block`) and
34
+ card anatomy (`<header>`/`<footer>`, full-bleed media, `data-tone`,
35
+ `<a class="card">` hover lift).
36
+ - Seven optional classes: `.row`, `.grid`, `.card`, `.badge`, `.muted`,
37
+ `.center`, `.wide`.
38
+ - Dialog anatomy: an optional `<header>` and `<footer>` that run edge to edge
39
+ and stay pinned while the body scrolls. Sticky rather than a grid, because a
40
+ classless sheet has no wrapper around the loose middle children to make a
41
+ grid row out of; the sticky offsets are negative so the chrome pins to the
42
+ dialog's border edge rather than its padding edge, which is where content
43
+ would otherwise scroll through.
44
+ - A max-width scale on Tailwind's names — `.max-w-xs` through `.max-w-7xl`,
45
+ plus `.max-w-full`, `.max-w-none` and `.max-w-prose`. Whole rather than
46
+ partial: a scale where `.max-w-2xl` works and `.max-w-3xl` silently does not
47
+ is worse than no scale. They are `max-inline-size`, so they still mean
48
+ "along the text" in a vertical writing mode.
49
+ - Layout utilities, named after Tailwind's so the names transfer: `.flex`,
50
+ `.flex-col`, `.flex-wrap`, `.flex-1`, `.grid-cols-2|3|4`,
51
+ `.items-start|center|end`, `.justify-start|center|end|between`,
52
+ `.gap-0|1|2|3|4|6`, `.mx-auto`, `.ms-auto`, `.me-auto`, `.w-full`,
53
+ `.hidden`. Layout only — no colour, type or sizing scale, and no responsive
54
+ variants, which would need a build step.
55
+ - Right-to-left support. Every inline-direction rule is flow-relative, with
56
+ `:dir(rtl)` rules for the two that cannot be — the switch knob's `translate`
57
+ and the fallback `<select>` chevron's background position. Verified by
58
+ rendering a Persian page in both directions.
59
+ - A second layer, `fertig-a11y`, declared after `fertig`. The forced-colors
60
+ block lives there and wins on layer order.
61
+ - Print styles, `prefers-reduced-motion` handling, and thin scrollbars.
62
+ - Robustness: `overflow-wrap: break-word`; `:required`, `:read-only` and
63
+ `:autofill` states; slashed, tabular numerals; `object-fit` on card media;
64
+ smooth in-page scrolling; `overscroll-behavior` on overlays; `@page` margins
65
+ with orphan and widow control.
66
+ - Environment queries: `inverted-colors` and `color-gamut: p3`.
67
+ - `anchor-size()` and `position-visibility` for menus, `::spelling-error`,
68
+ and Safari's native `<input switch>` styled to match `role="switch"`.
69
+
70
+ ### Browser support
71
+
72
+ - Two-year support policy: the sheet targets browsers from the last two years
73
+ and carries nothing for the ones before them. It ships no vendor prefixes
74
+ except the three no engine has replaced (`-webkit-text-size-adjust`, the
75
+ autofill repaint, and the `progress` pseudo-elements).
76
+ - The sheet is wrapped in `@layer fertig`, so unlayered author CSS overrides it
77
+ at any specificity. There is no `!important` anywhere in it: inside a cascade
78
+ layer an important declaration outranks your own unlayered CSS, which would
79
+ contradict the point of shipping in a layer.
80
+
81
+ ### Site
82
+
83
+ - A blocks gallery with 16 ready-to-use patterns — toolbars, stat rows, tables
84
+ with totals, pagination, empty states, sign-in, settings, alerts, confirm
85
+ dialogs, tabs, menus, pricing and shortcuts. Each snippet is generated from
86
+ its own live preview at runtime, so the code and the demo cannot drift apart.
87
+ - `llms.txt` describing the layout model, the seven classes, the ARIA
88
+ component conventions and the tokens.
89
+
90
+ ### Verified
91
+
92
+ - All foreground/background pairs meet WCAG 2.1 AA (≥ 4.5:1) in both themes,
93
+ at rest and on hover; the tightest is muted text on chrome at 4.65:1.
94
+ - Progressive enhancement behind `@supports`: `contrast-color()`,
95
+ `::details-content` with `interpolate-size`, `field-sizing`,
96
+ `corner-shape: squircle`, `text-box: trim-both` and `@property`-typed
97
+ shadow alphas. None of them are required for the sheet to work.
98
+ - Tables scroll themselves below 40rem instead of widening the page.
99
+ - 28.0 KB raw, 7.6 KB gzipped, 6.7 KB brotli (`fertig.min.css`).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mojtaba Beheshti
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 ADDED
@@ -0,0 +1,273 @@
1
+ # fertig.css
2
+
3
+ A classless CSS file for developers who want a project to look presentable in
4
+ the ten seconds before they start building it. Link it, write ordinary HTML,
5
+ and the page is finished.
6
+
7
+ **28.0 KB raw · 7.6 KB gzipped · no build step · no dependencies.**
8
+
9
+ ```html
10
+ <link rel="stylesheet" href="fertig.css">
11
+ ```
12
+
13
+ That is the whole integration. Write semantic HTML; it looks finished.
14
+ Open `index.html` for the full demo.
15
+
16
+ ## Install
17
+
18
+ ```sh
19
+ npm install fertig
20
+ ```
21
+
22
+ ```html
23
+ <!-- or from a CDN, pinned -->
24
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fertig@1/fertig.min.css">
25
+ ```
26
+
27
+ ```css
28
+ /* or through a bundler */
29
+ @import "fertig";
30
+ ```
31
+
32
+ ## What it is
33
+
34
+ System type with macOS window furniture and a classic sense of depth —
35
+ a nod to System 7 and Win98, not a costume.
36
+
37
+ - **System type, set properly** — 16px on a 1.65 line height across roughly
38
+ seventy characters. Code keeps a monospace face, where it earns its place.
39
+ - **A window on a desktop.** `<nav>` becomes a full-bleed toolbar with a
40
+ vibrancy blur; `header`/`main`/`footer` are the paper.
41
+ - **Depth from hairlines and soft shadows.** Buttons and cards sit above the
42
+ page, inputs and code sit below it. Shadow alphas step up in dark mode,
43
+ because a shadow on a dark background does nothing on its own.
44
+ - **Quiet text.** Links underline on hover rather than inverting mid-paragraph.
45
+ - **Dark mode with no second stylesheet.** One `light-dark()` token block.
46
+ Add `data-theme="dark"` (or `"light"`) on `<html>` to override the OS.
47
+
48
+ ## Layout
49
+
50
+ Direct children of `<body>` are the containers:
51
+
52
+ ```html
53
+ <body>
54
+ <nav>…</nav> <!-- toolbar: full-bleed, contents on the measure -->
55
+ <header>…</header>
56
+ <main>…</main>
57
+ <footer>…</footer>
58
+ </body>
59
+ ```
60
+
61
+ Using a framework where `body` is not the semantic parent? Re-point the four
62
+ container rules at your root element (`#root`, `#__next`) — they are the only
63
+ place `body >` appears.
64
+
65
+ ## Components
66
+
67
+ Addressed by ARIA attributes, not by class — the markup stays semantic and
68
+ accessible by construction.
69
+
70
+ | Component | Markup |
71
+ |---|---|
72
+ | Segmented control | `<div role="group">` of buttons, `aria-pressed` |
73
+ | Tabs | `<div role="tablist">`, `<button role="tab" aria-selected>` |
74
+ | Switch | `<input type="checkbox" role="switch">` |
75
+ | Menu | any `[popover]` + `popovertarget` (anchored, no JS) |
76
+ | Breadcrumb | `<nav aria-label="Breadcrumb"><ol>` |
77
+ | Dialog | `<dialog>` — animates in, blurs the page behind; optional `<header>`/`<footer>` pin while the body scrolls |
78
+ | Loading | `aria-busy="true"` (inline spinner) |
79
+ | Tooltip | `data-tooltip="…"` |
80
+ | Button variants | `data-variant="ghost\|link"`, `data-size="sm\|lg"`, `data-icon`, `data-block` |
81
+ | Card anatomy | `<header>` / `<footer>` inside `.card`; `<a class="card">` lifts on hover |
82
+ | Tones | `data-tone="ok\|warn\|err"` retints any component |
83
+
84
+ ## The seven optional classes
85
+
86
+ `.row` `.grid` `.card` `.badge` `.muted` `.center` `.wide`
87
+
88
+ Plus `.primary` on a button — though `type="submit"` already gets it.
89
+
90
+ ## Layout utilities, borrowed from Tailwind
91
+
92
+ The names are Tailwind's on purpose: if you know them there they mean the same
93
+ thing here, so nothing new has to be learned.
94
+
95
+ ```
96
+ .flex .flex-col .flex-wrap .flex-1
97
+ .grid-cols-2 .grid-cols-3 .grid-cols-4
98
+ .items-start .items-center .items-end
99
+ .justify-start .justify-center .justify-end .justify-between
100
+ .gap-0 .gap-1 .gap-2 .gap-3 .gap-4 .gap-6 (0 · .25 · .5 · .75 · 1 · 1.5rem)
101
+ .mx-auto .ms-auto .me-auto .w-full .hidden
102
+ .max-w-xs .max-w-sm .max-w-md .max-w-lg .max-w-xl (20 · 24 · 28 · 32 · 36rem)
103
+ .max-w-2xl .max-w-3xl .max-w-4xl .max-w-5xl .max-w-6xl .max-w-7xl (42 · 48 · 56 · 64 · 72 · 80rem)
104
+ .max-w-full .max-w-none .max-w-prose
105
+ ```
106
+
107
+ Layout and width only. No colour or type scale, and no responsive
108
+ variants — those need a build step, and this file does not have one. The
109
+ margins are flow-relative (`ms`/`me`, not `ml`/`mr`), so a toolbar still lands
110
+ correctly in Persian or Arabic. `.grid` is fertig.css's own auto-fit grid;
111
+ adding `.grid-cols-3` pins it to three columns.
112
+
113
+ The `max-w-*` scale is Tailwind's, whole rather than partial — a half-scale
114
+ where `.max-w-2xl` works and `.max-w-3xl` silently does not is worse than no
115
+ scale at all. They are `max-inline-size`, so they still mean "along the text"
116
+ in a vertical writing mode, and they outrank the sheet's own measure on
117
+ `body > *`, so they retarget a page container as readily as anything inside
118
+ one. `.max-w-prose` is that measure, as a class.
119
+
120
+ ## Customising
121
+
122
+ Override the four tokens you'd actually want to change:
123
+
124
+ ```css
125
+ :root {
126
+ --ac: light-dark(#c2410c, #fb923c); /* accent */
127
+ --w: 48rem; /* measure */
128
+ --r: 0px; /* control radius — go sharp */
129
+ --f: "Inter", system-ui, sans-serif; /* text font */
130
+ }
131
+ ```
132
+
133
+ If you change `--ac`, check `--on-ac` too — that is the text colour sitting on
134
+ the accent, and a light accent needs dark text to stay legible.
135
+ `--up` / `--up2` / `--dn` are the elevation scale, `--a1` / `--a2` the shadow
136
+ alphas, `--rw` the window radius.
137
+
138
+ ## Also handled
139
+
140
+ `:target`, external-link arrows, `user-invalid` fields, a CSS-drawn select
141
+ chevron, thin scrollbars, `sup`/`sub` that don't stretch lines, `q`/`dfn`/
142
+ `ins`/`del`/`address`/`meter`/`output`/`optgroup`/`hgroup`, print styles, and
143
+ `prefers-reduced-motion`.
144
+
145
+ ## Right-to-left
146
+
147
+ Every inline-direction rule is flow-relative — `padding-inline-start`,
148
+ `border-inline-start`, `margin-inline-end`, `text-align: start`,
149
+ `border-start-end-radius` — so `dir="rtl"` mirrors the sheet with nothing to
150
+ configure:
151
+
152
+ ```html
153
+ <html lang="fa" dir="rtl">
154
+ ```
155
+
156
+ List markers, blockquote and `<aside>` accent bars, table gutters, breadcrumb
157
+ separators, the segmented control's rounded ends, the `<select>` chevron and
158
+ the switch knob all move to the correct side. Two of those cannot be expressed
159
+ logically — `translate` and a background position — and carry `:dir(rtl)`
160
+ rules instead. The layout utilities follow the same rule: `.ms-auto` and
161
+ `.me-auto` exist, `.ml-auto` deliberately does not.
162
+
163
+ Tested by rendering a Persian page in both directions, not by inspection.
164
+
165
+ ## Accessibility
166
+
167
+ Every foreground/background pair meets WCAG 2.1 AA (>= 4.5:1) in **both**
168
+ themes, measured in-browser from the computed token values:
169
+
170
+ | Pair | Light | Dark |
171
+ |---|---:|---:|
172
+ | Body text on paper | 16.83 | 14.94 |
173
+ | Muted text on paper | 5.07 | 5.92 |
174
+ | Links on paper | 5.37 | 6.17 |
175
+ | Muted on chrome | 4.65 | 5.24 |
176
+ | Text on accent | 5.37 | 7.63 |
177
+ | Tones (ok / warn / err) | 4.87–5.44 | 6.13–6.74 |
178
+
179
+ Motion is gated behind `prefers-reduced-motion`, focus uses a visible ring at
180
+ `:focus-visible`, and the component layer is driven by the same ARIA attributes
181
+ assistive technology reads.
182
+
183
+ ## Size
184
+
185
+ | Sheet | Raw | Gzip |
186
+ |---|---:|---:|
187
+ | **fertig.css** | **28.0 KB** | **7.6 KB** |
188
+ | Pico 2 classless | 71.0 KB | 10.1 KB |
189
+
190
+ Measured with `gzip -9` via `npm run build`. Most of the gap is Pico's full
191
+ colour palette and its base64-SVG control icons; see
192
+ `docs/classless-css-research.md`.
193
+
194
+ ## Overriding it
195
+
196
+ The sheet declares two layers, `@layer fertig, fertig-a11y` — the second holds
197
+ the forced-colors block so it can beat a `.card` shadow on layer order instead
198
+ of `!important`. Anything you write outside a layer beats both whatever the
199
+ specificity, so overriding is never a fight:
200
+
201
+ ```css
202
+ button { background: hotpink } /* wins, no !important needed */
203
+ ```
204
+
205
+ ## Modern CSS, used deliberately
206
+
207
+ Everything past the baseline sits behind `@supports` and is additive:
208
+ `contrast-color()` picks the text colour on your accent so an override cannot
209
+ fail contrast; anchor positioning attaches popover menus to their button;
210
+ `::details-content` with `interpolate-size` animates disclosures open;
211
+ `field-sizing` grows textareas; `corner-shape: squircle` gives continuous
212
+ corners; `text-box: trim-both` sits headings on their cap height; and
213
+ `@property` types the shadow alphas so elevation can transition;
214
+ `appearance: base-select` styles the dropdown picker itself; and `.card` is a
215
+ container you can write `@container` queries against. Without any of it,
216
+ nothing breaks. Relative colour (`oklch(from …)`) is not in that list — it is
217
+ baseline here, deriving both the shadow ink and the filled-button hover.
218
+
219
+ It also answers to the OS: `prefers-reduced-motion`,
220
+ `prefers-reduced-transparency`, `prefers-contrast`, `forced-colors`,
221
+ `pointer: coarse` (44px targets, WCAG 2.5.8), `env(safe-area-inset-*)`,
222
+ `update: fast` (e-ink never starts a transition), `inverted-colors` and
223
+ `color-gamut: p3`.
224
+
225
+ And it survives content it has never seen: a pasted URL wraps instead of
226
+ widening the page, tables scroll themselves on a phone, autofilled fields are
227
+ repainted so the browser yellow never shows, required and read-only fields
228
+ read correctly, numerals are slashed and tabular, and print gets real page
229
+ margins with no stranded lines.
230
+
231
+ ## Browser support
232
+
233
+ The policy is a two-year window: fertig.css targets browsers released in the last
234
+ two years and carries nothing for the ones before them — no vendor prefixes, no
235
+ polyfills, no fallback build. Needs `light-dark()`, `color-mix()`, `:has()`,
236
+ `@starting-style` and relative colour — Chrome 125+, Safari 17.5+,
237
+ Firefox 129+. Anchor positioning is
238
+ Chromium-only for now and is wrapped in `@supports`; without it, `[popover]`
239
+ menus centre on screen instead of sitting under their button. Everything else
240
+ degrades to unstyled-but-readable HTML.
241
+
242
+ ## Development
243
+
244
+ ```sh
245
+ npm run dev # serve on :8899
246
+ npm run build # regenerate fertig.min.css and print sizes
247
+ ```
248
+
249
+ ## Builds
250
+
251
+ | Build | Raw | Gzip | |
252
+ |---|---:|---:|---|
253
+ | `fertig.min.css` | 28.0 KB | 7.6 KB | everything |
254
+ | `fertig.core.min.css` | 21.7 KB | 6.3 KB | without the ARIA component layer |
255
+
256
+ Dropping the component layer saves 0.8 KB gzipped — worth knowing, rarely worth
257
+ doing. The weight is in the element coverage and forms, not the components.
258
+
259
+ ## Files
260
+
261
+ - `fertig.css` — source, commented
262
+ - `fertig.min.css` — minified, what you ship
263
+ - `index.html` — landing page
264
+ - `blocks.html` — ready-to-use markup blocks (16 of them)
265
+ - `llms.txt` — machine-readable summary for LLMs, per llmstxt.org
266
+ - `docs.html` — documentation
267
+ - `app.html` — a full product screen built with no page CSS at all
268
+ - `build.js` — minifier and size report
269
+ - `docs/classless-css-research.md` — the research behind the decisions
270
+
271
+ ## License
272
+
273
+ MIT © Mojtaba Beheshti
@@ -0,0 +1 @@
1
+ /*! fertig.css v1.0.0 — a classless CSS stylesheet. MIT */@property --a1{syntax:"<number>";inherits:true;initial-value:.08}@property --a2{syntax:"<number>";inherits:true;initial-value:.06}@layer fertig,fertig-a11y;@layer fertig{:root{color-scheme:light dark;accent-color:var(--ac);caret-color:var(--ac);--f:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--fm:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;--w:38rem;--r:6px;--rw:10px;--stone-100:oklch(97.5% .004 75);--stone-300:oklch(91% .006 75);--stone-500:oklch(72% .008 75);--stone-700:oklch(47% .009 75);--stone-900:oklch(26% .008 75);--sage-100:oklch(96% .022 155);--sage-300:oklch(87% .042 155);--sage-500:oklch(66% .058 155);--sage-700:oklch(47% .055 155);--sage-900:oklch(29% .038 155);--sky-100:oklch(96% .022 240);--sky-300:oklch(87% .045 240);--sky-500:oklch(64% .085 245);--sky-700:oklch(48% .095 250);--sky-900:oklch(30% .06 250);--clay-100:oklch(96% .022 45);--clay-300:oklch(88% .045 45);--clay-500:oklch(68% .085 45);--clay-700:oklch(50% .09 40);--clay-900:oklch(31% .055 40);--plum-100:oklch(96% .02 320);--plum-300:oklch(88% .038 320);--plum-500:oklch(66% .06 320);--plum-700:oklch(47% .065 320);--plum-900:oklch(29% .042 320);--gold-100:oklch(96.5% .028 90);--gold-300:oklch(89% .055 88);--gold-500:oklch(74% .085 85);--gold-700:oklch(55% .085 80);--gold-900:oklch(33% .05 80);--bg:light-dark(oklch(93.5% .006 75),oklch(16% .006 75));--el:light-dark(oklch(99.4% .002 75),oklch(21% .006 75));--face:light-dark(oklch(97.2% .005 75),oklch(25% .007 75));--fg:light-dark(oklch(22% .008 75),oklch(95% .004 75));--mut:light-dark(oklch(50% .009 75),oklch(70% .008 75));--bd:light-dark(oklch(22% .008 75 / .13),oklch(95% .004 75 / .13));--tb:light-dark(oklch(97.2% .005 75 / .85),oklch(25% .007 75 / .85));--ac:light-dark(var(--sky-700),oklch(78% .085 245));--on-ac:light-dark(#fff,#06121f);--sh:oklch(23.1% .007 286);--a1:.08;--a2:.06;--sh1:oklch(from var(--sh) l c h / var(--a1));--sh2:oklch(from var(--sh) l c h / var(--a2));--up:0 1px 1px var(--sh1);--up2:0 1px 2px var(--sh1),0 6px 16px -6px var(--sh2);--dn:inset 0 1px 2px oklch(from var(--sh) l c h / .08);--caps:.74em/1.4 var(--f)}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--a1:.5;--a2:.45}}@supports (color:contrast-color(red)){:root{--on-ac:contrast-color(var(--ac))}}[data-theme=light]{color-scheme:light;--a1:.08;--a2:.06}[data-theme=dark]{color-scheme:dark;--a1:.5;--a2:.45}*,::before,::after{box-sizing:border-box}html{font:16px/1.65 var(--f);-webkit-text-size-adjust:100%;tab-size:2}body{margin:0;background:var(--bg);color:var(--fg);overflow-wrap:break-word;font-variant-numeric:slashed-zero tabular-nums}::selection{background:color-mix(in srgb,var(--ac) 28%,transparent)}:focus-visible{outline:3px solid color-mix(in srgb,var(--ac) 45%,transparent);outline-offset:1px;border-radius:var(--r)}img,svg,video,iframe{display:block;max-width:100%;height:auto}img,video{border-radius:var(--r);box-shadow:var(--up2)}body>*{max-width:var(--w);margin-inline:auto;padding-inline:1.9rem}body>header,body>main,body>footer{background:var(--el);border-inline:1px solid var(--bd)}body>header{padding-block:2.4rem .8rem}body>main{padding-bottom:2.8rem}body>footer{padding-block:1.2rem 2rem;color:var(--mut);font-size:.85em;border-top:1px solid var(--bd);border-bottom:1px solid var(--bd);border-radius:0 0 var(--rw) var(--rw);margin-bottom:2.5rem;box-shadow:0 18px 30px -22px oklch(from var(--sh) l c h / .5)}body>nav{position:sticky;top:0;z-index:9;max-width:none;padding-inline:max(1.9rem,calc(50% - var(--w) / 2 + 1.9rem),env(safe-area-inset-left),env(safe-area-inset-right));display:flex;flex-wrap:wrap;gap:1.1rem;align-items:center;padding-block:calc(.6rem + env(safe-area-inset-top,0px)) .6rem;background:var(--tb);color:var(--fg);backdrop-filter:saturate(180%) blur(20px);border-bottom:1px solid var(--bd);font-size:.92em}body>nav a{color:var(--fg);text-decoration:none;opacity:.75}body>nav a:hover{opacity:1}body>nav:is(strong,b) a{opacity:1}body>nav ul{display:flex;flex-wrap:wrap;gap:1.1rem;list-style:none;padding:0;margin:0;flex:1}h1,h2,h3,h4,h5,h6{line-height:1.3;margin:1.4rem 0 .7rem;text-wrap:balance}h1{font-size:1.55rem;letter-spacing:-.015em}h2{font-size:1.25rem;letter-spacing:-.01em;margin-top:2.4rem}h3{font-size:1.08rem;margin-top:1.9rem}h4{font-size:1rem}h5,h6{font:700 var(--caps);text-transform:uppercase;letter-spacing:.1em;color:var(--mut)}:is(h1,h2,h3,h4,h5,h6):first-child{margin-top:0}@supports (text-box:trim-both cap alphabetic){h1,h2,h3,h4{text-box:trim-both cap alphabetic}}:is(section,article) +:is(section,article){margin-top:2.8rem}p,ul,ol,dl,pre,blockquote,table,figure,details,fieldset,hr{margin:1.1rem 0}p{text-wrap:pretty}a{color:var(--ac);text-underline-offset:3px;text-decoration-thickness:1px}a:hover{text-decoration-thickness:2px}small{font-size:.85em;color:var(--mut)}hr{border:0;border-top:1px solid var(--bd);margin:2.2rem 0}mark{background:light-dark(#ffe58f,#5c4a15);color:inherit;border-radius:3px;padding:0 .15em}abbr[title]{text-decoration:underline dotted;cursor:help}blockquote{border-inline-start:2px solid var(--bd);padding-block:.15rem;padding-inline:1.2rem 0;color:var(--mut)}ul,ol{padding-inline-start:1.5rem}li::marker{color:var(--mut)}dl{display:grid;grid-template-columns:max-content 1fr;gap:.35rem 1rem}dt{color:var(--mut)}dd{margin:0}figcaption{font-size:.85em;color:var(--mut);text-align:center}code,kbd,samp,pre{font-family:var(--fm);font-size:.9em}:not(pre)>code,samp{background:var(--face);border:1px solid var(--bd);border-radius:var(--r);padding:.08em .35em}kbd{background:var(--face);border:1px solid var(--bd);border-bottom-width:2px;border-radius:var(--r);padding:.08em .4em;box-shadow:var(--up)}pre{background:var(--face);border:1px solid var(--bd);border-radius:var(--r);padding:1rem;overflow-x:auto}pre code{background:none;border:0;padding:0;font-size:1em}:root{--syn-comment:light-dark(#6b7280,#8b949e);--syn-key:light-dark(#7c3aed,#c4a7fb);--syn-str:light-dark(#15803d,#7ee787);--syn-num:light-dark(#b45309,#f0b866);--syn-fn:light-dark(#1d4ed8,#93c5fd);--syn-attr:light-dark(#b91c1c,#ff9492)}:is(.hljs-comment,.hljs-quote,.token.comment,.token.prolog,.token.doctype){color:var(--syn-comment);font-style:italic}:is(.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-type,.hljs-built_in,.token.keyword,.token.atrule,.token.rule,.token.important,.token.selector){color:var(--syn-key)}:is(.hljs-string,.hljs-meta-string,.token.string,.token.attr-value,.token.char){color:var(--syn-str)}:is(.hljs-number,.hljs-symbol,.hljs-bullet,.token.number,.token.boolean,.token.constant,.token.unit){color:var(--syn-num)}:is(.hljs-title,.hljs-name,.hljs-section,.hljs-function,.token.tag,.token.function,.token.class-name){color:var(--syn-fn)}:is(.hljs-attr,.hljs-attribute,.hljs-variable,.hljs-template-variable,.token.attr-name,.token.property,.token.variable){color:var(--syn-attr)}:is(.hljs-punctuation,.hljs-operator,.token.punctuation,.token.operator){color:var(--mut)}:is(.hljs-emphasis,.token.italic){font-style:italic}:is(.hljs-strong,.token.bold){font-weight:700}:is(.hljs-deletion,.token.deleted){color:light-dark(#c0392b,#ff6b6b)}:is(.hljs-addition,.token.inserted){color:light-dark(#15803d,#7ee787)}table{width:100%;border-collapse:collapse;font-size:.92em}th,td{border-bottom:1px solid var(--bd);padding-block:.55rem;padding-inline:0 .7rem;text-align:start}th:last-child,td:last-child{padding-inline-end:0}thead th{border-bottom:1px solid color-mix(in srgb,var(--fg) 45%,transparent);font:700 var(--caps);text-transform:uppercase;letter-spacing:.09em;color:var(--mut);padding-bottom:.4rem}tbody tr:last-child td{border-bottom:0}tfoot td{font-weight:700;border-top:1px solid var(--bd);border-bottom:0}:is(th,td)[align=right]{text-align:right}:is(th,td)[align=center]{text-align:center}tbody tr:hover{background:var(--face)}@media (width <= 40rem){table{display:block;overflow-x:auto;overscroll-behavior-x:contain}}caption{text-align:start;color:var(--mut);font-size:.85em;padding-bottom:.35rem}button,input,select,textarea{font:inherit;color:inherit}label{display:block;font-size:.85em;color:var(--mut)}label:has(input){font-size:1rem;color:var(--fg)}:is(input,select,textarea) + label{margin-top:.9rem}textarea{width:100%;min-height:5rem;resize:vertical}@supports (field-sizing:content){textarea{field-sizing:content;max-height:24rem}}input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=submit],[type=button],[type=reset]),select,textarea{display:block;width:100%;padding:.4em .6em;background:var(--el);border:1px solid var(--bd);border-radius:var(--r);box-shadow:var(--dn)}select{appearance:none;padding-inline-end:2.2rem;background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%);background-position:calc(100% - 17px) 55%,calc(100% - 12.5px) 55%;background-size:5px 5px;background-repeat:no-repeat}select:dir(rtl){background-position:12.5px 55%,17px 55%}select[multiple]{background-image:none;padding-inline-end:.6em}@supports (appearance:base-select){select,::picker(select){appearance:base-select}select{display:flex;align-items:center;justify-content:space-between;gap:.6em;background-image:none;padding-inline-end:.7em}select::picker-icon{content:"";inline-size:.45em;block-size:.45em;flex:none;border:solid currentColor;border-width:0 1px 1px 0;rotate:45deg;translate:0 -.15em;opacity:.7;transition:rotate .15s ease,translate .15s ease}select:open::picker-icon{rotate:225deg;translate:0 .1em}::picker(select){min-width:anchor-size(width);border:1px solid var(--bd);border-radius:var(--r);padding:.3rem;background:var(--el);margin-block-start:.35rem;box-shadow:var(--up2),0 20px 40px -14px oklch(from var(--sh) l c h / .4)}option{display:flex;align-items:center;gap:.5em;padding:.4em .6em;border-radius:calc(var(--r) - 2px)}option:hover{background:var(--face)}option:checked{background:var(--ac);color:var(--on-ac)}option::checkmark{order:1;margin-inline-start:auto;content:"✓"}}:is(input,select,textarea):hover:not(:disabled){border-color:color-mix(in srgb,var(--fg) 25%,transparent)}:is(input,select,textarea):focus-visible{border-color:var(--ac)}input[type=checkbox],input[type=radio]{width:1.15em;height:1.15em;margin:0 .45em 0 0;vertical-align:-.18em}label:has(input[type=checkbox]),label:has(input[type=radio]){line-height:1.9}input[type=range]{width:100%;height:1.15em}::placeholder{color:var(--mut)}@supports selector(::spelling-error){::spelling-error{text-decoration:wavy underline light-dark(#c0392b,#ff6b6b)}::grammar-error{text-decoration:wavy underline light-dark(#9a6700,#d29922)}}:is(input,textarea):read-only:not(:disabled){background:var(--face);cursor:default}label:has(+:required)::after,label:has(:required)::after{content:" *";color:var(--ac)}input:autofill,input:autofill:hover,input:autofill:focus{-webkit-text-fill-color:var(--fg);box-shadow:var(--dn),inset 0 0 0 100px var(--el);caret-color:var(--ac)}:disabled{color:var(--mut);cursor:not-allowed;box-shadow:none}fieldset{border:1px solid var(--bd);border-radius:var(--r);padding:.9rem 1rem 1rem;background:var(--face)}fieldset:focus-within{border-color:color-mix(in srgb,var(--ac) 45%,var(--bd))}legend{float:left;width:100%;margin-bottom:.8rem;padding:0 0 .6rem;border-bottom:1px solid var(--bd);font-size:.95em;font-weight:700;color:var(--fg)}legend + *{clear:left}button,[type=submit],[type=button],[type=reset],:where(a.primary,a[role=button]),::file-selector-button{display:inline-block;text-decoration:none;text-align:center;padding:.38em 1.1em;background:var(--el);color:var(--fg);cursor:pointer;border:1px solid var(--bd);border-radius:var(--r);box-shadow:var(--up);font:inherit;min-width:5rem}:is(button,[type=submit],[type=button],[type=reset],a.primary,a[role=button]):hover:not(:disabled){background:var(--face)}:is(button,[type=submit],[type=button],[type=reset],a.primary,a[role=button]):active:not(:disabled){box-shadow:var(--dn);translate:0 .5px}[type=submit],.primary{background:var(--ac);border-color:transparent;color:var(--on-ac)}:is([type=submit],.primary,a.primary):hover:not(:disabled){background:oklch(from var(--ac) calc(l + .05) c h)}[data-size=sm]{padding:.2em .7em;font-size:.85em;min-width:0}[data-size=lg]{padding:.55em 1.5em;font-size:1.05em}button[data-icon]{min-width:0;padding:.38em .62em;line-height:1}[data-block]{display:block;width:100%;min-width:0}[data-variant=ghost]{background:none;border-color:transparent;box-shadow:none}[data-variant=ghost]:hover:not(:disabled){background:var(--face);border-color:var(--bd)}[data-variant=link]{background:none;border:0;box-shadow:none;min-width:0;padding-inline:.2em;color:var(--ac);text-decoration:underline;text-underline-offset:3px}[data-variant=link]:hover:not(:disabled){background:none;text-decoration-thickness:2px}button[aria-pressed=true]{background:var(--face);color:var(--ac);font-weight:700}button[aria-pressed=true]:hover:not(:disabled){background:color-mix(in srgb,var(--fg) 7%,var(--face))}:is([type=submit],.primary){box-shadow:var(--up),inset 0 1px 0 light-dark(#fff3,#ffffff26)}:is([type=submit],.primary):active:not(:disabled){box-shadow:inset 0 1px 3px #0006}@supports (corner-shape:squircle){*{corner-shape:squircle}}details{border:1px solid var(--bd);border-radius:var(--r);padding:.7rem 1.1rem;background:var(--el)}summary{cursor:pointer;font-weight:700;list-style:none}summary::before{content:"▸ ";color:var(--mut)}details[open]>summary::before{content:"▾ "}details[open]>summary{margin-bottom:.6rem}dialog{background:var(--el);color:var(--fg);border:1px solid var(--bd);border-radius:var(--rw);padding:1.4rem;max-width:min(30rem,92dvw);box-shadow:0 32px 64px -16px oklch(from var(--sh) l c h / .45)}dialog>:last-child:not(footer){margin-bottom:0}dialog,[popover]{overscroll-behavior:contain}dialog::backdrop{background:oklch(from var(--sh) l c h / .35);backdrop-filter:blur(3px)}dialog:has(>:is(header,footer)){max-block-size:min(44rem,85dvh);overflow:auto}dialog>:is(header,footer){position:sticky;z-index:1;margin-inline:-1.4rem;padding:.7rem 1.4rem;background:var(--el)}dialog>header{inset-block-start:-1.4rem;margin-block:-1.4rem 1rem;font-weight:700;border-bottom:1px solid var(--bd);border-radius:var(--rw) var(--rw) 0 0}dialog>header>:is(h1,h2,h3,h4,p){margin:0;font-size:1.05rem}dialog>footer{inset-block-end:-1.4rem;margin-block:1rem -1.4rem;border-top:1px solid var(--bd);border-radius:0 0 var(--rw) var(--rw);display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;justify-content:flex-end}dialog>footer>:is(p,span):first-child{margin:0;margin-inline-end:auto;color:var(--mut)}@media (prefers-reduced-motion:no-preference) and (update:fast){dialog,dialog::backdrop{transition:opacity .2s,translate .2s,display .2s allow-discrete,overlay .2s allow-discrete}dialog{opacity:0;translate:0 10px}dialog[open]{opacity:1;translate:0}dialog::backdrop{opacity:0}dialog[open]::backdrop{opacity:1}@starting-style{dialog[open]{opacity:0;translate:0 10px}}@starting-style{dialog[open]::backdrop{opacity:0}}[popover]{opacity:0;translate:0 -4px;transition:opacity .13s,translate .13s,display .13s allow-discrete,overlay .13s allow-discrete}[popover]:popover-open{opacity:1;translate:0}@starting-style{[popover]:popover-open{opacity:0;translate:0 -4px}}}search{display:block}::target-text{background:color-mix(in srgb,var(--ac) 28%,transparent)}aside{border:1px solid var(--bd);border-inline-start:3px solid var(--ac);border-radius:var(--r);border-start-start-radius:0;border-end-start-radius:0;background:var(--el);padding:.7rem 1.1rem}progress{width:100%;height:.5rem;border:0;border-radius:calc(infinity * 1px);background:var(--face)}progress::-webkit-progress-bar{background:var(--face);border-radius:calc(infinity * 1px)}progress::-webkit-progress-value{background:var(--ac);border-radius:calc(infinity * 1px)}progress::-moz-progress-bar{background:var(--ac);border-radius:calc(infinity * 1px)}@supports selector(::details-content){@media (prefers-reduced-motion:no-preference) and (update:fast){:root{interpolate-size:allow-keywords}details::details-content{block-size:0;overflow:clip;transition:block-size .28s ease,content-visibility .28s allow-discrete}details[open]::details-content{block-size:auto}}}.muted{color:var(--mut)}.center{text-align:center}.wide{max-width:66rem}.row{display:flex;flex-wrap:wrap;gap:.7rem;align-items:center}.row:is(input:not([type=checkbox],[type=radio]),textarea){width:auto;flex:1 1 10rem;min-width:0}.row select{width:auto;flex:0 1 auto;min-width:0}.row:is(progress,meter){width:auto;flex:1 1 6rem}.row>label{flex:none;margin-top:0}.grid{display:grid;gap:.9rem;grid-template-columns:repeat(auto-fit,minmax(11rem,1fr))}.card{container-type:inline-size;border:1px solid var(--bd);border-radius:var(--r);padding:.9rem;background:var(--el);box-shadow:var(--up2);display:flex;flex-direction:column;gap:.85rem}.card>*{margin-block:0}.flex{display:flex}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.flex-1{flex:1;min-width:0}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.items-start{align-items:start}.items-center{align-items:center}.items-end{align-items:end}.justify-start{justify-content:start}.justify-center{justify-content:center}.justify-end{justify-content:end}.justify-between{justify-content:space-between}.gap-0{gap:0}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.mx-auto{margin-inline:auto}.ms-auto{margin-inline-start:auto}.me-auto{margin-inline-end:auto}.w-full{width:100%}.max-w-xs{max-inline-size:20rem}.max-w-sm{max-inline-size:24rem}.max-w-md{max-inline-size:28rem}.max-w-lg{max-inline-size:32rem}.max-w-xl{max-inline-size:36rem}.max-w-2xl{max-inline-size:42rem}.max-w-3xl{max-inline-size:48rem}.max-w-4xl{max-inline-size:56rem}.max-w-5xl{max-inline-size:64rem}.max-w-6xl{max-inline-size:72rem}.max-w-7xl{max-inline-size:80rem}.max-w-full{max-inline-size:100%}.max-w-none{max-inline-size:none}.max-w-prose{max-inline-size:var(--w)}.hidden{display:none}.badge{border:1px solid var(--bd);border-radius:calc(infinity * 1px);background:var(--face);padding:.1em .6em;font:700 var(--caps);color:var(--mut)}.card>:is(header,footer){margin-inline:-.9rem;padding:.55rem .9rem;background:var(--face)}.card>header{margin-top:-.9rem;font-weight:700;border-bottom:1px solid var(--bd);border-radius:var(--r) var(--r) 0 0}.card>footer{margin-top:auto;margin-bottom:-.9rem;color:var(--mut);font-size:.85em;border-top:1px solid var(--bd);border-radius:0 0 var(--r) var(--r)}.card>:is(img,video):first-child{align-self:stretch;width:auto;max-width:none;margin:-.9rem -.9rem 0;aspect-ratio:16 / 9;object-fit:cover;border:0;border-radius:var(--r) var(--r) 0 0;box-shadow:none}.card[data-tone]{box-shadow:var(--up2),inset 0 2px 0 var(--ac)}.card[data-tone]>header:first-child{box-shadow:inset 0 2px 0 var(--ac)}:is(a,button).card{display:flex;width:100%;text-align:start;color:inherit;text-decoration:none;font:inherit}:is(a,button).card:hover:not(:disabled){border-color:color-mix(in srgb,var(--ac) 45%,var(--bd));box-shadow:var(--up2),0 12px 26px -14px oklch(from var(--sh) l c h / .4);translate:0 -2px}:is(a,button).card:active:not(:disabled){translate:0 0}[hidden]:not([hidden=until-found]){display:none}@media (prefers-reduced-motion:no-preference) and (update:fast){html{scroll-behavior:smooth}}:target{scroll-margin-top:4rem}:is(h1,h2,h3,h4):target{background:color-mix(in srgb,var(--ac) 12%,transparent)}a[target=_blank]::after{content:" ↗";font-size:.85em;opacity:.6}a:has(>img),a:has(>code){text-decoration:none}sup,sub{line-height:0;font-size:.75em}q{quotes:"“" "”" "‘" "’"}dfn{font-style:normal;font-weight:700}ins{text-decoration:underline;text-decoration-style:wavy;text-decoration-color:var(--ac)}del{color:var(--mut)}address{font-style:normal;color:var(--mut)}hgroup>*{margin:0}hgroup>p{color:var(--mut)}output{font-weight:700}meter{width:100%;height:.5rem}optgroup{font-weight:700;color:var(--mut)}::file-selector-button{margin-inline-end:.8em}::file-selector-button:hover{background:var(--face)}input:user-invalid,textarea:user-invalid{border-color:light-dark(#c0392b,#ff6b6b)}input:user-invalid + small{color:light-dark(#c0392b,#ff6b6b)}summary:hover{color:var(--ac)}*{scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--fg) 25%,transparent) transparent}@page{margin:2cm}@media print{:root{--bg:#fff;--el:#fff;--fg:#000;--bd:#999}body>nav,body>footer{display:none}body>*{border:0;max-width:none}p,blockquote,li{orphans:3;widows:3}a[href^="http"]::after{content:" (" attr(href) ")";font-size:.8em;color:#555}pre,table,figure,details,tr,img{break-inside:avoid}h1,h2,h3,h4{break-after:avoid}}@media (pointer:coarse){button,[type=submit],[type=button],[type=reset],:where(a.primary,a[role=button]),select,summary,input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file]){min-height:44px}input[type=checkbox],input[type=radio]{width:1.4em;height:1.4em}}@media (inverted-colors:inverted){img,video,iframe{filter:invert(1) hue-rotate(180deg)}}@media (color-gamut:p3){@supports (color:oklch(60% .2 250)){:root{--ac:light-dark(oklch(52% .21 258),oklch(76% .15 258))}}}:root{text-spacing-trim:trim-start;text-autospace:normal}@media (prefers-reduced-transparency:reduce){body>nav{background:var(--face);backdrop-filter:none}dialog::backdrop{backdrop-filter:none}}@media (prefers-contrast:more){:root{--bd:light-dark(#00000059,#ffffff6b);--mut:light-dark(#45454a,#c6c6ce)}}@media (prefers-reduced-motion:no-preference) and (update:fast){a,button,input,select,textarea,summary,tr,[type=submit],[type=button],[type=reset]{transition:box-shadow .15s,background-color .15s,border-color .15s,translate .08s}}}@layer fertig-a11y{@media (forced-colors:active){*{box-shadow:none}button,[type=submit],[type=button],[type=reset],input,select,textarea,.card,.badge,details,dialog,[popover],fieldset,table{border:1px solid CanvasText}[role=tab][aria-selected=true],button[aria-pressed=true]{border-color:Highlight}}}