fertig 4.0.2 → 4.0.4
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 +39 -436
- package/fertig.css +10 -2
- package/fertig.min.css +1 -1
- package/package.json +6 -7
- package/CHANGELOG.md +0 -470
package/README.md
CHANGED
|
@@ -1,473 +1,76 @@
|
|
|
1
1
|
# fertig
|
|
2
2
|
|
|
3
|
-
[](https://bundlephobia.com/package/fertig)
|
|
4
|
+
[](https://bundlephobia.com/package/fertig)
|
|
5
5
|
|
|
6
|
-
A classless CSS
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
JavaScript switched off.
|
|
6
|
+
A classless CSS framework for finished interfaces. Link one file and write
|
|
7
|
+
semantic HTML; fertig styles the page, forms, tables, dialogs, popovers,
|
|
8
|
+
navigation, feedback, and common layout patterns.
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
**36.7 KB raw · 8.6 KB gzipped · no build step · no dependencies · no JavaScript.**
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
### What makes it different
|
|
16
|
-
|
|
17
|
-
Surveyed across the eleven most-used classless stylesheets on 2026-08-31
|
|
18
|
-
([working notes](docs/classless-landscape-2026.md)):
|
|
19
|
-
|
|
20
|
-
- **Components addressed by ARIA.** Only one other classless sheet ships a
|
|
21
|
-
single ARIA-addressed component. None ships tabs, a segmented control, or an
|
|
22
|
-
anchored popover menu.
|
|
23
|
-
- **Behaviour without JavaScript.** Others style `<dialog>` and leave the open
|
|
24
|
-
and close to you. Here `popover`, `command` and anchor positioning do it —
|
|
25
|
-
[audited with scripting disabled](#components-that-work-without-javascript).
|
|
26
|
-
- **Modern CSS.** Zero of the eleven use `oklch()`, `light-dark()`, `@layer`,
|
|
27
|
-
`@property`, container queries or anchor positioning. This sheet uses all of
|
|
28
|
-
them.
|
|
29
|
-
- **Cascade-layered.** It lives in `@layer fertig`, so your own unlayered CSS
|
|
30
|
-
wins at any specificity and overriding never needs `!important`. No other
|
|
31
|
-
classless sheet does this.
|
|
32
|
-
- **RTL by construction.** Written in logical properties throughout, not
|
|
33
|
-
patched with `[dir=rtl]` overrides afterwards.
|
|
34
|
-
|
|
35
|
-
`fertig.min.css` is 8.6 KB gzipped. That includes semantic element styling,
|
|
36
|
-
the component layer, responsive utilities, light and dark themes, RTL support
|
|
37
|
-
and accessibility safeguards. Size is a constraint here, not the pitch.
|
|
38
|
-
|
|
39
|
-
## Components that work without JavaScript
|
|
40
|
-
|
|
41
|
-
Audited in a browser with scripting disabled:
|
|
42
|
-
|
|
43
|
-
| | |
|
|
44
|
-
|---|---|
|
|
45
|
-
| Popover menu, dialog, drawer, toast, tooltip, disclosure | **work with no script** |
|
|
46
|
-
| Tabs | **styled only** — selection, panels and arrow keys need a short script |
|
|
47
|
-
|
|
48
|
-
This gap is deliberate: `aria-selected` must be a real attribute, inactive tabs
|
|
49
|
-
need roving focus, and CSS cannot implement the arrow-key contract. The complete
|
|
50
|
-
enhancement is in the docs. `<details name>` remains an exclusive accordion,
|
|
51
|
-
not a tabs substitute.
|
|
52
|
-
|
|
53
|
-
```html
|
|
54
|
-
<link rel="stylesheet" href="fertig.css">
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
That is the whole integration. Write semantic HTML; it looks finished.
|
|
58
|
-
Open the [live site](https://moji2002.github.io/fertig/) for the full demo.
|
|
59
|
-
|
|
60
|
-
## Upgrading from 2.x
|
|
61
|
-
|
|
62
|
-
3.0 is breaking for one reason: **every public token now carries a `--fertig-`
|
|
63
|
-
prefix**, and the old names are gone — no aliases. The classes, the ARIA
|
|
64
|
-
attributes the components read, and the layout utilities are all unchanged.
|
|
65
|
-
The sheet's behaviour is the same; the migration is a rename.
|
|
66
|
-
|
|
67
|
-
If you override tokens, prefix what you set. The common ones:
|
|
68
|
-
|
|
69
|
-
| 2.x | 3.0 |
|
|
70
|
-
|---|---|
|
|
71
|
-
| `--ac` | `--fertig-ac` |
|
|
72
|
-
| `--on-ac` | `--fertig-on-ac` |
|
|
73
|
-
| `--w` / `--g` | `--fertig-w` / `--fertig-g` |
|
|
74
|
-
| `--r` / `--rs` / `--rw` | `--fertig-r` / `--fertig-rs` / `--fertig-rw` |
|
|
75
|
-
| `--bg` / `--el` / `--face` / `--fg` / `--mut` / `--bd` / `--tb` | `--fertig-*` (same short name) |
|
|
76
|
-
| `--up` / `--up2` / `--dn` / `--sh` / `--sh1` / `--sh2` | `--fertig-up` / `--fertig-up2` / `--fertig-dn` / `--fertig-sh` / `--fertig-sh1` / `--fertig-sh2` |
|
|
77
|
-
| fonts `--f` / `--fm`, page width `--w`, gutter `--g`, caps `--caps`, `--nw` | `--fertig-*` |
|
|
78
|
-
| color ramps `--stone-*` / `--sage-*` / `--sky-*` / `--clay-*` / `--plum-*` / `--gold-*` | `--fertig-*` (same stop) |
|
|
79
|
-
|
|
80
|
-
The rule is simple: **any `--name` you set becomes `--fertig-name`.** Nothing
|
|
81
|
-
changed meaning; the prefix exists so the sheet never collides with a custom
|
|
82
|
-
property of yours (it is the same reason `--fertig-a1` / `--fertig-a2` were
|
|
83
|
-
already prefixed — those are `@property` registrations, which are global).
|
|
84
|
-
|
|
85
|
-
The defaults now favor a platform-neutral interface:
|
|
86
|
-
|
|
87
|
-
- **Palette.** Accents and neutrals moved to a cooler voice — graphite
|
|
88
|
-
neutrals and a violet-blue accent — replacing the older indigo/warm scheme.
|
|
89
|
-
- **Geometry.** Buttons share the restrained control radius. Pill geometry is
|
|
90
|
-
reserved for badges, switches, meters and joined ends.
|
|
91
|
-
|
|
92
|
-
The docs site was also rebuilt and the two demo pages (`app.html` /
|
|
93
|
-
`app-invoice.html`) are gone. None of that touches the sheet.
|
|
94
|
-
|
|
95
|
-
## Install
|
|
12
|
+
## Use
|
|
96
13
|
|
|
97
14
|
```sh
|
|
98
15
|
npm install fertig
|
|
99
16
|
```
|
|
100
17
|
|
|
101
|
-
```html
|
|
102
|
-
<!-- or from a CDN, pinned -->
|
|
103
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fertig@4/fertig.min.css">
|
|
104
|
-
```
|
|
105
|
-
|
|
106
18
|
```css
|
|
107
|
-
/* or through a bundler */
|
|
108
19
|
@import "fertig";
|
|
109
20
|
```
|
|
110
21
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Opinions, so you don't have to have them: system type, one accent, one page
|
|
114
|
-
width and a clear content canvas. The structure is classic — a toolbar,
|
|
115
|
-
sunken fields and flat buttons — while the finish stays platform-neutral:
|
|
116
|
-
opaque surfaces, hairlines, restrained corners and a violet-blue focus ring
|
|
117
|
-
over cool graphite neutrals.
|
|
118
|
-
|
|
119
|
-
- **System type, set properly** — 16px on a 1.65 line height. Long-form copy
|
|
120
|
-
gets a roughly seventy-character measure with `.max-w-prose`. Code keeps a
|
|
121
|
-
monospace face, where it earns its place.
|
|
122
|
-
- **A centered content canvas.** `<nav>` becomes a full-bleed opaque toolbar;
|
|
123
|
-
`header`/`main`/`footer` form the page surface.
|
|
124
|
-
- **Depth from hairlines and soft shadows.** Cards sit above the page while
|
|
125
|
-
buttons stay flat and inputs and code sit below it. Shadow alphas step up in dark mode,
|
|
126
|
-
because a shadow on a dark background does nothing on its own.
|
|
127
|
-
- **Quiet text.** Links underline on hover rather than inverting mid-paragraph.
|
|
128
|
-
- **Comfortable foregrounds.** Light mode uses graphite rather than absolute
|
|
129
|
-
black; dark mode uses a softened near-white rather than full white.
|
|
130
|
-
- **Dark mode with no second stylesheet.** One `light-dark()` token block.
|
|
131
|
-
Add `data-theme="dark"` (or `"light"`) on `<html>` to override the OS.
|
|
132
|
-
|
|
133
|
-
## Layout
|
|
134
|
-
|
|
135
|
-
Direct children of `<body>` are full-width containers with responsive page
|
|
136
|
-
gutters:
|
|
22
|
+
Or use the CDN:
|
|
137
23
|
|
|
138
24
|
```html
|
|
139
|
-
<
|
|
140
|
-
<nav>…</nav> <!-- toolbar: full-bleed, contents on the page column -->
|
|
141
|
-
<header>…</header>
|
|
142
|
-
<main>…</main>
|
|
143
|
-
<footer>…</footer>
|
|
144
|
-
</body>
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
There is no default maximum width on body-level containers. Add
|
|
148
|
-
`.max-w-prose` to long-form content for a readable `38rem` line length, or use
|
|
149
|
-
the `max-w-*` utilities when a page needs a specific measure. The
|
|
150
|
-
`--fertig-g` gutter scales from `1.15rem` on narrow phones to `1.9rem` on
|
|
151
|
-
larger screens.
|
|
152
|
-
|
|
153
|
-
One wrapper is fine. React, Vue, Svelte and Next render into a mount node, so
|
|
154
|
-
the shell matches `body`'s children *or* the children of a single `#root`,
|
|
155
|
-
`#app`, `#__next`, or `[data-fertig]` wrapper:
|
|
156
|
-
|
|
157
|
-
```html
|
|
158
|
-
<body>
|
|
159
|
-
<div id="root">
|
|
160
|
-
<nav>…</nav>
|
|
161
|
-
<main>…</main>
|
|
162
|
-
</div>
|
|
163
|
-
</body>
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Deeper than that, or a differently named mount node, and you re-point the shell
|
|
167
|
-
yourself — it is the only place `body >` appears:
|
|
168
|
-
|
|
169
|
-
```css
|
|
170
|
-
#shell > *, #shell > header, #shell > main, #shell > footer { /* … */ }
|
|
25
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fertig@4/fertig.min.css">
|
|
171
26
|
```
|
|
172
27
|
|
|
173
|
-
|
|
28
|
+
That is the complete setup. See the [documentation](https://moji2002.github.io/fertig/docs.html),
|
|
29
|
+
[component catalogue](https://moji2002.github.io/fertig/components.html), and
|
|
30
|
+
[copy-paste blocks](https://moji2002.github.io/fertig/blocks.html).
|
|
174
31
|
|
|
175
|
-
|
|
176
|
-
markup stays accessible by construction.
|
|
32
|
+
## What it includes
|
|
177
33
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
| Loading | `aria-busy="true"` (inline spinner) |
|
|
187
|
-
| Tooltip | `data-tooltip="…"` — decorative; put the same words in `aria-label` too |
|
|
188
|
-
| Button variants | `data-variant="ghost\|link"`, `data-size="sm\|lg"`, `data-icon`, `data-block` — on controls only, so they cannot catch a `<span data-size>` of yours |
|
|
189
|
-
| Card anatomy | `<header>` / `<footer>` inside `.card`; `<a class="card">` lifts on hover |
|
|
190
|
-
| Tones | `data-tone="ok\|warn\|err"` retints any component |
|
|
34
|
+
- Light and dark themes through `light-dark()`
|
|
35
|
+
- Accessible forms, tables, cards, alerts, tabs, menus, dialogs, drawers,
|
|
36
|
+
toasts, tooltips, skeletons, and more
|
|
37
|
+
- Native no-JavaScript behavior for popovers, dialogs, drawers, disclosures,
|
|
38
|
+
toasts, and tooltips
|
|
39
|
+
- Logical properties for RTL layouts
|
|
40
|
+
- OKLCH color ramps and WCAG AA semantic pairs
|
|
41
|
+
- A cascade layer, so unlayered project CSS overrides fertig cleanly
|
|
191
42
|
|
|
192
|
-
|
|
193
|
-
|
|
43
|
+
Seven component classes are optional: `.row`, `.grid`, `.card`, `.badge`,
|
|
44
|
+
`.muted`, `.center`, and `.wide`. Layout utilities are available when semantic
|
|
45
|
+
HTML alone cannot express the layout.
|
|
194
46
|
|
|
195
|
-
|
|
196
|
-
|---|---|
|
|
197
|
-
| Avatar | `data-avatar` on an `<img>` or on initials in a `<span>`; `="sm\|lg"` |
|
|
198
|
-
| Skeleton | `data-skeleton` on the element that is still loading |
|
|
199
|
-
| Sheet / drawer | `<dialog data-side="left\|right\|bottom">` — the same dialog, docked to an edge |
|
|
200
|
-
| Toast | `[popover][data-toast]` — non-modal, parked in a corner. Several at once: `<div popover="manual" data-toast-region>` with a `<div data-toast>` per message |
|
|
201
|
-
| List group | a plain `<menu>` outside a popover becomes a bordered list |
|
|
202
|
-
| Nav menu | a `<menu>` inside a `<nav>` is navigation instead — no rules, no bullets, `aria-current` marks the page |
|
|
203
|
-
| Sidebar layout | `data-layout="sidebar"` on a wrapper of two children; the first sticks |
|
|
204
|
-
| Carousel | `data-carousel` — scroll snapping, with real scroll buttons where they exist |
|
|
47
|
+
## Customize
|
|
205
48
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
`.row` `.grid` `.card` `.badge` `.muted` `.center` `.wide`
|
|
209
|
-
|
|
210
|
-
Plus `.primary` on a button — though `type="submit"` already gets it.
|
|
211
|
-
|
|
212
|
-
## Layout utilities
|
|
213
|
-
|
|
214
|
-
A compact set of predictable layout helpers covers common flex, grid,
|
|
215
|
-
alignment, gap, margin, width and visibility needs.
|
|
216
|
-
|
|
217
|
-
```
|
|
218
|
-
.flex .flex-col .flex-wrap .flex-1
|
|
219
|
-
.grid-cols-2 .grid-cols-3 .grid-cols-4
|
|
220
|
-
.items-start .items-center .items-end
|
|
221
|
-
.justify-start .justify-center .justify-end .justify-between
|
|
222
|
-
.gap-0 .gap-1 .gap-2 .gap-3 .gap-4 .gap-6 (0 · .25 · .5 · .75 · 1 · 1.5rem)
|
|
223
|
-
.mx-auto .ms-auto .me-auto .w-full .hidden
|
|
224
|
-
.max-w-xs .max-w-sm .max-w-md .max-w-lg .max-w-xl (20 · 24 · 28 · 32 · 36rem)
|
|
225
|
-
.max-w-2xl .max-w-3xl .max-w-4xl .max-w-5xl .max-w-6xl .max-w-7xl (42 · 48 · 56 · 64 · 72 · 80rem)
|
|
226
|
-
.max-w-full .max-w-none .max-w-prose
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
Layout and width only. No colour or type scale, and no responsive
|
|
230
|
-
variants — those need a build step, and this file does not have one. The
|
|
231
|
-
margins are flow-relative (`ms`/`me`, not `ml`/`mr`), so a toolbar still lands
|
|
232
|
-
correctly in Persian or Arabic. `.grid` is fertig's own auto-fit grid;
|
|
233
|
-
adding `.grid-cols-3` pins it to three columns.
|
|
234
|
-
|
|
235
|
-
The `max-w-*` scale is complete rather than partial — a half-scale where
|
|
236
|
-
`.max-w-2xl` works and `.max-w-3xl` silently does not is worse than no scale
|
|
237
|
-
at all. They are `max-inline-size`, so they still mean "along the text"
|
|
238
|
-
in a vertical writing mode and can constrain a page container as readily as
|
|
239
|
-
anything inside one. `.max-w-prose` is a fixed `38rem` reading measure.
|
|
240
|
-
|
|
241
|
-
## Customising
|
|
242
|
-
|
|
243
|
-
Override the tokens you'd actually want to change:
|
|
49
|
+
Override tokens in your own CSS:
|
|
244
50
|
|
|
245
51
|
```css
|
|
246
52
|
:root {
|
|
247
|
-
--fertig-ac:
|
|
248
|
-
--fertig-
|
|
249
|
-
--fertig-
|
|
250
|
-
--fertig-r: 0px; /* control radius — go sharp */
|
|
251
|
-
--fertig-f: "Inter", system-ui, sans-serif; /* text font */
|
|
53
|
+
--fertig-ac: oklch(52% 0.18 270);
|
|
54
|
+
--fertig-r: 10px;
|
|
55
|
+
--fertig-w: 72rem;
|
|
252
56
|
}
|
|
253
57
|
```
|
|
254
58
|
|
|
255
|
-
The accent is the only colour most people touch. The default is blue sitting
|
|
256
|
-
on cool gray neutrals; the
|
|
257
|
-
`data-accent` attribute retints a whole region without touching tokens:
|
|
258
|
-
|
|
259
|
-
```html
|
|
260
|
-
<section data-accent="green">…</section> <!-- or blue, cyan, amber, red, violet, gray -->
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
The palette exposes `gray`, `blue`, `cyan`, `green`, `amber`, `red` and
|
|
264
|
-
`violet` ramps at `100`, `300`, `500`, `700` and `900`. For example,
|
|
265
|
-
`--fertig-violet-500` is the middle violet stop. The former
|
|
266
|
-
`stone/sage/sky/clay/plum/gold` ramps and named accents were removed rather
|
|
267
|
-
than retained as aliases.
|
|
268
|
-
|
|
269
|
-
Tones work the same way — `data-tone="ok|warn|err"` retints any component
|
|
270
|
-
without a round trip through the tokens:
|
|
271
|
-
|
|
272
|
-
```html
|
|
273
|
-
<button data-tone="err">Delete</button>
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
If you change `--fertig-ac`, check `--fertig-on-ac` too — that is the text
|
|
277
|
-
colour sitting on the accent, and a light accent needs dark text to stay
|
|
278
|
-
legible. `--fertig-up` / `--fertig-up2` / `--fertig-dn` are the elevation
|
|
279
|
-
scale, `--fertig-a1` / `--fertig-a2` the shadow alphas (these two are
|
|
280
|
-
`@property` registrations, and a registration is global — hence the prefix),
|
|
281
|
-
`--fertig-rw` the large-surface radius, and `--fertig-nw` the column the toolbar's
|
|
282
|
-
contents line up with. `--fertig-nw` follows `--fertig-w`, so nothing moves by
|
|
283
|
-
default; `<nav class="wide">` re-points it at the wide column, which is what an
|
|
284
|
-
app screen built on `.wide` wants so its wordmark doesn't float in the middle
|
|
285
|
-
of the viewport.
|
|
286
|
-
|
|
287
|
-
## Also handled
|
|
288
|
-
|
|
289
|
-
`:target`, external-link arrows, `user-invalid` fields, a CSS-drawn select
|
|
290
|
-
chevron, thin scrollbars, `sup`/`sub` that don't stretch lines, `q`/`dfn`/
|
|
291
|
-
`ins`/`del`/`address`/`meter`/`output`/`optgroup`/`hgroup`, print styles, and
|
|
292
|
-
`prefers-reduced-motion`.
|
|
293
|
-
|
|
294
|
-
## Right-to-left
|
|
295
|
-
|
|
296
|
-
Every inline-direction rule is flow-relative — `padding-inline-start`,
|
|
297
|
-
`border-inline-start`, `margin-inline-end`, `text-align: start`,
|
|
298
|
-
`border-start-end-radius` — so `dir="rtl"` mirrors the sheet with nothing to
|
|
299
|
-
configure:
|
|
300
|
-
|
|
301
|
-
```html
|
|
302
|
-
<html lang="fa" dir="rtl">
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
List markers, blockquote and `<aside>` accent bars, table gutters, breadcrumb
|
|
306
|
-
separators, the segmented control's rounded ends, the `<select>` chevron and
|
|
307
|
-
the switch knob all move to the correct side. Two of those cannot be expressed
|
|
308
|
-
logically — `translate` and a background position — and carry `:dir(rtl)`
|
|
309
|
-
rules instead. The layout utilities follow the same rule: `.ms-auto` and
|
|
310
|
-
`.me-auto` exist, `.ml-auto` deliberately does not.
|
|
311
|
-
|
|
312
|
-
Tested by rendering a Persian page in both directions, not by inspection.
|
|
313
|
-
|
|
314
|
-
## Accessibility
|
|
315
|
-
|
|
316
|
-
Every foreground/background pair meets WCAG 2.1 AA (>= 4.5:1) in **both**
|
|
317
|
-
themes, calculated from the computed token values:
|
|
318
|
-
|
|
319
|
-
| Pair | Light | Dark |
|
|
320
|
-
|---|---:|---:|
|
|
321
|
-
| Body text on content surface | 16.83 | 15.32 |
|
|
322
|
-
| Muted text on content surface | 6.92 | 7.15 |
|
|
323
|
-
| Links on content surface | 6.72 | 9.50 |
|
|
324
|
-
| Muted on controls | 6.57 | 6.45 |
|
|
325
|
-
| Muted on page ground | 5.89 | 7.88 |
|
|
326
|
-
| Text on accent | 6.16 | 11.22 |
|
|
327
|
-
| Tones (ok / warn / err) | 5.91–7.17 | 9.12–10.76 |
|
|
328
|
-
|
|
329
|
-
The tightest pair in the sheet is text on the amber fill in light mode, at
|
|
330
|
-
5.41:1.
|
|
331
|
-
|
|
332
|
-
Motion is gated behind `prefers-reduced-motion`, focus uses a visible ring at
|
|
333
|
-
`:focus-visible`, and the component layer is driven by the same ARIA attributes
|
|
334
|
-
assistive technology reads.
|
|
335
|
-
|
|
336
|
-
## Size
|
|
337
|
-
|
|
338
|
-
| File | Raw | Gzip |
|
|
339
|
-
|---|---:|---:|
|
|
340
|
-
| **fertig.min.css** | **36.6 KB** | **8.6 KB** |
|
|
341
|
-
|
|
342
|
-
Measured with `gzip -9`; KB = 1024 bytes.
|
|
343
|
-
|
|
344
|
-
## Overriding it
|
|
345
|
-
|
|
346
|
-
The sheet declares two layers, `@layer fertig, fertig-a11y` — the second holds
|
|
347
|
-
the forced-colors block so it can beat a `.card` shadow on layer order instead
|
|
348
|
-
of `!important`. Anything you write outside a layer beats both whatever the
|
|
349
|
-
specificity, so overriding is never a fight:
|
|
350
|
-
|
|
351
|
-
```css
|
|
352
|
-
button { background: hotpink } /* wins, no !important needed */
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
## Modern CSS, used deliberately
|
|
356
|
-
|
|
357
|
-
Everything past the floor sits behind `@supports` and is additive:
|
|
358
|
-
`contrast-color()` picks the light or dark text colour on your accent and a
|
|
359
|
-
small mix keeps it away from absolute black or white; anchor positioning
|
|
360
|
-
attaches popover menus to their button;
|
|
361
|
-
`::details-content` with `interpolate-size` animates disclosures open;
|
|
362
|
-
`field-sizing` grows textareas; `text-box: trim-both` sits headings on their
|
|
363
|
-
cap height; and
|
|
364
|
-
`appearance: base-select` styles the dropdown picker itself. Without any of it,
|
|
365
|
-
nothing breaks. Relative colour (`oklch(from …)`) is on that list too, for one
|
|
366
|
-
job only: lightening the filled button on hover in OKLCH. The shadow alphas
|
|
367
|
-
that used to need it are taken with `color-mix` against `transparent` instead —
|
|
368
|
-
pixel-identical, and three years older, which is what keeps Safari 17.5 inside
|
|
369
|
-
the floor. Two things are *not* on the list because they are part of the floor:
|
|
370
|
-
`@property`, which types the shadow alphas so elevation can transition, and
|
|
371
|
-
`container-type` on `.card`, which makes every card a container you can write
|
|
372
|
-
`@container` queries against.
|
|
373
|
-
|
|
374
|
-
It also answers to user and device preferences: `prefers-reduced-motion`,
|
|
375
|
-
`prefers-contrast`, `forced-colors`,
|
|
376
|
-
`pointer: coarse` (44px targets, WCAG 2.5.8), `env(safe-area-inset-*)`,
|
|
377
|
-
`update: fast` (e-ink never starts a transition), `inverted-colors` and
|
|
378
|
-
`color-gamut: p3`.
|
|
379
|
-
|
|
380
|
-
And it survives content it has never seen: a pasted URL wraps instead of
|
|
381
|
-
widening the page, tables scroll themselves on a phone, autofilled fields are
|
|
382
|
-
repainted so the browser yellow never shows, required and read-only fields
|
|
383
|
-
read correctly, numerals are slashed and tabular, and print gets real page
|
|
384
|
-
margins with no stranded lines.
|
|
385
|
-
|
|
386
|
-
## Browser support
|
|
387
|
-
|
|
388
|
-
The two-year window is on *browsers*, not on CSS. fertig runs in anything
|
|
389
|
-
released since August 2024. The CSS it uses is mostly older than that:
|
|
390
|
-
`@layer` has been cross-engine since 2022, `oklch()` and `color-mix()` since
|
|
391
|
-
2023, `light-dark()` since May 2024. The newest thing it *requires* is
|
|
392
|
-
`@starting-style`, cross-engine since August 2024 — nothing it needs shipped
|
|
393
|
-
inside the last two years.
|
|
394
|
-
|
|
395
|
-
It carries almost nothing for the browsers before that: no polyfills, no
|
|
396
|
-
fallback build, and no vendor prefixes beyond the three no engine has replaced
|
|
397
|
-
(`-webkit-text-size-adjust`, the `-webkit-text-fill-color` autofill repaint,
|
|
398
|
-
and the `progress` pseudo-elements). The one concession is a `@supports not
|
|
399
|
-
(color: light-dark(…))` block restating the palette in flat sRGB — without it
|
|
400
|
-
an engine that lacks `light-dark()` gets invalid colour tokens and lands
|
|
401
|
-
unreadable rather than plain.
|
|
402
|
-
|
|
403
|
-
| Engine | Minimum | Set by |
|
|
404
|
-
|---|---|---|
|
|
405
|
-
| Chrome / Edge | **123** | `light-dark()` |
|
|
406
|
-
| Safari | **17.5** | `light-dark()`, `@starting-style`, `text-wrap: balance` |
|
|
407
|
-
| Firefox | **129** | `@starting-style`, `transition-behavior` |
|
|
408
|
-
|
|
409
|
-
No component needs more than that floor — anything a component would *like* to
|
|
410
|
-
have it asks for through `@supports`. Anchor positioning, for instance, is
|
|
411
|
-
gated; without it `[popover]` menus centre on screen instead of sitting under
|
|
412
|
-
their button. Below the floor everything degrades to unstyled-but-readable
|
|
413
|
-
HTML.
|
|
414
|
-
|
|
415
|
-
Per-component and per-enhancement version tables, with the shipping dates
|
|
416
|
-
behind them, are in [`docs/browser-support-research.md`](docs/browser-support-research.md)
|
|
417
|
-
and on the [docs site](https://moji2002.github.io/fertig/docs.html#support).
|
|
418
|
-
|
|
419
59
|
## Development
|
|
420
60
|
|
|
421
61
|
```sh
|
|
422
|
-
npm
|
|
423
|
-
npm run
|
|
424
|
-
npm
|
|
425
|
-
npm run site
|
|
426
|
-
npm run site:serve
|
|
427
|
-
npm run
|
|
62
|
+
npm install
|
|
63
|
+
npm run build # regenerate fertig.min.css
|
|
64
|
+
npm test # library and site tests
|
|
65
|
+
npm run site # Astro production build
|
|
66
|
+
npm run site:serve # Astro development server
|
|
67
|
+
npm run check # complete release check
|
|
428
68
|
```
|
|
429
69
|
|
|
430
|
-
The
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
package contents. If a generated file or size claim is stale, run the command
|
|
434
|
-
named by the failure, review the diff, and commit it deliberately.
|
|
435
|
-
Tracked changes must be fully staged, preventing an unstaged fix from hiding a
|
|
436
|
-
broken staged snapshot during validation.
|
|
437
|
-
|
|
438
|
-
## Builds
|
|
439
|
-
|
|
440
|
-
| Build | Raw | Gzip | |
|
|
441
|
-
|---|---:|---:|---|
|
|
442
|
-
| `fertig.min.css` | 36.6 KB | 8.6 KB | everything |
|
|
443
|
-
|
|
444
|
-
## Files
|
|
445
|
-
|
|
446
|
-
The sheet:
|
|
447
|
-
|
|
448
|
-
- `fertig.css` — source, commented
|
|
449
|
-
- `fertig.min.css` — minified, what you ship
|
|
450
|
-
- `build.js` — minifier and size report
|
|
451
|
-
|
|
452
|
-
The site (Eleventy, output to `dist/`):
|
|
453
|
-
|
|
454
|
-
- `src/_includes/layout.njk` — shared document shell and navigation
|
|
455
|
-
- `src/_includes/{page-header,footer}.njk` — shared inner-page header and footer
|
|
456
|
-
- `src/_data/site.js` — version pulled from `package.json` (the one source of truth)
|
|
457
|
-
- `src/{index,docs,components,blocks}.njk` — the only authored page sources
|
|
458
|
-
- `site.css`, `site.js`, `icons.svg`, `favicon.svg` — the site's own chrome,
|
|
459
|
-
none of it part of the sheet
|
|
460
|
-
- `dist/` — the built site that GitHub Pages deploys
|
|
461
|
-
|
|
462
|
-
Everything else:
|
|
463
|
-
|
|
464
|
-
- `llms.txt` — machine-readable summary for LLMs, per llmstxt.org
|
|
465
|
-
- `CHANGELOG.md` — what changed and why, per release
|
|
466
|
-
- `docs/classless-css-research.md` — the research behind the decisions
|
|
467
|
-
|
|
468
|
-
The sheet itself ships without the site — the npm package holds the two CSS
|
|
469
|
-
files plus the README and licence, nothing else.
|
|
70
|
+
The package publishes only `fertig.css`, `fertig.min.css`, this README, and the
|
|
71
|
+
MIT license. The Astro site lives in `src/pages`, with its shared shell in
|
|
72
|
+
`src/layouts` and `src/components`.
|
|
470
73
|
|
|
471
74
|
## License
|
|
472
75
|
|
|
473
|
-
MIT
|
|
76
|
+
MIT
|
package/fertig.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! fertig v4.0.
|
|
1
|
+
/*! fertig v4.0.4 — a classless CSS stylesheet. MIT */
|
|
2
2
|
|
|
3
3
|
/* Opinions, so you don't have to have them:
|
|
4
4
|
system type · one accent · responsive gutters · a clear content canvas.
|
|
@@ -476,6 +476,12 @@ button, [type=submit], [type=button], [type=reset],
|
|
|
476
476
|
}
|
|
477
477
|
:is(button,[type=submit],[type=button],[type=reset],a.primary,a[role=button]):hover:not(:disabled) { background: var(--fertig-face) }
|
|
478
478
|
[type=submit], .primary { background: var(--fertig-ac); border-color: transparent; color: var(--fertig-on-ac) }
|
|
479
|
+
/* Filled controls must not keep their enabled accent after :disabled. This
|
|
480
|
+
follows the filled rule deliberately: equal-specificity declarations later
|
|
481
|
+
in the cascade restore the quiet control surface and muted text. */
|
|
482
|
+
:is(button,[type=submit],[type=button],[type=reset]):disabled {
|
|
483
|
+
background: var(--fertig-face); border-color: var(--fertig-bd); color: var(--fertig-mut);
|
|
484
|
+
}
|
|
479
485
|
/* The filled button lightens on hover. color-mix does that in oklab, which is
|
|
480
486
|
close enough and is Baseline; relative colour does it by adding to L
|
|
481
487
|
directly, which holds the hue exactly when --fertig-ac is a wide-gamut override.
|
|
@@ -900,7 +906,9 @@ nav menu :is(a, button)[aria-current] {
|
|
|
900
906
|
/* on the toolbar .wide cannot mean "be 80rem wide" — the bar stays full-bleed
|
|
901
907
|
and its contents move out to the wide column, so an app screen's wordmark
|
|
902
908
|
lines up with the app's own content rather than floating mid-screen. */
|
|
903
|
-
:is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav.wide {
|
|
909
|
+
:is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav.wide {
|
|
910
|
+
max-width: none; --fertig-nw: 80rem;
|
|
911
|
+
}
|
|
904
912
|
.row { display: flex; flex-wrap: wrap; gap: .7rem; align-items: center }
|
|
905
913
|
/* Form controls are full-width blocks by default, which is right in a form and
|
|
906
914
|
wrong in a toolbar. Inside a .row they size to the row instead. */
|
package/fertig.min.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
/*! fertig v4.0.2 — a classless CSS stylesheet. MIT */@property --fertig-a1{syntax:"<number>";inherits:true;initial-value:.06}@property --fertig-a2{syntax:"<number>";inherits:true;initial-value:.05}@layer fertig,fertig-a11y;@layer fertig{:root{color-scheme:light dark;accent-color:var(--fertig-ac);caret-color:var(--fertig-ac);--fertig-f:ui-sans-serif,system-ui,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--fertig-fm:ui-monospace,"Cascadia Code","Roboto Mono",Consolas,"Liberation Mono",monospace;--fertig-w:72rem;--fertig-g:clamp(1.15rem,4vw,1.9rem);--fertig-r:8px;--fertig-rs:calc(var(--fertig-r) * .5);--fertig-rw:calc(var(--fertig-r) * 1.33);--fertig-rp:calc(var(--fertig-r) * 1000);--fertig-gray-100:oklch(97% .005 260);--fertig-gray-300:oklch(82% .01 260);--fertig-gray-500:oklch(62% .014 260);--fertig-gray-700:oklch(47% .015 260);--fertig-gray-900:oklch(25% .018 260);--fertig-blue-100:oklch(96% .018 255);--fertig-blue-300:oklch(80% .095 255);--fertig-blue-500:oklch(62% .16 255);--fertig-blue-700:oklch(47% .15 255);--fertig-blue-900:oklch(29% .09 255);--fertig-cyan-100:oklch(96% .025 210);--fertig-cyan-300:oklch(82% .085 210);--fertig-cyan-500:oklch(64% .11 210);--fertig-cyan-700:oklch(47% .08 210);--fertig-cyan-900:oklch(29% .05 210);--fertig-green-100:oklch(96% .025 150);--fertig-green-300:oklch(80% .095 150);--fertig-green-500:oklch(62% .13 150);--fertig-green-700:oklch(46% .10 150);--fertig-green-900:oklch(28% .06 150);--fertig-amber-100:oklch(97% .025 80);--fertig-amber-300:oklch(84% .10 80);--fertig-amber-500:oklch(72% .14 80);--fertig-amber-700:oklch(50% .10 80);--fertig-amber-900:oklch(29% .06 80);--fertig-red-100:oklch(96% .018 25);--fertig-red-300:oklch(80% .10 25);--fertig-red-500:oklch(62% .18 25);--fertig-red-700:oklch(47% .15 25);--fertig-red-900:oklch(28% .09 25);--fertig-violet-100:oklch(96% .018 290);--fertig-violet-300:oklch(80% .095 290);--fertig-violet-500:oklch(62% .16 290);--fertig-violet-700:oklch(47% .15 290);--fertig-violet-900:oklch(28% .09 290);--fertig-bg:light-dark(oklch(93.5% .008 260),oklch(15.5% .014 260));--fertig-el:light-dark(oklch(99% .004 260),oklch(21% .016 260));--fertig-face:light-dark(oklch(97.2% .006 260),oklch(25% .018 260));--fertig-fg:light-dark(oklch(22% .02 260),oklch(95% .012 260));--fertig-mut:light-dark(oklch(46% .018 260),oklch(72% .02 260));--fertig-bd:light-dark(oklch(22% .02 260 / .13),oklch(95% .012 260 / .13));--fertig-tb:light-dark(oklch(97.2% .006 260),oklch(25% .018 260));--fertig-ac:light-dark(var(--fertig-blue-700),var(--fertig-blue-300));--fertig-on-ac:light-dark(#f7f8fb,#07071c);--fertig-sh:oklch(30% .012 270);--fertig-a1:.06;--fertig-a2:.05;--fertig-sh1:color-mix(in srgb,var(--fertig-sh) calc(var(--fertig-a1) * 100%),transparent);--fertig-sh2:color-mix(in srgb,var(--fertig-sh) calc(var(--fertig-a2) * 100%),transparent);--fertig-up:0 1px 1px var(--fertig-sh1);--fertig-up2:0 1px 1px var(--fertig-sh1),0 8px 22px -8px var(--fertig-sh2);--fertig-dn:inset 0 1px 2px color-mix(in srgb,var(--fertig-sh) 7%,transparent);--fertig-caps:.74em/1.4 var(--fertig-f);--fertig-ease-out:cubic-bezier(.22,1,.36,1);--fertig-ease-in:cubic-bezier(.55,0,1,.45);--fertig-ease:cubic-bezier(.4,0,.2,1);--fertig-dur-1:.12s;--fertig-dur-2:.2s}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--fertig-a1:.42;--fertig-a2:.38}}@supports (color:oklch(from red l c h)){:root{--fertig-on-ac:oklch(from var(--fertig-ac) clamp(.06,(l - .62) * -100,.96) 0 h)}}@supports (color:contrast-color(red)){:root{--fertig-on-ac:color-mix(in oklab,contrast-color(var(--fertig-ac)) 96%,var(--fertig-ac))}}[data-theme=light]{color-scheme:light;--fertig-a1:.06;--fertig-a2:.05}[data-theme=dark]{color-scheme:dark;--fertig-a1:.42;--fertig-a2:.38}[data-accent=blue]{--fertig-ac:light-dark(var(--fertig-blue-700),var(--fertig-blue-300))}[data-accent=cyan]{--fertig-ac:light-dark(var(--fertig-cyan-700),var(--fertig-cyan-300))}[data-accent=green]{--fertig-ac:light-dark(var(--fertig-green-700),var(--fertig-green-300))}[data-accent=amber]{--fertig-ac:light-dark(var(--fertig-amber-700),var(--fertig-amber-300))}[data-accent=red]{--fertig-ac:light-dark(var(--fertig-red-700),var(--fertig-red-300))}[data-accent=violet]{--fertig-ac:light-dark(var(--fertig-violet-700),var(--fertig-violet-300))}[data-accent=gray]{--fertig-ac:light-dark(var(--fertig-gray-700),var(--fertig-gray-300))}*,::before,::after{box-sizing:border-box}html{font:16px/1.65 var(--fertig-f);-webkit-text-size-adjust:100%;tab-size:2}body{margin:0;background:var(--fertig-bg);color:var(--fertig-fg);overflow-wrap:break-word;font-variant-numeric:slashed-zero tabular-nums}::selection{background:color-mix(in srgb,var(--fertig-ac) 28%,transparent)}:focus-visible{outline:3px solid color-mix(in srgb,var(--fertig-ac) 45%,transparent);outline-offset:1px}img,video,iframe{display:block;max-width:100%;height:auto}svg{max-width:100%;vertical-align:middle}img,video{border-radius:var(--fertig-r);box-shadow:var(--fertig-up2)}body>*,body>:where(#root,#app,#__next,[data-fertig])>*{padding-inline:var(--fertig-g)}body>:where(#root,#app,#__next,[data-fertig]){padding-inline:0}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>:is(header,main,footer){background:var(--fertig-el);border-inline:1px solid var(--fertig-bd)}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>header{padding-block:2.4rem .8rem}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>main{padding-bottom:2.8rem}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>footer{padding-block:1.2rem 2rem;color:var(--fertig-mut);font-size:.85em;border-top:1px solid var(--fertig-bd);border-bottom:1px solid var(--fertig-bd)}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav{position:sticky;top:0;z-index:9;--fertig-nw:var(--fertig-w);padding-inline:max(var(--fertig-g),calc(50% - var(--fertig-nw) / 2 + var(--fertig-g)),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(--fertig-tb);color:var(--fertig-fg);border-bottom:1px solid var(--fertig-bd);font-size:.92em}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav a{color:var(--fertig-fg);text-decoration:none;opacity:.75}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav a:hover{opacity:1}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav :is(strong,b) a{opacity:1}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav ul{display:flex;flex-wrap:wrap;gap:1.1rem;list-style:none;padding:0;margin:0;flex:1}@media (width <= 40rem){:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav{row-gap:.55rem}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav>ul{order:2;flex:0 0 100%;flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav>ul::-webkit-scrollbar{display:none}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav>:last-child:not(ul){margin-inline-start:auto}}h1,h2,h3,h4,h5,h6{line-height:1.3;margin:1.4rem 0 .7rem;text-wrap:balance}h1{font-size:clamp(2rem,1.55rem + 1.5vw,2.8rem);letter-spacing:-.035em}h2{font-size:clamp(1.35rem,1.2rem + .5vw,1.65rem);letter-spacing:-.02em;margin-top:2.4rem}h3{font-size:1.12rem;letter-spacing:-.008em;margin-top:1.9rem}h4{font-size:1rem}h5,h6{font:700 var(--fertig-caps);text-transform:uppercase;letter-spacing:.1em;color:var(--fertig-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(--fertig-ac);text-underline-offset:3px;text-decoration-thickness:1px}a:hover{text-decoration-thickness:2px}small{font-size:.85em;color:var(--fertig-mut)}hr{border:0;border-top:1px solid var(--fertig-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(--fertig-bd);padding-block:.15rem;padding-inline:1.2rem 0;color:var(--fertig-mut)}ul,ol{padding-inline-start:1.5rem}li::marker{color:var(--fertig-mut)}dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:.35rem 1rem}dt{color:var(--fertig-mut)}dd{margin:0}figcaption{font-size:.85em;color:var(--fertig-mut);text-align:center}code,kbd,samp,pre{font-family:var(--fertig-fm);font-size:.9em}:not(pre)>code,samp{background:var(--fertig-face);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rs);padding:.08em .35em}kbd{background:var(--fertig-face);border:1px solid var(--fertig-bd);border-bottom-width:2px;border-radius:var(--fertig-rs);padding:.08em .4em;box-shadow:var(--fertig-up)}pre{background:var(--fertig-face);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:1rem;overflow-x:auto}pre code{background:none;border:0;padding:0;font-size:1em}:root{--fertig-syn-comment:light-dark(#6b7280,#8b949e);--fertig-syn-key:light-dark(#7c3aed,#c4a7fb);--fertig-syn-str:light-dark(#15803d,#7ee787);--fertig-syn-num:light-dark(#b45309,#f0b866);--fertig-syn-fn:light-dark(#1d4ed8,#93c5fd);--fertig-syn-attr:light-dark(#b91c1c,#ff9492)}:is(.hljs-comment,.hljs-quote,.token.comment,.token.prolog,.token.doctype){color:var(--fertig-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(--fertig-syn-key)}:is(.hljs-string,.hljs-meta-string,.token.string,.token.attr-value,.token.char){color:var(--fertig-syn-str)}:is(.hljs-number,.hljs-symbol,.hljs-bullet,.token.number,.token.boolean,.token.constant,.token.unit){color:var(--fertig-syn-num)}:is(.hljs-title,.hljs-name,.hljs-section,.hljs-function,.token.tag,.token.function,.token.class-name){color:var(--fertig-syn-fn)}:is(.hljs-attr,.hljs-attribute,.hljs-variable,.hljs-template-variable,.token.attr-name,.token.property,.token.variable){color:var(--fertig-syn-attr)}:is(.hljs-punctuation,.hljs-operator,.token.punctuation,.token.operator){color:var(--fertig-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(--fertig-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(--fertig-fg) 45%,transparent);font:700 var(--fertig-caps);text-transform:uppercase;letter-spacing:.09em;color:var(--fertig-mut);padding-bottom:.4rem}tbody tr:last-child td{border-bottom:0}tfoot td{font-weight:700;border-top:1px solid var(--fertig-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(--fertig-face)}@media (width <= 40rem){table{display:block;overflow-x:auto;overscroll-behavior-x:contain}table :is(th,td){white-space:nowrap}}caption{text-align:start;color:var(--fertig-mut);font-size:.85em;padding-bottom:.35rem}button,input,select,textarea{font:inherit;color:inherit}label{display:block;font-size:.85em;color:var(--fertig-mut)}label:has(input){font-size:1rem;color:var(--fertig-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=image],[type=submit],[type=button],[type=reset]),select,textarea{display:block;width:100%;padding:.52em .7em;background:var(--fertig-el);border:1px solid var(--fertig-bd);border-radius:var(--fertig-r);box-shadow:var(--fertig-dn)}select{appearance:none;padding-inline-end:2.2rem;background-image:linear-gradient(45deg,transparent calc(50% - 1px),currentColor calc(50% - 1px),currentColor calc(50% + .5px),transparent calc(50% + .5px)),linear-gradient(-45deg,transparent calc(50% - 1px),currentColor calc(50% - 1px),currentColor calc(50% + .5px),transparent calc(50% + .5px));background-position:calc(100% - 17px) 54%,calc(100% - 12px) 54%;background-size:6px 6px;background-repeat:no-repeat}select:dir(rtl){background-position:12px 54%,17px 54%}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 var(--fertig-dur-1) var(--fertig-ease),translate var(--fertig-dur-1) var(--fertig-ease)}select:open::picker-icon{rotate:225deg;translate:0 .1em}::picker(select){min-width:anchor-size(width);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:.35rem;background:var(--fertig-el);margin-block-start:.35rem;box-shadow:var(--fertig-up2),0 24px 44px -18px color-mix(in srgb,var(--fertig-sh) 28%,transparent)}option{display:flex;align-items:center;gap:.5em;padding:.4em .6em;border-radius:calc(var(--fertig-r) - 2px)}option:hover{background:var(--fertig-face)}option:checked{background:var(--fertig-ac);color:var(--fertig-on-ac)}option::checkmark{order:1;margin-inline-start:auto;content:"✓"}@media (prefers-reduced-motion:no-preference) and (update:fast){::picker(select){opacity:0;translate:0 -4px;transform-origin:top center;transition:opacity .13s var(--fertig-ease-out),translate .13s var(--fertig-ease-out),display .13s allow-discrete,overlay .13s allow-discrete}select:open::picker(select){opacity:1;translate:0}@starting-style{select:open::picker(select){opacity:0;translate:0 -4px}}}}:is(input,select,textarea):hover:not(:disabled){border-color:color-mix(in srgb,var(--fertig-fg) 25%,transparent)}:is(input,select,textarea):focus-visible{border-color:var(--fertig-ac)}input[type=checkbox],input[type=radio]{width:1.15em;height:1.15em;margin:0;margin-inline-end:.45em;vertical-align:-.18em}:is(input[type=checkbox],input[type=radio],input[type=range],progress,select[multiple]){accent-color:var(--fertig-ac)}:is(input,textarea,[contenteditable]){caret-color:var(--fertig-ac)}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(--fertig-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(--fertig-face);cursor:default}label:has(+ :required)::after,label:has(:required)::after{content:" *";color:var(--fertig-ac)}input:autofill,input:autofill:hover,input:autofill:focus{-webkit-text-fill-color:var(--fertig-fg);box-shadow:var(--fertig-dn),inset 0 0 0 100px var(--fertig-el);caret-color:var(--fertig-ac)}:disabled{color:var(--fertig-mut);cursor:not-allowed;box-shadow:none}fieldset{border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:.9rem 1rem 1rem;background:var(--fertig-face)}fieldset:focus-within{border-color:color-mix(in srgb,var(--fertig-ac) 45%,var(--fertig-bd))}legend{float:left;width:100%;margin-bottom:.8rem;padding:0 0 .6rem;border-bottom:1px solid var(--fertig-bd);font-size:.95em;font-weight:700;color:var(--fertig-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:.48em 1.1em;background:var(--fertig-el);color:var(--fertig-fg);cursor:pointer;border:1px solid var(--fertig-bd);border-radius:var(--fertig-r);font:inherit;min-width:5rem}:is(button,[type=submit],[type=button],[type=reset],a.primary,a[role=button]):hover:not(:disabled){background:var(--fertig-face)}[type=submit],.primary{background:var(--fertig-ac);border-color:transparent;color:var(--fertig-on-ac)}:is([type=submit],.primary,a.primary):hover:not(:disabled){background:color-mix(in oklab,var(--fertig-ac),#fff 9%)}@supports (color:oklch(from red l c h)){:is([type=submit],.primary,a.primary):hover:not(:disabled){background:oklch(from var(--fertig-ac) calc(l + .05) c h)}}:is(button,a,input,select,label)[data-size=sm]{padding:.2em .7em;font-size:.85em;min-width:0}:is(button,a,input,select,label)[data-size=lg]{padding:.55em 1.5em;font-size:1.05em}button[data-icon]{min-width:0;padding:.38em .62em;line-height:1}:is(button,a,input,select,label)[data-block]{display:block;width:100%;min-width:0}:is(button,a,input)[data-variant=ghost]{background:none;border-color:transparent;box-shadow:none}:is(button,a,input)[data-variant=ghost]:hover:not(:disabled){background:var(--fertig-face);border-color:var(--fertig-bd)}:is(button,a,input)[data-variant=link]{background:none;border:0;box-shadow:none;min-width:0;padding-inline:.2em;color:var(--fertig-ac);text-decoration:underline;text-underline-offset:3px}:is(button,a,input)[data-variant=link]:hover:not(:disabled){background:none;text-decoration-thickness:2px}button[aria-pressed=true]{background:var(--fertig-face);color:var(--fertig-ac);font-weight:700}button[aria-pressed=true]:hover:not(:disabled){background:color-mix(in srgb,var(--fertig-fg) 7%,var(--fertig-face))}details{border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:.7rem 1.1rem;background:var(--fertig-el)}summary{cursor:pointer;font-weight:700;list-style:none}summary::before{content:"▸ ";color:var(--fertig-mut)}details[open]>summary::before{content:"▾ "}details[open]>summary{margin-bottom:.6rem}dialog{background:var(--fertig-el);color:var(--fertig-fg);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:1.6rem;max-width:min(30rem,92dvw);box-shadow:0 1px 1px color-mix(in srgb,var(--fertig-sh) 8%,transparent),0 28px 60px -22px color-mix(in srgb,var(--fertig-sh) 28%,transparent)}dialog>:last-child:not(footer){margin-bottom:0}dialog,[popover]{overscroll-behavior:contain}dialog::backdrop{background:color-mix(in srgb,var(--fertig-sh) 32%,transparent)}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.6rem;background:var(--fertig-el)}dialog>header{inset-block-start:-1.6rem;margin-block:-1.6rem .35rem;padding:1.6rem 1.6rem .5rem;font-weight:700;border-radius:var(--fertig-rw) var(--fertig-rw) 0 0}dialog:is([open],:modal)>header>:is(h1,h2,h3,h4,p){margin:0;font-family:var(--fertig-f);font-size:1.1rem;font-weight:600;line-height:1.3;letter-spacing:-.01em}dialog>footer{inset-block-end:-1.6rem;margin-block:1.35rem -1.6rem;padding:.5rem 1.6rem 1.6rem;border-radius:0 0 var(--fertig-rw) var(--fertig-rw);display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;justify-content:flex-end}@supports (animation-timeline:scroll()){dialog>header{animation:fertig-rule-under linear both;animation-timeline:scroll(nearest);animation-range:0 1.2rem}dialog>footer{animation:fertig-rule-over linear both;animation-timeline:scroll(nearest);animation-range:calc(100% - 1.2rem) 100%}@keyframes fertig-rule-under{from{box-shadow:none}to{box-shadow:0 1px 0 var(--fertig-bd)}}@keyframes fertig-rule-over{from{box-shadow:0 -1px 0 var(--fertig-bd)}to{box-shadow:none}}}dialog>footer>:is(p,span):first-child{margin:0;margin-inline-end:auto;color:var(--fertig-mut)}@media (prefers-reduced-motion:no-preference) and (update:fast){dialog,dialog::backdrop{transition:opacity var(--fertig-dur-2) var(--fertig-ease-out),translate var(--fertig-dur-2) var(--fertig-ease-out),display var(--fertig-dur-2) allow-discrete,overlay var(--fertig-dur-2) 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 var(--fertig-ease-out),translate .13s var(--fertig-ease-out),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;margin-block:1.1rem}::target-text{background:color-mix(in srgb,var(--fertig-ac) 28%,transparent)}aside{border:1px solid var(--fertig-bd);border-inline-start:3px solid var(--fertig-ac);border-radius:var(--fertig-rw);border-start-start-radius:0;border-end-start-radius:0;background:var(--fertig-el);padding:.7rem 1.1rem;margin-block:1.1rem}progress{width:100%;height:.5rem;border:0;border-radius:var(--fertig-rp);background:var(--fertig-face)}progress::-webkit-progress-bar{background:var(--fertig-face);border-radius:var(--fertig-rp)}progress::-webkit-progress-value{background:var(--fertig-ac);border-radius:var(--fertig-rp)}progress::-moz-progress-bar{background:var(--fertig-ac);border-radius:var(--fertig-rp)}@supports selector(::details-content){@media (prefers-reduced-motion:no-preference) and (update:fast){details{interpolate-size:allow-keywords}details::details-content{block-size:0;overflow:clip;transition:block-size .28s var(--fertig-ease),content-visibility .28s allow-discrete}details[open]::details-content{block-size:auto}}}[role=group]{display:inline-flex;vertical-align:middle;max-inline-size:100%;overflow:auto clip;overscroll-behavior-x:contain}[role=group]>*{border-radius:0;margin-inline-start:-1px;box-shadow:none;min-width:0}[role=group]>:focus-visible{outline-offset:-3px}[role=group]>:first-child{margin-inline-start:0;border-start-start-radius:var(--fertig-rp);border-end-start-radius:var(--fertig-rp)}[role=group]>:last-child{border-start-end-radius:var(--fertig-rp);border-end-end-radius:var(--fertig-rp)}[role=group]>[aria-pressed=true]{background:var(--fertig-face);color:var(--fertig-ac);font-weight:700}[role=group]>:active:not(:disabled){translate:none}[role=tablist]{display:flex;gap:.1rem;border-bottom:1px solid var(--fertig-bd);margin:1.1rem 0}[role=tab]{background:none;border:0;box-shadow:none;min-width:0;color:var(--fertig-mut);padding:.45em .9em;border-radius:var(--fertig-r) var(--fertig-r) 0 0;margin-bottom:-1px}[role=tab]:hover:not(:disabled){background:var(--fertig-face);color:var(--fertig-fg)}[role=tab][aria-selected=true]{color:var(--fertig-fg);box-shadow:inset 0 -2px 0 var(--fertig-ac)}input[type=checkbox][switch],input[type=checkbox][role=switch]{appearance:none;width:2.2em;height:1.3em;border-radius:var(--fertig-rp);border:0;background:color-mix(in srgb,var(--fertig-fg) 20%,transparent);position:relative;cursor:pointer;vertical-align:-.3em;margin-inline-end:.5em}input[switch]::after,input[role=switch]::after{content:"";position:absolute;inset-block-start:.14em;inset-inline-start:.14em;width:1.02em;height:1.02em;border-radius:50%;background:#fff;box-shadow:var(--fertig-up);transition:translate .16s var(--fertig-ease-out)}input[switch]:checked,input[role=switch]:checked{background:var(--fertig-ac)}input[switch]:checked::after,input[role=switch]:checked::after{translate:.9em 0}:is(input[switch],input[role=switch]):checked:dir(rtl)::after{translate:-.9em 0}[popover]{background:var(--fertig-el);color:var(--fertig-fg);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:.35rem;min-width:12rem;max-block-size:60dvh;overflow:auto;font-size:.95em;box-shadow:var(--fertig-up2),0 24px 44px -18px color-mix(in srgb,var(--fertig-sh) 28%,transparent)}@supports (position-area:block-end span-inline-end){[popover]{position:fixed;inset:auto;position-anchor:auto;position-area:block-end span-inline-end;position-try-fallbacks:flip-block,flip-inline;margin:.35rem 0 0}@supports (min-width:anchor-size(width)){[popover]{min-width:max(12rem,anchor-size(width));position-visibility:anchors-visible}}}[popover] :is(ul,menu){list-style:none;padding:0;margin:0}[popover] :is(a,button):not(:disabled){display:block;width:100%;text-align:start;background:none;border:0;box-shadow:none;min-width:0;padding:.4em .6em;text-decoration:none;color:inherit;border-radius:calc(var(--fertig-r) - 2px);font-weight:400}[popover] :is(a,button):hover:not(:disabled){background:var(--fertig-ac);color:var(--fertig-on-ac)}[popover] hr{margin:.3rem 0}nav[aria-label] ol{display:flex;flex-wrap:wrap;gap:.5em;list-style:none;padding:0;font-size:.9em}nav[aria-label] ol li + li::before{content:"/";margin-inline-end:.5em;color:var(--fertig-mut)}[aria-busy=true]{cursor:progress}[aria-busy=true]::before{content:"";display:inline-block;width:.85em;height:.85em;margin-inline-end:.55em;border:2px solid currentColor;border-top-color:transparent;border-radius:50%;vertical-align:-.1em}@media (prefers-reduced-motion:no-preference) and (update:fast){[aria-busy=true]::before{animation:fertig-spin .6s linear infinite}}@keyframes fertig-spin{to{rotate:360deg}}[data-tooltip]{position:relative}[data-tooltip]:is(:hover,:focus-visible,:active)::after{content:attr(data-tooltip);position:absolute;inset-block-end:100%;inset-inline-start:50%;translate:-50% -.45em;z-index:10;white-space:nowrap;pointer-events:none;background:light-dark(#1d1d1f,#3a3a40);color:#f7f8fb;font-size:.8em;padding:.25em .55em;border-radius:var(--fertig-r);box-shadow:var(--fertig-up2)}[data-tooltip]:dir(rtl)::after{translate:50% -.45em}[data-tone=ok]{--fertig-ac:light-dark(var(--fertig-green-700),var(--fertig-green-300))}[data-tone=warn]{--fertig-ac:light-dark(var(--fertig-amber-700),var(--fertig-amber-300))}[data-tone=err]{--fertig-ac:light-dark(var(--fertig-red-700),var(--fertig-red-300))}[data-tone] .badge,.badge[data-tone]{color:var(--fertig-ac);border-color:var(--fertig-ac)}[data-avatar]{display:inline-grid;place-items:center;flex:none;overflow:hidden;inline-size:2.5rem;aspect-ratio:1;border-radius:50%;background:var(--fertig-face);border:1px solid var(--fertig-bd);font-size:.8em;font-weight:700;color:var(--fertig-mut);object-fit:cover}[data-avatar=sm]{inline-size:1.75rem;font-size:.7em}[data-avatar=lg]{inline-size:3.5rem;font-size:1em}[data-skeleton]{color:transparent;border-radius:var(--fertig-r);pointer-events:none;user-select:none;min-height:1em;background:linear-gradient(90deg,var(--fertig-face),color-mix(in srgb,var(--fertig-fg) 9%,var(--fertig-face)),var(--fertig-face));background-size:200% 100%}[data-skeleton] *{visibility:hidden}@media (prefers-reduced-motion:no-preference) and (update:fast){[data-skeleton]{animation:fertig-shimmer 1.4s linear infinite}@keyframes fertig-shimmer{to{background-position:-200% 0}}}dialog[data-side]{max-width:none;margin:0;border-radius:0;padding:1.4rem}dialog[data-side=right]{inset:0 0 0 auto;block-size:100dvh;inline-size:min(28rem,92dvw);border-block:0;border-inline-end:0}dialog[data-side=left]{inset:0 auto 0 0;block-size:100dvh;inline-size:min(28rem,92dvw);border-block:0;border-inline-start:0}dialog[data-side=bottom]{inset:auto 0 0 0;inline-size:100%;max-block-size:85dvh;border-radius:var(--fertig-rw) var(--fertig-rw) 0 0;border-bottom:0}@media (prefers-reduced-motion:no-preference) and (update:fast){dialog[data-side=right]{translate:100% 0}dialog[data-side=left]{translate:-100% 0}dialog[data-side=bottom]{translate:0 100%}dialog[data-side][open]{translate:0 0}@starting-style{dialog[data-side=right][open]{translate:100% 0}dialog[data-side=left][open]{translate:-100% 0}dialog[data-side=bottom][open]{translate:0 100%}}}[popover][data-toast]{position:fixed;inset:auto 1rem 1rem auto;margin:0;min-width:16rem;max-width:min(24rem,92dvw);padding:.8rem 1rem}@supports (position-area:block-end span-inline-end){[popover][data-toast]{position-area:none;inset:auto 1rem 1rem auto;min-width:16rem}}[popover][data-toast-region]{position:fixed;inset:auto 1rem 1rem auto;margin:0;display:flex;flex-direction:column;align-items:flex-end;gap:.6rem;background:none;border:0;box-shadow:none;padding:0;max-block-size:none;overflow:visible;pointer-events:none}[popover][data-toast-region]>[data-toast]{pointer-events:auto;position:static;inset:auto;min-width:16rem;max-width:min(24rem,92dvw);padding:.8rem 1rem;background:var(--fertig-el);color:var(--fertig-fg);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);font-size:.95em;box-shadow:var(--fertig-up2),0 24px 44px -18px color-mix(in srgb,var(--fertig-sh) 28%,transparent)}@supports (position-area:block-end span-inline-end){[popover][data-toast-region]{position-area:none;inset:auto 1rem 1rem auto}}menu{list-style:none;padding:0;margin:1.1rem 0;border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);background:var(--fertig-el)}menu>li{padding:.55rem .85rem}menu>li + li{border-top:1px solid var(--fertig-bd)}[popover] menu{border:0;padding:0;margin:0;background:none}[popover] menu>li{padding:0}[popover] menu>li + li{border-top:0}nav menu{border:0;background:none;padding:0;margin-block:0 1.2rem}nav menu>li{padding:0}nav menu>li + li{border-top:0}nav menu :is(a,button){display:block;inline-size:100%;text-align:start;padding:.38rem .6rem;border:0;border-radius:var(--fertig-r);background:none;box-shadow:none;font:inherit;color:var(--fertig-fg);text-decoration:none;opacity:.72}nav menu :is(a,button):hover{background:var(--fertig-face);opacity:1}nav menu :is(a,button)[aria-current]{background:var(--fertig-face);color:var(--fertig-ac);font-weight:600;opacity:1}[data-layout=sidebar]{display:grid;gap:1.5rem;align-items:start}@media (width>= 56rem){[data-layout=sidebar]{grid-template-columns:15rem minmax(0,1fr)}[data-layout=sidebar]>:first-child{position:sticky;top:4.5rem}}[data-layout=sidebar]>*{min-width:0}[data-carousel]{display:flex;gap:1rem;overflow-x:auto;padding-bottom:.5rem;scroll-snap-type:x mandatory;overscroll-behavior-x:contain}[data-carousel]>*{scroll-snap-align:start;flex:0 0 min(20rem,82%)}.muted{color:var(--fertig-mut)}.center{text-align:center}.wide{max-width:80rem}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav.wide{--fertig-nw:80rem}.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))}.grid + *{margin-top:1.1rem}.card{container-type:inline-size;border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:1.1rem;background:var(--fertig-el);box-shadow:var(--fertig-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:38rem}.hidden{display:none}.badge{border:1px solid var(--fertig-bd);border-radius:var(--fertig-rp);background:var(--fertig-face);padding:.1em .6em;font:700 var(--fertig-caps);color:var(--fertig-mut);text-transform:uppercase;letter-spacing:.07em}.card>:is(header,footer){margin-inline:-1.1rem;padding-inline:1.1rem}.card>header{margin-top:-.25rem;padding-bottom:.7rem;font-weight:600;border-bottom:1px solid var(--fertig-bd)}.card>footer{margin-top:auto;margin-bottom:-.25rem;padding-top:.7rem;color:var(--fertig-mut);font-size:.85em;border-top:1px solid var(--fertig-bd)}.card>:is(img,video):first-child{align-self:stretch;width:auto;max-width:none;margin:-1.1rem -1.1rem 0;aspect-ratio:16 / 9;object-fit:cover;border:0;border-radius:var(--fertig-rw) var(--fertig-rw) 0 0;box-shadow:none}.card[data-tone]{background:linear-gradient(var(--fertig-ac),var(--fertig-ac)) top / 100% 3px no-repeat,var(--fertig-el)}: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(--fertig-ac) 45%,var(--fertig-bd));box-shadow:var(--fertig-up2),0 16px 30px -16px color-mix(in srgb,var(--fertig-sh) 28%,transparent);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-block-start:4rem}:is(h1,h2,h3,h4):target{background:color-mix(in srgb,var(--fertig-ac) 12%,transparent)}a[target=_blank]:not(:has(>img,>svg))::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(--fertig-ac)}del{color:var(--fertig-mut)}address{font-style:normal;color:var(--fertig-mut)}hgroup>*{margin:0}hgroup>p{color:var(--fertig-mut)}output{font-weight:700}meter{width:100%;height:.5rem}optgroup{font-weight:700;color:var(--fertig-mut)}::file-selector-button{margin-inline-end:.8em}::file-selector-button:hover{background:var(--fertig-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(--fertig-ac)}:is(pre,table,textarea,dialog,[popover],menu,fieldset,[role=group],[data-carousel],[data-layout=sidebar]>*){scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--fertig-fg) 25%,transparent) transparent}@page{margin:2cm}@media print{:root{--fertig-bg:#fff;--fertig-el:#fff;--fertig-fg:#000;--fertig-bd:#999}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav{display:none}body>*,body>:where(#root,#app,#__next,[data-fertig])>*{border:0}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}:is(button,a,input,select,label)[data-size=sm]{min-height:32px}}@media (inverted-colors:inverted){img,video,iframe{filter:invert(1) hue-rotate(180deg)}}@media (color-gamut:p3){@supports (color:oklch(60% .2 250)){:root{--fertig-ac:light-dark(oklch(52% .21 258),oklch(76% .15 258))}}}:root{text-spacing-trim:trim-start;text-autospace:normal}@media (prefers-contrast:more){:root{--fertig-bd:light-dark(#00000059,#ffffff6b);--fertig-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],.card,.badge,[role=tab],[role=group]>*,[popover] :is(a,button){transition:box-shadow var(--fertig-dur-1) var(--fertig-ease),background-color var(--fertig-dur-1) var(--fertig-ease),border-color var(--fertig-dur-1) var(--fertig-ease),color var(--fertig-dur-1) var(--fertig-ease),translate .08s var(--fertig-ease-out)}:focus-visible{transition:none}}@supports not (color:light-dark(#000,#fff)){:root{--fertig-bg:#e6eaef;--fertig-el:#fafcfe;--fertig-face:#f3f6fa;--fertig-fg:#151b24;--fertig-mut:#525962;--fertig-bd:#151b2421;--fertig-tb:#f3f6fa;--fertig-ac:#2850de;--fertig-on-ac:#f7f8fb}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--fertig-bg:#090c12;--fertig-el:#141920;--fertig-face:#1c222a;--fertig-fg:#eaeff7;--fertig-mut:#9da5b1;--fertig-bd:#eaeff721;--fertig-tb:#1c222a;--fertig-ac:#90b5ff;--fertig-on-ac:#07071c}}[data-theme=dark]{--fertig-bg:#090c12;--fertig-el:#141920;--fertig-face:#1c222a;--fertig-fg:#eaeff7;--fertig-mut:#9da5b1;--fertig-bd:#eaeff721;--fertig-tb:#1c222a;--fertig-ac:#90b5ff;--fertig-on-ac:#07071c}}}@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]{border-bottom:2px solid Highlight}button[aria-pressed=true]{border-color:Highlight}}}
|
|
1
|
+
/*! fertig v4.0.4 — a classless CSS stylesheet. MIT */@property --fertig-a1{syntax:"<number>";inherits:true;initial-value:.06}@property --fertig-a2{syntax:"<number>";inherits:true;initial-value:.05}@layer fertig,fertig-a11y;@layer fertig{:root{color-scheme:light dark;accent-color:var(--fertig-ac);caret-color:var(--fertig-ac);--fertig-f:ui-sans-serif,system-ui,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--fertig-fm:ui-monospace,"Cascadia Code","Roboto Mono",Consolas,"Liberation Mono",monospace;--fertig-w:72rem;--fertig-g:clamp(1.15rem,4vw,1.9rem);--fertig-r:8px;--fertig-rs:calc(var(--fertig-r) * .5);--fertig-rw:calc(var(--fertig-r) * 1.33);--fertig-rp:calc(var(--fertig-r) * 1000);--fertig-gray-100:oklch(97% .005 260);--fertig-gray-300:oklch(82% .01 260);--fertig-gray-500:oklch(62% .014 260);--fertig-gray-700:oklch(47% .015 260);--fertig-gray-900:oklch(25% .018 260);--fertig-blue-100:oklch(96% .018 255);--fertig-blue-300:oklch(80% .095 255);--fertig-blue-500:oklch(62% .16 255);--fertig-blue-700:oklch(47% .15 255);--fertig-blue-900:oklch(29% .09 255);--fertig-cyan-100:oklch(96% .025 210);--fertig-cyan-300:oklch(82% .085 210);--fertig-cyan-500:oklch(64% .11 210);--fertig-cyan-700:oklch(47% .08 210);--fertig-cyan-900:oklch(29% .05 210);--fertig-green-100:oklch(96% .025 150);--fertig-green-300:oklch(80% .095 150);--fertig-green-500:oklch(62% .13 150);--fertig-green-700:oklch(46% .10 150);--fertig-green-900:oklch(28% .06 150);--fertig-amber-100:oklch(97% .025 80);--fertig-amber-300:oklch(84% .10 80);--fertig-amber-500:oklch(72% .14 80);--fertig-amber-700:oklch(50% .10 80);--fertig-amber-900:oklch(29% .06 80);--fertig-red-100:oklch(96% .018 25);--fertig-red-300:oklch(80% .10 25);--fertig-red-500:oklch(62% .18 25);--fertig-red-700:oklch(47% .15 25);--fertig-red-900:oklch(28% .09 25);--fertig-violet-100:oklch(96% .018 290);--fertig-violet-300:oklch(80% .095 290);--fertig-violet-500:oklch(62% .16 290);--fertig-violet-700:oklch(47% .15 290);--fertig-violet-900:oklch(28% .09 290);--fertig-bg:light-dark(oklch(93.5% .008 260),oklch(15.5% .014 260));--fertig-el:light-dark(oklch(99% .004 260),oklch(21% .016 260));--fertig-face:light-dark(oklch(97.2% .006 260),oklch(25% .018 260));--fertig-fg:light-dark(oklch(22% .02 260),oklch(95% .012 260));--fertig-mut:light-dark(oklch(46% .018 260),oklch(72% .02 260));--fertig-bd:light-dark(oklch(22% .02 260 / .13),oklch(95% .012 260 / .13));--fertig-tb:light-dark(oklch(97.2% .006 260),oklch(25% .018 260));--fertig-ac:light-dark(var(--fertig-blue-700),var(--fertig-blue-300));--fertig-on-ac:light-dark(#f7f8fb,#07071c);--fertig-sh:oklch(30% .012 270);--fertig-a1:.06;--fertig-a2:.05;--fertig-sh1:color-mix(in srgb,var(--fertig-sh) calc(var(--fertig-a1) * 100%),transparent);--fertig-sh2:color-mix(in srgb,var(--fertig-sh) calc(var(--fertig-a2) * 100%),transparent);--fertig-up:0 1px 1px var(--fertig-sh1);--fertig-up2:0 1px 1px var(--fertig-sh1),0 8px 22px -8px var(--fertig-sh2);--fertig-dn:inset 0 1px 2px color-mix(in srgb,var(--fertig-sh) 7%,transparent);--fertig-caps:.74em/1.4 var(--fertig-f);--fertig-ease-out:cubic-bezier(.22,1,.36,1);--fertig-ease-in:cubic-bezier(.55,0,1,.45);--fertig-ease:cubic-bezier(.4,0,.2,1);--fertig-dur-1:.12s;--fertig-dur-2:.2s}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--fertig-a1:.42;--fertig-a2:.38}}@supports (color:oklch(from red l c h)){:root{--fertig-on-ac:oklch(from var(--fertig-ac) clamp(.06,(l - .62) * -100,.96) 0 h)}}@supports (color:contrast-color(red)){:root{--fertig-on-ac:color-mix(in oklab,contrast-color(var(--fertig-ac)) 96%,var(--fertig-ac))}}[data-theme=light]{color-scheme:light;--fertig-a1:.06;--fertig-a2:.05}[data-theme=dark]{color-scheme:dark;--fertig-a1:.42;--fertig-a2:.38}[data-accent=blue]{--fertig-ac:light-dark(var(--fertig-blue-700),var(--fertig-blue-300))}[data-accent=cyan]{--fertig-ac:light-dark(var(--fertig-cyan-700),var(--fertig-cyan-300))}[data-accent=green]{--fertig-ac:light-dark(var(--fertig-green-700),var(--fertig-green-300))}[data-accent=amber]{--fertig-ac:light-dark(var(--fertig-amber-700),var(--fertig-amber-300))}[data-accent=red]{--fertig-ac:light-dark(var(--fertig-red-700),var(--fertig-red-300))}[data-accent=violet]{--fertig-ac:light-dark(var(--fertig-violet-700),var(--fertig-violet-300))}[data-accent=gray]{--fertig-ac:light-dark(var(--fertig-gray-700),var(--fertig-gray-300))}*,::before,::after{box-sizing:border-box}html{font:16px/1.65 var(--fertig-f);-webkit-text-size-adjust:100%;tab-size:2}body{margin:0;background:var(--fertig-bg);color:var(--fertig-fg);overflow-wrap:break-word;font-variant-numeric:slashed-zero tabular-nums}::selection{background:color-mix(in srgb,var(--fertig-ac) 28%,transparent)}:focus-visible{outline:3px solid color-mix(in srgb,var(--fertig-ac) 45%,transparent);outline-offset:1px}img,video,iframe{display:block;max-width:100%;height:auto}svg{max-width:100%;vertical-align:middle}img,video{border-radius:var(--fertig-r);box-shadow:var(--fertig-up2)}body>*,body>:where(#root,#app,#__next,[data-fertig])>*{padding-inline:var(--fertig-g)}body>:where(#root,#app,#__next,[data-fertig]){padding-inline:0}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>:is(header,main,footer){background:var(--fertig-el);border-inline:1px solid var(--fertig-bd)}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>header{padding-block:2.4rem .8rem}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>main{padding-bottom:2.8rem}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>footer{padding-block:1.2rem 2rem;color:var(--fertig-mut);font-size:.85em;border-top:1px solid var(--fertig-bd);border-bottom:1px solid var(--fertig-bd)}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav{position:sticky;top:0;z-index:9;--fertig-nw:var(--fertig-w);padding-inline:max(var(--fertig-g),calc(50% - var(--fertig-nw) / 2 + var(--fertig-g)),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(--fertig-tb);color:var(--fertig-fg);border-bottom:1px solid var(--fertig-bd);font-size:.92em}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav a{color:var(--fertig-fg);text-decoration:none;opacity:.75}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav a:hover{opacity:1}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav :is(strong,b) a{opacity:1}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav ul{display:flex;flex-wrap:wrap;gap:1.1rem;list-style:none;padding:0;margin:0;flex:1}@media (width <= 40rem){:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav{row-gap:.55rem}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav>ul{order:2;flex:0 0 100%;flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav>ul::-webkit-scrollbar{display:none}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav>:last-child:not(ul){margin-inline-start:auto}}h1,h2,h3,h4,h5,h6{line-height:1.3;margin:1.4rem 0 .7rem;text-wrap:balance}h1{font-size:clamp(2rem,1.55rem + 1.5vw,2.8rem);letter-spacing:-.035em}h2{font-size:clamp(1.35rem,1.2rem + .5vw,1.65rem);letter-spacing:-.02em;margin-top:2.4rem}h3{font-size:1.12rem;letter-spacing:-.008em;margin-top:1.9rem}h4{font-size:1rem}h5,h6{font:700 var(--fertig-caps);text-transform:uppercase;letter-spacing:.1em;color:var(--fertig-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(--fertig-ac);text-underline-offset:3px;text-decoration-thickness:1px}a:hover{text-decoration-thickness:2px}small{font-size:.85em;color:var(--fertig-mut)}hr{border:0;border-top:1px solid var(--fertig-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(--fertig-bd);padding-block:.15rem;padding-inline:1.2rem 0;color:var(--fertig-mut)}ul,ol{padding-inline-start:1.5rem}li::marker{color:var(--fertig-mut)}dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:.35rem 1rem}dt{color:var(--fertig-mut)}dd{margin:0}figcaption{font-size:.85em;color:var(--fertig-mut);text-align:center}code,kbd,samp,pre{font-family:var(--fertig-fm);font-size:.9em}:not(pre)>code,samp{background:var(--fertig-face);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rs);padding:.08em .35em}kbd{background:var(--fertig-face);border:1px solid var(--fertig-bd);border-bottom-width:2px;border-radius:var(--fertig-rs);padding:.08em .4em;box-shadow:var(--fertig-up)}pre{background:var(--fertig-face);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:1rem;overflow-x:auto}pre code{background:none;border:0;padding:0;font-size:1em}:root{--fertig-syn-comment:light-dark(#6b7280,#8b949e);--fertig-syn-key:light-dark(#7c3aed,#c4a7fb);--fertig-syn-str:light-dark(#15803d,#7ee787);--fertig-syn-num:light-dark(#b45309,#f0b866);--fertig-syn-fn:light-dark(#1d4ed8,#93c5fd);--fertig-syn-attr:light-dark(#b91c1c,#ff9492)}:is(.hljs-comment,.hljs-quote,.token.comment,.token.prolog,.token.doctype){color:var(--fertig-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(--fertig-syn-key)}:is(.hljs-string,.hljs-meta-string,.token.string,.token.attr-value,.token.char){color:var(--fertig-syn-str)}:is(.hljs-number,.hljs-symbol,.hljs-bullet,.token.number,.token.boolean,.token.constant,.token.unit){color:var(--fertig-syn-num)}:is(.hljs-title,.hljs-name,.hljs-section,.hljs-function,.token.tag,.token.function,.token.class-name){color:var(--fertig-syn-fn)}:is(.hljs-attr,.hljs-attribute,.hljs-variable,.hljs-template-variable,.token.attr-name,.token.property,.token.variable){color:var(--fertig-syn-attr)}:is(.hljs-punctuation,.hljs-operator,.token.punctuation,.token.operator){color:var(--fertig-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(--fertig-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(--fertig-fg) 45%,transparent);font:700 var(--fertig-caps);text-transform:uppercase;letter-spacing:.09em;color:var(--fertig-mut);padding-bottom:.4rem}tbody tr:last-child td{border-bottom:0}tfoot td{font-weight:700;border-top:1px solid var(--fertig-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(--fertig-face)}@media (width <= 40rem){table{display:block;overflow-x:auto;overscroll-behavior-x:contain}table :is(th,td){white-space:nowrap}}caption{text-align:start;color:var(--fertig-mut);font-size:.85em;padding-bottom:.35rem}button,input,select,textarea{font:inherit;color:inherit}label{display:block;font-size:.85em;color:var(--fertig-mut)}label:has(input){font-size:1rem;color:var(--fertig-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=image],[type=submit],[type=button],[type=reset]),select,textarea{display:block;width:100%;padding:.52em .7em;background:var(--fertig-el);border:1px solid var(--fertig-bd);border-radius:var(--fertig-r);box-shadow:var(--fertig-dn)}select{appearance:none;padding-inline-end:2.2rem;background-image:linear-gradient(45deg,transparent calc(50% - 1px),currentColor calc(50% - 1px),currentColor calc(50% + .5px),transparent calc(50% + .5px)),linear-gradient(-45deg,transparent calc(50% - 1px),currentColor calc(50% - 1px),currentColor calc(50% + .5px),transparent calc(50% + .5px));background-position:calc(100% - 17px) 54%,calc(100% - 12px) 54%;background-size:6px 6px;background-repeat:no-repeat}select:dir(rtl){background-position:12px 54%,17px 54%}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 var(--fertig-dur-1) var(--fertig-ease),translate var(--fertig-dur-1) var(--fertig-ease)}select:open::picker-icon{rotate:225deg;translate:0 .1em}::picker(select){min-width:anchor-size(width);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:.35rem;background:var(--fertig-el);margin-block-start:.35rem;box-shadow:var(--fertig-up2),0 24px 44px -18px color-mix(in srgb,var(--fertig-sh) 28%,transparent)}option{display:flex;align-items:center;gap:.5em;padding:.4em .6em;border-radius:calc(var(--fertig-r) - 2px)}option:hover{background:var(--fertig-face)}option:checked{background:var(--fertig-ac);color:var(--fertig-on-ac)}option::checkmark{order:1;margin-inline-start:auto;content:"✓"}@media (prefers-reduced-motion:no-preference) and (update:fast){::picker(select){opacity:0;translate:0 -4px;transform-origin:top center;transition:opacity .13s var(--fertig-ease-out),translate .13s var(--fertig-ease-out),display .13s allow-discrete,overlay .13s allow-discrete}select:open::picker(select){opacity:1;translate:0}@starting-style{select:open::picker(select){opacity:0;translate:0 -4px}}}}:is(input,select,textarea):hover:not(:disabled){border-color:color-mix(in srgb,var(--fertig-fg) 25%,transparent)}:is(input,select,textarea):focus-visible{border-color:var(--fertig-ac)}input[type=checkbox],input[type=radio]{width:1.15em;height:1.15em;margin:0;margin-inline-end:.45em;vertical-align:-.18em}:is(input[type=checkbox],input[type=radio],input[type=range],progress,select[multiple]){accent-color:var(--fertig-ac)}:is(input,textarea,[contenteditable]){caret-color:var(--fertig-ac)}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(--fertig-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(--fertig-face);cursor:default}label:has(+ :required)::after,label:has(:required)::after{content:" *";color:var(--fertig-ac)}input:autofill,input:autofill:hover,input:autofill:focus{-webkit-text-fill-color:var(--fertig-fg);box-shadow:var(--fertig-dn),inset 0 0 0 100px var(--fertig-el);caret-color:var(--fertig-ac)}:disabled{color:var(--fertig-mut);cursor:not-allowed;box-shadow:none}fieldset{border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:.9rem 1rem 1rem;background:var(--fertig-face)}fieldset:focus-within{border-color:color-mix(in srgb,var(--fertig-ac) 45%,var(--fertig-bd))}legend{float:left;width:100%;margin-bottom:.8rem;padding:0 0 .6rem;border-bottom:1px solid var(--fertig-bd);font-size:.95em;font-weight:700;color:var(--fertig-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:.48em 1.1em;background:var(--fertig-el);color:var(--fertig-fg);cursor:pointer;border:1px solid var(--fertig-bd);border-radius:var(--fertig-r);font:inherit;min-width:5rem}:is(button,[type=submit],[type=button],[type=reset],a.primary,a[role=button]):hover:not(:disabled){background:var(--fertig-face)}[type=submit],.primary{background:var(--fertig-ac);border-color:transparent;color:var(--fertig-on-ac)}:is(button,[type=submit],[type=button],[type=reset]):disabled{background:var(--fertig-face);border-color:var(--fertig-bd);color:var(--fertig-mut)}:is([type=submit],.primary,a.primary):hover:not(:disabled){background:color-mix(in oklab,var(--fertig-ac),#fff 9%)}@supports (color:oklch(from red l c h)){:is([type=submit],.primary,a.primary):hover:not(:disabled){background:oklch(from var(--fertig-ac) calc(l + .05) c h)}}:is(button,a,input,select,label)[data-size=sm]{padding:.2em .7em;font-size:.85em;min-width:0}:is(button,a,input,select,label)[data-size=lg]{padding:.55em 1.5em;font-size:1.05em}button[data-icon]{min-width:0;padding:.38em .62em;line-height:1}:is(button,a,input,select,label)[data-block]{display:block;width:100%;min-width:0}:is(button,a,input)[data-variant=ghost]{background:none;border-color:transparent;box-shadow:none}:is(button,a,input)[data-variant=ghost]:hover:not(:disabled){background:var(--fertig-face);border-color:var(--fertig-bd)}:is(button,a,input)[data-variant=link]{background:none;border:0;box-shadow:none;min-width:0;padding-inline:.2em;color:var(--fertig-ac);text-decoration:underline;text-underline-offset:3px}:is(button,a,input)[data-variant=link]:hover:not(:disabled){background:none;text-decoration-thickness:2px}button[aria-pressed=true]{background:var(--fertig-face);color:var(--fertig-ac);font-weight:700}button[aria-pressed=true]:hover:not(:disabled){background:color-mix(in srgb,var(--fertig-fg) 7%,var(--fertig-face))}details{border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:.7rem 1.1rem;background:var(--fertig-el)}summary{cursor:pointer;font-weight:700;list-style:none}summary::before{content:"▸ ";color:var(--fertig-mut)}details[open]>summary::before{content:"▾ "}details[open]>summary{margin-bottom:.6rem}dialog{background:var(--fertig-el);color:var(--fertig-fg);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:1.6rem;max-width:min(30rem,92dvw);box-shadow:0 1px 1px color-mix(in srgb,var(--fertig-sh) 8%,transparent),0 28px 60px -22px color-mix(in srgb,var(--fertig-sh) 28%,transparent)}dialog>:last-child:not(footer){margin-bottom:0}dialog,[popover]{overscroll-behavior:contain}dialog::backdrop{background:color-mix(in srgb,var(--fertig-sh) 32%,transparent)}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.6rem;background:var(--fertig-el)}dialog>header{inset-block-start:-1.6rem;margin-block:-1.6rem .35rem;padding:1.6rem 1.6rem .5rem;font-weight:700;border-radius:var(--fertig-rw) var(--fertig-rw) 0 0}dialog:is([open],:modal)>header>:is(h1,h2,h3,h4,p){margin:0;font-family:var(--fertig-f);font-size:1.1rem;font-weight:600;line-height:1.3;letter-spacing:-.01em}dialog>footer{inset-block-end:-1.6rem;margin-block:1.35rem -1.6rem;padding:.5rem 1.6rem 1.6rem;border-radius:0 0 var(--fertig-rw) var(--fertig-rw);display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;justify-content:flex-end}@supports (animation-timeline:scroll()){dialog>header{animation:fertig-rule-under linear both;animation-timeline:scroll(nearest);animation-range:0 1.2rem}dialog>footer{animation:fertig-rule-over linear both;animation-timeline:scroll(nearest);animation-range:calc(100% - 1.2rem) 100%}@keyframes fertig-rule-under{from{box-shadow:none}to{box-shadow:0 1px 0 var(--fertig-bd)}}@keyframes fertig-rule-over{from{box-shadow:0 -1px 0 var(--fertig-bd)}to{box-shadow:none}}}dialog>footer>:is(p,span):first-child{margin:0;margin-inline-end:auto;color:var(--fertig-mut)}@media (prefers-reduced-motion:no-preference) and (update:fast){dialog,dialog::backdrop{transition:opacity var(--fertig-dur-2) var(--fertig-ease-out),translate var(--fertig-dur-2) var(--fertig-ease-out),display var(--fertig-dur-2) allow-discrete,overlay var(--fertig-dur-2) 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 var(--fertig-ease-out),translate .13s var(--fertig-ease-out),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;margin-block:1.1rem}::target-text{background:color-mix(in srgb,var(--fertig-ac) 28%,transparent)}aside{border:1px solid var(--fertig-bd);border-inline-start:3px solid var(--fertig-ac);border-radius:var(--fertig-rw);border-start-start-radius:0;border-end-start-radius:0;background:var(--fertig-el);padding:.7rem 1.1rem;margin-block:1.1rem}progress{width:100%;height:.5rem;border:0;border-radius:var(--fertig-rp);background:var(--fertig-face)}progress::-webkit-progress-bar{background:var(--fertig-face);border-radius:var(--fertig-rp)}progress::-webkit-progress-value{background:var(--fertig-ac);border-radius:var(--fertig-rp)}progress::-moz-progress-bar{background:var(--fertig-ac);border-radius:var(--fertig-rp)}@supports selector(::details-content){@media (prefers-reduced-motion:no-preference) and (update:fast){details{interpolate-size:allow-keywords}details::details-content{block-size:0;overflow:clip;transition:block-size .28s var(--fertig-ease),content-visibility .28s allow-discrete}details[open]::details-content{block-size:auto}}}[role=group]{display:inline-flex;vertical-align:middle;max-inline-size:100%;overflow:auto clip;overscroll-behavior-x:contain}[role=group]>*{border-radius:0;margin-inline-start:-1px;box-shadow:none;min-width:0}[role=group]>:focus-visible{outline-offset:-3px}[role=group]>:first-child{margin-inline-start:0;border-start-start-radius:var(--fertig-rp);border-end-start-radius:var(--fertig-rp)}[role=group]>:last-child{border-start-end-radius:var(--fertig-rp);border-end-end-radius:var(--fertig-rp)}[role=group]>[aria-pressed=true]{background:var(--fertig-face);color:var(--fertig-ac);font-weight:700}[role=group]>:active:not(:disabled){translate:none}[role=tablist]{display:flex;gap:.1rem;border-bottom:1px solid var(--fertig-bd);margin:1.1rem 0}[role=tab]{background:none;border:0;box-shadow:none;min-width:0;color:var(--fertig-mut);padding:.45em .9em;border-radius:var(--fertig-r) var(--fertig-r) 0 0;margin-bottom:-1px}[role=tab]:hover:not(:disabled){background:var(--fertig-face);color:var(--fertig-fg)}[role=tab][aria-selected=true]{color:var(--fertig-fg);box-shadow:inset 0 -2px 0 var(--fertig-ac)}input[type=checkbox][switch],input[type=checkbox][role=switch]{appearance:none;width:2.2em;height:1.3em;border-radius:var(--fertig-rp);border:0;background:color-mix(in srgb,var(--fertig-fg) 20%,transparent);position:relative;cursor:pointer;vertical-align:-.3em;margin-inline-end:.5em}input[switch]::after,input[role=switch]::after{content:"";position:absolute;inset-block-start:.14em;inset-inline-start:.14em;width:1.02em;height:1.02em;border-radius:50%;background:#fff;box-shadow:var(--fertig-up);transition:translate .16s var(--fertig-ease-out)}input[switch]:checked,input[role=switch]:checked{background:var(--fertig-ac)}input[switch]:checked::after,input[role=switch]:checked::after{translate:.9em 0}:is(input[switch],input[role=switch]):checked:dir(rtl)::after{translate:-.9em 0}[popover]{background:var(--fertig-el);color:var(--fertig-fg);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:.35rem;min-width:12rem;max-block-size:60dvh;overflow:auto;font-size:.95em;box-shadow:var(--fertig-up2),0 24px 44px -18px color-mix(in srgb,var(--fertig-sh) 28%,transparent)}@supports (position-area:block-end span-inline-end){[popover]{position:fixed;inset:auto;position-anchor:auto;position-area:block-end span-inline-end;position-try-fallbacks:flip-block,flip-inline;margin:.35rem 0 0}@supports (min-width:anchor-size(width)){[popover]{min-width:max(12rem,anchor-size(width));position-visibility:anchors-visible}}}[popover] :is(ul,menu){list-style:none;padding:0;margin:0}[popover] :is(a,button):not(:disabled){display:block;width:100%;text-align:start;background:none;border:0;box-shadow:none;min-width:0;padding:.4em .6em;text-decoration:none;color:inherit;border-radius:calc(var(--fertig-r) - 2px);font-weight:400}[popover] :is(a,button):hover:not(:disabled){background:var(--fertig-ac);color:var(--fertig-on-ac)}[popover] hr{margin:.3rem 0}nav[aria-label] ol{display:flex;flex-wrap:wrap;gap:.5em;list-style:none;padding:0;font-size:.9em}nav[aria-label] ol li + li::before{content:"/";margin-inline-end:.5em;color:var(--fertig-mut)}[aria-busy=true]{cursor:progress}[aria-busy=true]::before{content:"";display:inline-block;width:.85em;height:.85em;margin-inline-end:.55em;border:2px solid currentColor;border-top-color:transparent;border-radius:50%;vertical-align:-.1em}@media (prefers-reduced-motion:no-preference) and (update:fast){[aria-busy=true]::before{animation:fertig-spin .6s linear infinite}}@keyframes fertig-spin{to{rotate:360deg}}[data-tooltip]{position:relative}[data-tooltip]:is(:hover,:focus-visible,:active)::after{content:attr(data-tooltip);position:absolute;inset-block-end:100%;inset-inline-start:50%;translate:-50% -.45em;z-index:10;white-space:nowrap;pointer-events:none;background:light-dark(#1d1d1f,#3a3a40);color:#f7f8fb;font-size:.8em;padding:.25em .55em;border-radius:var(--fertig-r);box-shadow:var(--fertig-up2)}[data-tooltip]:dir(rtl)::after{translate:50% -.45em}[data-tone=ok]{--fertig-ac:light-dark(var(--fertig-green-700),var(--fertig-green-300))}[data-tone=warn]{--fertig-ac:light-dark(var(--fertig-amber-700),var(--fertig-amber-300))}[data-tone=err]{--fertig-ac:light-dark(var(--fertig-red-700),var(--fertig-red-300))}[data-tone] .badge,.badge[data-tone]{color:var(--fertig-ac);border-color:var(--fertig-ac)}[data-avatar]{display:inline-grid;place-items:center;flex:none;overflow:hidden;inline-size:2.5rem;aspect-ratio:1;border-radius:50%;background:var(--fertig-face);border:1px solid var(--fertig-bd);font-size:.8em;font-weight:700;color:var(--fertig-mut);object-fit:cover}[data-avatar=sm]{inline-size:1.75rem;font-size:.7em}[data-avatar=lg]{inline-size:3.5rem;font-size:1em}[data-skeleton]{color:transparent;border-radius:var(--fertig-r);pointer-events:none;user-select:none;min-height:1em;background:linear-gradient(90deg,var(--fertig-face),color-mix(in srgb,var(--fertig-fg) 9%,var(--fertig-face)),var(--fertig-face));background-size:200% 100%}[data-skeleton] *{visibility:hidden}@media (prefers-reduced-motion:no-preference) and (update:fast){[data-skeleton]{animation:fertig-shimmer 1.4s linear infinite}@keyframes fertig-shimmer{to{background-position:-200% 0}}}dialog[data-side]{max-width:none;margin:0;border-radius:0;padding:1.4rem}dialog[data-side=right]{inset:0 0 0 auto;block-size:100dvh;inline-size:min(28rem,92dvw);border-block:0;border-inline-end:0}dialog[data-side=left]{inset:0 auto 0 0;block-size:100dvh;inline-size:min(28rem,92dvw);border-block:0;border-inline-start:0}dialog[data-side=bottom]{inset:auto 0 0 0;inline-size:100%;max-block-size:85dvh;border-radius:var(--fertig-rw) var(--fertig-rw) 0 0;border-bottom:0}@media (prefers-reduced-motion:no-preference) and (update:fast){dialog[data-side=right]{translate:100% 0}dialog[data-side=left]{translate:-100% 0}dialog[data-side=bottom]{translate:0 100%}dialog[data-side][open]{translate:0 0}@starting-style{dialog[data-side=right][open]{translate:100% 0}dialog[data-side=left][open]{translate:-100% 0}dialog[data-side=bottom][open]{translate:0 100%}}}[popover][data-toast]{position:fixed;inset:auto 1rem 1rem auto;margin:0;min-width:16rem;max-width:min(24rem,92dvw);padding:.8rem 1rem}@supports (position-area:block-end span-inline-end){[popover][data-toast]{position-area:none;inset:auto 1rem 1rem auto;min-width:16rem}}[popover][data-toast-region]{position:fixed;inset:auto 1rem 1rem auto;margin:0;display:flex;flex-direction:column;align-items:flex-end;gap:.6rem;background:none;border:0;box-shadow:none;padding:0;max-block-size:none;overflow:visible;pointer-events:none}[popover][data-toast-region]>[data-toast]{pointer-events:auto;position:static;inset:auto;min-width:16rem;max-width:min(24rem,92dvw);padding:.8rem 1rem;background:var(--fertig-el);color:var(--fertig-fg);border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);font-size:.95em;box-shadow:var(--fertig-up2),0 24px 44px -18px color-mix(in srgb,var(--fertig-sh) 28%,transparent)}@supports (position-area:block-end span-inline-end){[popover][data-toast-region]{position-area:none;inset:auto 1rem 1rem auto}}menu{list-style:none;padding:0;margin:1.1rem 0;border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);background:var(--fertig-el)}menu>li{padding:.55rem .85rem}menu>li + li{border-top:1px solid var(--fertig-bd)}[popover] menu{border:0;padding:0;margin:0;background:none}[popover] menu>li{padding:0}[popover] menu>li + li{border-top:0}nav menu{border:0;background:none;padding:0;margin-block:0 1.2rem}nav menu>li{padding:0}nav menu>li + li{border-top:0}nav menu :is(a,button){display:block;inline-size:100%;text-align:start;padding:.38rem .6rem;border:0;border-radius:var(--fertig-r);background:none;box-shadow:none;font:inherit;color:var(--fertig-fg);text-decoration:none;opacity:.72}nav menu :is(a,button):hover{background:var(--fertig-face);opacity:1}nav menu :is(a,button)[aria-current]{background:var(--fertig-face);color:var(--fertig-ac);font-weight:600;opacity:1}[data-layout=sidebar]{display:grid;gap:1.5rem;align-items:start}@media (width>= 56rem){[data-layout=sidebar]{grid-template-columns:15rem minmax(0,1fr)}[data-layout=sidebar]>:first-child{position:sticky;top:4.5rem}}[data-layout=sidebar]>*{min-width:0}[data-carousel]{display:flex;gap:1rem;overflow-x:auto;padding-bottom:.5rem;scroll-snap-type:x mandatory;overscroll-behavior-x:contain}[data-carousel]>*{scroll-snap-align:start;flex:0 0 min(20rem,82%)}.muted{color:var(--fertig-mut)}.center{text-align:center}.wide{max-width:80rem}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav.wide{max-width:none;--fertig-nw:80rem}.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))}.grid + *{margin-top:1.1rem}.card{container-type:inline-size;border:1px solid var(--fertig-bd);border-radius:var(--fertig-rw);padding:1.1rem;background:var(--fertig-el);box-shadow:var(--fertig-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:38rem}.hidden{display:none}.badge{border:1px solid var(--fertig-bd);border-radius:var(--fertig-rp);background:var(--fertig-face);padding:.1em .6em;font:700 var(--fertig-caps);color:var(--fertig-mut);text-transform:uppercase;letter-spacing:.07em}.card>:is(header,footer){margin-inline:-1.1rem;padding-inline:1.1rem}.card>header{margin-top:-.25rem;padding-bottom:.7rem;font-weight:600;border-bottom:1px solid var(--fertig-bd)}.card>footer{margin-top:auto;margin-bottom:-.25rem;padding-top:.7rem;color:var(--fertig-mut);font-size:.85em;border-top:1px solid var(--fertig-bd)}.card>:is(img,video):first-child{align-self:stretch;width:auto;max-width:none;margin:-1.1rem -1.1rem 0;aspect-ratio:16 / 9;object-fit:cover;border:0;border-radius:var(--fertig-rw) var(--fertig-rw) 0 0;box-shadow:none}.card[data-tone]{background:linear-gradient(var(--fertig-ac),var(--fertig-ac)) top / 100% 3px no-repeat,var(--fertig-el)}: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(--fertig-ac) 45%,var(--fertig-bd));box-shadow:var(--fertig-up2),0 16px 30px -16px color-mix(in srgb,var(--fertig-sh) 28%,transparent);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-block-start:4rem}:is(h1,h2,h3,h4):target{background:color-mix(in srgb,var(--fertig-ac) 12%,transparent)}a[target=_blank]:not(:has(>img,>svg))::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(--fertig-ac)}del{color:var(--fertig-mut)}address{font-style:normal;color:var(--fertig-mut)}hgroup>*{margin:0}hgroup>p{color:var(--fertig-mut)}output{font-weight:700}meter{width:100%;height:.5rem}optgroup{font-weight:700;color:var(--fertig-mut)}::file-selector-button{margin-inline-end:.8em}::file-selector-button:hover{background:var(--fertig-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(--fertig-ac)}:is(pre,table,textarea,dialog,[popover],menu,fieldset,[role=group],[data-carousel],[data-layout=sidebar]>*){scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--fertig-fg) 25%,transparent) transparent}@page{margin:2cm}@media print{:root{--fertig-bg:#fff;--fertig-el:#fff;--fertig-fg:#000;--fertig-bd:#999}:is(body,body>:where(#root,#app,#__next,[data-fertig]))>nav{display:none}body>*,body>:where(#root,#app,#__next,[data-fertig])>*{border:0}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}:is(button,a,input,select,label)[data-size=sm]{min-height:32px}}@media (inverted-colors:inverted){img,video,iframe{filter:invert(1) hue-rotate(180deg)}}@media (color-gamut:p3){@supports (color:oklch(60% .2 250)){:root{--fertig-ac:light-dark(oklch(52% .21 258),oklch(76% .15 258))}}}:root{text-spacing-trim:trim-start;text-autospace:normal}@media (prefers-contrast:more){:root{--fertig-bd:light-dark(#00000059,#ffffff6b);--fertig-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],.card,.badge,[role=tab],[role=group]>*,[popover] :is(a,button){transition:box-shadow var(--fertig-dur-1) var(--fertig-ease),background-color var(--fertig-dur-1) var(--fertig-ease),border-color var(--fertig-dur-1) var(--fertig-ease),color var(--fertig-dur-1) var(--fertig-ease),translate .08s var(--fertig-ease-out)}:focus-visible{transition:none}}@supports not (color:light-dark(#000,#fff)){:root{--fertig-bg:#e6eaef;--fertig-el:#fafcfe;--fertig-face:#f3f6fa;--fertig-fg:#151b24;--fertig-mut:#525962;--fertig-bd:#151b2421;--fertig-tb:#f3f6fa;--fertig-ac:#2850de;--fertig-on-ac:#f7f8fb}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--fertig-bg:#090c12;--fertig-el:#141920;--fertig-face:#1c222a;--fertig-fg:#eaeff7;--fertig-mut:#9da5b1;--fertig-bd:#eaeff721;--fertig-tb:#1c222a;--fertig-ac:#90b5ff;--fertig-on-ac:#07071c}}[data-theme=dark]{--fertig-bg:#090c12;--fertig-el:#141920;--fertig-face:#1c222a;--fertig-fg:#eaeff7;--fertig-mut:#9da5b1;--fertig-bd:#eaeff721;--fertig-tb:#1c222a;--fertig-ac:#90b5ff;--fertig-on-ac:#07071c}}}@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]{border-bottom:2px solid Highlight}button[aria-pressed=true]{border-color:Highlight}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fertig",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.4",
|
|
4
4
|
"description": "A classless CSS stylesheet with no legacy in it: no polyfills, no required classes. Link one file, write ordinary HTML, done — 8.6 KB gzipped, no build step, no dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fertig",
|
|
@@ -55,7 +55,6 @@
|
|
|
55
55
|
"fertig.css",
|
|
56
56
|
"fertig.min.css",
|
|
57
57
|
"README.md",
|
|
58
|
-
"CHANGELOG.md",
|
|
59
58
|
"LICENSE"
|
|
60
59
|
],
|
|
61
60
|
"scripts": {
|
|
@@ -67,14 +66,14 @@
|
|
|
67
66
|
"check:site": "npm run site && node tools/check-site.js",
|
|
68
67
|
"check:package": "npm pack --dry-run --ignore-scripts",
|
|
69
68
|
"hooks:install": "git config core.hooksPath .githooks",
|
|
70
|
-
"site": "
|
|
71
|
-
"site
|
|
72
|
-
"site:
|
|
73
|
-
"dev": "
|
|
69
|
+
"site:prepare": "node tools/prepare-site.mjs",
|
|
70
|
+
"site": "npm run site:prepare && astro build",
|
|
71
|
+
"site:serve": "npm run site:prepare && astro dev",
|
|
72
|
+
"dev": "npm run site:serve",
|
|
74
73
|
"prepublishOnly": "node build.js",
|
|
75
74
|
"sizes": "python3 tools/sizes.py"
|
|
76
75
|
},
|
|
77
76
|
"devDependencies": {
|
|
78
|
-
"
|
|
77
|
+
"astro": "^5.18.2"
|
|
79
78
|
}
|
|
80
79
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,470 +0,0 @@
|
|
|
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
|
-
## Unreleased
|
|
10
|
-
|
|
11
|
-
## [4.0.2] — 2026-09-01
|
|
12
|
-
|
|
13
|
-
### Changed
|
|
14
|
-
|
|
15
|
-
- **Body-level page containers are full width by default.** fertig keeps the
|
|
16
|
-
responsive page gutter but no longer applies a maximum width to direct body
|
|
17
|
-
children or supported app-root children. Explicit `max-w-*`
|
|
18
|
-
utilities remain available when a page needs a constrained measure.
|
|
19
|
-
|
|
20
|
-
## [4.0.1] — 2026-09-01
|
|
21
|
-
|
|
22
|
-
### Changed
|
|
23
|
-
|
|
24
|
-
- **Buttons are flat and stay put.** The raised shadow, filled-button highlight
|
|
25
|
-
and active press nudge are gone. Hover contrast, focus-visible outlines,
|
|
26
|
-
disabled feedback and coarse-pointer target sizing remain intact.
|
|
27
|
-
- **The public documentation speaks only about fertig.** Comparative product
|
|
28
|
-
names, size rankings and survey links were removed from every published page.
|
|
29
|
-
|
|
30
|
-
### Fixed
|
|
31
|
-
|
|
32
|
-
- **Shared mobile controls now have reliable touch targets.** Navigation,
|
|
33
|
-
theme, colour, catalogue filter and sidebar controls reach 44 by 44 pixels;
|
|
34
|
-
catalogue filters stay in one horizontal row instead of building a tall
|
|
35
|
-
stack on narrow screens.
|
|
36
|
-
- **Theme and copy feedback are clearer.** The theme control names its target,
|
|
37
|
-
while clipboard fallbacks select the text and use platform-neutral wording.
|
|
38
|
-
|
|
39
|
-
## [4.0.0] — 2026-09-01
|
|
40
|
-
|
|
41
|
-
### Changed
|
|
42
|
-
|
|
43
|
-
- **The palette is new and intentionally direct.** `gray`, `blue`, `cyan`,
|
|
44
|
-
`green`, `amber`, `red` and `violet` replace the former
|
|
45
|
-
`stone/sage/sky/clay/plum/gold` ramps. Each ships at 100/300/500/700/900,
|
|
46
|
-
stays inside sRGB and uses a consistent OKLCH progression. Blue is the new
|
|
47
|
-
default accent; `ok`, `warn` and `err` now map directly to green, amber and
|
|
48
|
-
red.
|
|
49
|
-
- **The default finish is platform-neutral.** Opaque toolbar and surface
|
|
50
|
-
colors, restrained 8px control geometry, ordinary rounded buttons and generic
|
|
51
|
-
system font fallbacks replace the OS-specific translucent treatment. The
|
|
52
|
-
optional squircle enhancement and decorative backdrop blur are gone.
|
|
53
|
-
- **The default hierarchy is clearer and the page gutter is responsive.**
|
|
54
|
-
`h1` and `h2` now use a restrained fluid type scale, while the new
|
|
55
|
-
`--fertig-g` token grows from 1.15rem on narrow phones to 1.9rem on larger
|
|
56
|
-
screens. Desktop density is unchanged; small screens recover useful space.
|
|
57
|
-
- **The generic toolbar stays composed on phones.** A navigation list gets one
|
|
58
|
-
horizontally scrollable row beneath the identity and trailing control instead
|
|
59
|
-
of wrapping around them in an uneven cluster.
|
|
60
|
-
|
|
61
|
-
### Removed
|
|
62
|
-
|
|
63
|
-
- **The former palette and named accents.** Old ramp tokens and
|
|
64
|
-
`data-accent="indigo|sky|sage|clay|plum|gold|slate"` are not retained as
|
|
65
|
-
aliases. Use `data-accent="blue|cyan|green|amber|red|violet|gray"`.
|
|
66
|
-
- **Legacy mockup pages and static social-preview screenshots.** The site build
|
|
67
|
-
no longer copies them or emits metadata pointing at deleted preview images.
|
|
68
|
-
|
|
69
|
-
### Fixed
|
|
70
|
-
|
|
71
|
-
- **Responsive tables scroll before their cells become unreadable.** Below
|
|
72
|
-
40rem, cell content keeps its intrinsic width inside the existing table scroll
|
|
73
|
-
container instead of wrapping almost word-by-word.
|
|
74
|
-
- **Size synchronization cannot rewrite third-party measurements.** Published
|
|
75
|
-
claims are now an explicit manifest of fertig-specific contexts. A changed or
|
|
76
|
-
missing context fails the command, and a regression test protects unrelated
|
|
77
|
-
values that happen to match fertig's previous size.
|
|
78
|
-
|
|
79
|
-
## [3.1.0] — 2026-09-01
|
|
80
|
-
|
|
81
|
-
### Changed
|
|
82
|
-
|
|
83
|
-
- **The 72rem default is now a page shell, not a prose measure.**
|
|
84
|
-
`.max-w-prose` keeps long-form copy at 38rem, while `.wide` provides an 80rem
|
|
85
|
-
application column. The documentation and customiser now use the same
|
|
86
|
-
defaults and terminology as the stylesheet.
|
|
87
|
-
- **The documentation toolbar stays compact on phones.** Its primary controls
|
|
88
|
-
occupy the first row and its links scroll horizontally on the second instead
|
|
89
|
-
of wrapping into a tall stack. The Components page is now present in the
|
|
90
|
-
shared navigation.
|
|
91
|
-
|
|
92
|
-
### Fixed
|
|
93
|
-
|
|
94
|
-
- **The minified build preserves descendant selectors.** The old punctuation
|
|
95
|
-
regex changed selectors such as `nav :is(…)` into `nav:is(…)`, silently
|
|
96
|
-
breaking row controls and popover menus. The minifier now understands CSS
|
|
97
|
-
strings and comments, with focused regression tests for both failure modes.
|
|
98
|
-
- **Reduced-transparency preferences reach framework wrappers.** A toolbar
|
|
99
|
-
inside `#root`, `#app`, `#__next` or `[data-fertig]` now drops its backdrop
|
|
100
|
-
blur just like a toolbar that is a direct child of `body`.
|
|
101
|
-
|
|
102
|
-
## [3.0.0] — 2026-08-31
|
|
103
|
-
|
|
104
|
-
The breaking change is one mechanical line: **every public token now carries a
|
|
105
|
-
`--fertig-` prefix, and the old names are gone** — no aliases, no shims. The
|
|
106
|
-
classes, the layout utilities and the ARIA attributes the component layer reads
|
|
107
|
-
are all untouched. The sheet does exactly what it did; the migration is a
|
|
108
|
-
rename.
|
|
109
|
-
|
|
110
|
-
`--fertig-a1` / `--fertig-a2` already carried the prefix for the reason the rest
|
|
111
|
-
receive it now: a short, unprefixed custom property is a bet you only lose
|
|
112
|
-
once. `--ac` collided with your own `--ac`; the prefix makes every token yours
|
|
113
|
-
to override, and no future rename is ever needed again.
|
|
114
|
-
|
|
115
|
-
**To migrate:** prefix whatever you override. `--w` → `--fertig-w`,
|
|
116
|
-
`--ac` / `--on-ac` → `--fertig-ac` / `--fertig-on-ac`, the radii
|
|
117
|
-
`--r` / `--rs` / `--rw` → `--fertig-*`, the surfaces (`--bg`, `--el`, `--face`,
|
|
118
|
-
`--fg`, `--mut`, `--bd`, `--tb`, `--nw`), the depth tokens (`--up`, `--up2`,
|
|
119
|
-
`--dn`, `--sh`, `--sh1`, `--sh2`, and the `@property` alphas `--a1` / `--a2`),
|
|
120
|
-
the motion tokens (`--ease`, `--ease-in`, `--ease-out`, `--dur-1`, `--dur-2`),
|
|
121
|
-
`--caps`, and the colour ramps (`--stone-*`, `--sage-*`, `--sky-*`, `--clay-*`,
|
|
122
|
-
`--plum-*`, `--gold-*`). The rule is one line: **any `--name` you set becomes
|
|
123
|
-
`--fertig-name`.** Nothing changed meaning.
|
|
124
|
-
|
|
125
|
-
### Changed
|
|
126
|
-
|
|
127
|
-
- **The palette moves to a cooler voice.** Neutrals are a cool graphite
|
|
128
|
-
(hue ≈ 258) with a faint violet cast, replacing the warm stone; the accent is
|
|
129
|
-
a violet-blue (hue 266), replacing indigo. Measured: the accent clears 6.21:1
|
|
130
|
-
as link text on paper and 6.39:1 for a white label on the fill in light,
|
|
131
|
-
8.62:1 in dark — both sit inside sRGB. The
|
|
132
|
-
`@supports not (color: light-dark(…))` flat-sRGB fallback is restated to match,
|
|
133
|
-
and every pair still clears WCAG AA in both schemes.
|
|
134
|
-
- **Buttons are fully rounded.** The shared button rule takes a new
|
|
135
|
-
`--fertig-rp` (pill) token instead of the control radius. It matches the
|
|
136
|
-
badge, the switch and the progress bar, which were already pills. Set
|
|
137
|
-
`--fertig-rp: var(--fertig-r)` for square-shouldered buttons.
|
|
138
|
-
- **One radius, and the rest derived from it.** `--fertig-r` (12px) is the base;
|
|
139
|
-
`--fertig-rs` is `calc(var(--fertig-r) * .5)` and `--fertig-rw` is
|
|
140
|
-
`calc(var(--fertig-r) * 1.33)`, so setting the base on `:root` rescales the
|
|
141
|
-
whole sheet instead of desynchronising it. Windows — cards, dialogs, popover
|
|
142
|
-
menus, the select picker, `pre`, `details`, `fieldset`, `aside`, toasts —
|
|
143
|
-
now take `--fertig-rw` rather than the control radius, and full-bleed card
|
|
144
|
-
media follows the card it bleeds into.
|
|
145
|
-
- **Badges are uppercase.** They already used the caps *size*; they never got
|
|
146
|
-
the transform that `h5`, `h6` and `th` get.
|
|
147
|
-
- **The dialog lost its banded rules.** No hairline under the header or over
|
|
148
|
-
the footer by default; the separation is spacing. The rule now arrives as
|
|
149
|
-
scroll state — a scroll-driven animation fades it in under the header once the
|
|
150
|
-
body has scrolled and out of the footer at the end — so a dialog that fits
|
|
151
|
-
shows no rules at all. Title takes `--fertig-f`, the interface face, at
|
|
152
|
-
600/1.1rem: a monospaced heading font reads as a terminal on a dialog.
|
|
153
|
-
- **The `err` tone is red, not clay.** `[data-tone=err]` borrowed
|
|
154
|
-
`--fertig-clay-700`, which at 50% lightness reads brown on a destructive
|
|
155
|
-
button. Now `oklch(52% .16 27)` / `oklch(74% .13 25)` — 5.97:1 with the white
|
|
156
|
-
label, and `--fertig-on-ac` still derives correctly in both themes.
|
|
157
|
-
- **The select picker animates open and closed**, with `display` and `overlay`
|
|
158
|
-
transitioned discretely so the close is not a pop.
|
|
159
|
-
|
|
160
|
-
### Fixed
|
|
161
|
-
|
|
162
|
-
- **`accent-color` and `caret-color` ignored every local accent.** Both were
|
|
163
|
-
declared once on `:root`. They are inherited properties, so they resolved
|
|
164
|
-
there against the root accent and every descendant inherited that *computed
|
|
165
|
-
colour* — a `[data-accent]` or `[data-tone]` subtree repainted its buttons and
|
|
166
|
-
links but left its checkboxes, radios, ranges and caret on the root's tint.
|
|
167
|
-
Both are now re-declared on the elements that consume them.
|
|
168
|
-
- **The segmented control showed a vertical scrollbar.** `overflow-x: auto`
|
|
169
|
-
makes `overflow-y` compute to `auto` as well, and Safari paints a scrollbar
|
|
170
|
-
for a sub-pixel of overflow. The block axis is now clipped (`overflow: auto
|
|
171
|
-
clip`), and group children take their focus ring inside the edge
|
|
172
|
-
(`outline-offset: -3px`) so the clip cannot slice it.
|
|
173
|
-
- **The `<select>` marker was a different shape per engine.** Engines without
|
|
174
|
-
`appearance: base-select` fell back to a solid filled triangle while the
|
|
175
|
-
styleable picker drew a thin chevron. The fallback now draws the same
|
|
176
|
-
stroked chevron.
|
|
177
|
-
- **The docs site is built with Eleventy.** The pages moved out of hand-edited
|
|
178
|
-
HTML at the repo root into `src/` templates that build to `dist/`, with the
|
|
179
|
-
version flowing from `package.json` as the single source of truth. This is how
|
|
180
|
-
the sheet's own site is maintained; it is not part of the npm package, which
|
|
181
|
-
ships the two CSS files plus the README and licence.
|
|
182
|
-
- **The demo template pages are gone.** `app.html`, `app-invoice.html` and the
|
|
183
|
-
whole `templates/` set (`dashboard`, `article`, `pricing`, `signin`) are
|
|
184
|
-
removed from the site and repo; the docs no longer point at them.
|
|
185
|
-
|
|
186
|
-
## [2.0.0] — 2026-08-31
|
|
187
|
-
|
|
188
|
-
### Breaking
|
|
189
|
-
|
|
190
|
-
- **`--a1` / `--a2` are now `--fertig-a1` / `--fertig-a2`, with no alias.**
|
|
191
|
-
These are `@property` registrations, and a registration is global — it cannot
|
|
192
|
-
be layered, scoped or overridden. A two-character name meant a consumer's own
|
|
193
|
-
`--a1` was silently retyped to `<number>`, which is a bug that only a rename
|
|
194
|
-
can fix.
|
|
195
|
-
|
|
196
|
-
**To migrate:** if you set `--a1` or `--a2`, rename them. Nothing else
|
|
197
|
-
changes — the values mean the same thing and the elevation scale is
|
|
198
|
-
untouched. If you never set them, there is nothing to do.
|
|
199
|
-
|
|
200
|
-
Every other token name is unchanged. They are ordinary custom properties,
|
|
201
|
-
they are the documented API, and they are deliberately short.
|
|
202
|
-
|
|
203
|
-
A visual refresh, an audit pass, and a component-first repositioning. One token
|
|
204
|
-
rename aside, the surface is the same — the same classes and attributes — but
|
|
205
|
-
the default look changes visibly, so treat this as a redesign rather than a
|
|
206
|
-
drop-in bump.
|
|
207
|
-
|
|
208
|
-
### Added
|
|
209
|
-
|
|
210
|
-
- **Named accents.** `data-accent="indigo|sky|sage|clay|plum|gold|slate"` on any
|
|
211
|
-
element retints everything inside it: links, focus rings, filled buttons, the
|
|
212
|
-
caret, the selection. Scoped rather than global, so one section can differ
|
|
213
|
-
from the rest of a page. Each pair is measured — the light tone clears AA as
|
|
214
|
-
link text on paper, the dark tone clears it on the dark ground.
|
|
215
|
-
- **Motion tokens.** `--ease-out`, `--ease-in`, `--ease` and the durations
|
|
216
|
-
`--dur-1` / `--dur-2`. The sheet had been animating with a bare `ease`, which
|
|
217
|
-
is the browser default and the flattest curve available.
|
|
218
|
-
- `--rs`, a small radius for inline chips and code, so they do not inherit the
|
|
219
|
-
larger control radius and read as lozenges.
|
|
220
|
-
|
|
221
|
-
### Changed
|
|
222
|
-
|
|
223
|
-
- **The default accent is indigo**, not the desaturated navy it was. Measured
|
|
224
|
-
6.28:1 as link text on paper and 6.39:1 for a white label on the fill in
|
|
225
|
-
light; 8.72:1 and 10.26:1 in dark. Both sit inside sRGB.
|
|
226
|
-
- **Cards no longer paint a tinted strip behind their header and footer.** A
|
|
227
|
-
filled bar across the top of a card is the old panel-heading pattern and is
|
|
228
|
-
what dated the sheet on sight; a hairline separates just as well and lets the
|
|
229
|
-
card read as one surface.
|
|
230
|
-
- Radii up: `--r` 6px → 9px, `--rw` 10px → 14px. Controls have more room —
|
|
231
|
-
buttons and fields gained roughly a tenth of an em of padding.
|
|
232
|
-
- More things transition, on the named curves: tabs, badges, cards, segmented
|
|
233
|
-
controls and popover items, alongside the controls that already did.
|
|
234
|
-
`:focus-visible` is explicitly excluded — a focus ring has to be there the
|
|
235
|
-
instant focus lands, not fade in after it.
|
|
236
|
-
|
|
237
|
-
### Fixed
|
|
238
|
-
|
|
239
|
-
- The tone bar on `.card[data-tone]` follows the corner radius again. It was an
|
|
240
|
-
inset shadow, which does not track the curve cleanly at the larger radius —
|
|
241
|
-
it read as a detached line with gaps at both top corners. It is a background
|
|
242
|
-
layer now, which the radius clips. The duplicate indicator on
|
|
243
|
-
`.card > header` is gone with it: the filled header used to hide it, and
|
|
244
|
-
without the fill both were painting.
|
|
245
|
-
- Navigation lists. `[data-layout=sidebar]` shipped without any styling for the
|
|
246
|
-
nav inside it, so the obvious markup — a `<menu>` in a `<nav>` — came out as
|
|
247
|
-
a boxed list group. It is navigation now: no rules between items, no bullets,
|
|
248
|
-
and the link fills the row.
|
|
249
|
-
- `aside` and `search` are block landmarks that had no vertical rhythm of their
|
|
250
|
-
own, so whatever followed sat flush against them.
|
|
251
|
-
|
|
252
|
-
### Fixed — audit pass
|
|
253
|
-
|
|
254
|
-
An audit pass. Everything here came out of `docs/known-flaws.md`, which lists
|
|
255
|
-
what was found, what was verified in a browser, and what was left alone on
|
|
256
|
-
purpose.
|
|
257
|
-
|
|
258
|
-
- **The shell survives a framework wrapper.** The page shell was `body > *`, so
|
|
259
|
-
a React, Vue, Svelte or Next app rendering into `<div id="root">` lost the
|
|
260
|
-
measure, the paper surface and the gutters with nothing on screen to say why.
|
|
261
|
-
The shell now also matches the children of a single `#root`, `#app`,
|
|
262
|
-
`#__next` or `[data-fertig]` wrapper. Every added selector sits inside
|
|
263
|
-
`:where()`, so specificity is unchanged.
|
|
264
|
-
- **A floor under the floor.** Every colour token was an unguarded
|
|
265
|
-
`light-dark()`. In an engine without it the tokens were invalid at
|
|
266
|
-
computed-value time, so backgrounds went transparent and colour was
|
|
267
|
-
inherited — a page could land unreadable rather than plain. A
|
|
268
|
-
`@supports not (color: light-dark(…))` block at the end of the layer restates
|
|
269
|
-
the palette in flat sRGB, in both schemes.
|
|
270
|
-
- **`data-size`, `data-variant` and `data-block` are scoped to controls.** As
|
|
271
|
-
bare attribute selectors they restyled any element carrying those very common
|
|
272
|
-
attribute names — a `<span data-size="sm">` picked up button padding.
|
|
273
|
-
- **The focus ring no longer reshapes what it rings.** `:focus-visible` set
|
|
274
|
-
`border-radius: var(--r)`, which is the element's own radius, not the ring's:
|
|
275
|
-
a focused `<dialog>` snapped from `--rw` (14px) to `--r` (9px). Outlines
|
|
276
|
-
already follow the element's corners, so the declaration is simply gone.
|
|
277
|
-
- **`<svg>` stays inline.** It was in the `display: block` rule with `img`,
|
|
278
|
-
`video` and `iframe`, which dropped every inline icon onto its own line.
|
|
279
|
-
- **Toasts can stack.** Two `[popover][data-toast]` elements shared one set of
|
|
280
|
-
corner coordinates and overlapped, and an open popover is in the top layer so
|
|
281
|
-
no ordinary wrapper could stack them. `<div popover="manual"
|
|
282
|
-
data-toast-region>` is now the popover, with a `<div data-toast>` per message.
|
|
283
|
-
- **A selected tab is visible in Windows High Contrast.** Its cue was a
|
|
284
|
-
`box-shadow` that the forced-colors layer removes, and the replacement set
|
|
285
|
-
`border-color` on an element with `border: 0`. It now sets a real
|
|
286
|
-
`border-bottom`.
|
|
287
|
-
- **`--on-ac` survives a custom `--ac` in shipping browsers.** The
|
|
288
|
-
`contrast-color()` guard is real but almost nothing implements it. A relative
|
|
289
|
-
colour branch reaches the same black-or-white decision from the accent's own
|
|
290
|
-
lightness, and has been cross-engine since 2024.
|
|
291
|
-
- **`interpolate-size: allow-keywords` is set on `details`, not `:root`.** It is
|
|
292
|
-
inherited, so the old placement changed how *your* `height: auto` transitions
|
|
293
|
-
behaved as a side effect of animating a disclosure.
|
|
294
|
-
- **Two universal rules narrowed to what the sheet actually styles.**
|
|
295
|
-
`scrollbar-width: thin` no longer thins the page's own scrollbar (a
|
|
296
|
-
target-size problem for imprecise pointers), and `corner-shape: squircle` no
|
|
297
|
-
longer reshapes your components.
|
|
298
|
-
- **`input[type=image]` is a button, not a text field.** It was missing from the
|
|
299
|
-
`:not()` list and got full-width sunken-field treatment.
|
|
300
|
-
- **The tooltip is flow-relative and reachable on touch** — logical inset
|
|
301
|
-
properties with a `:dir(rtl)` offset, and `:active` alongside `:hover`. It is
|
|
302
|
-
still decorative, and now says so in the sheet, the README and the docs.
|
|
303
|
-
- **`a[target=_blank]`** no longer appends an arrow to a link wrapping an image.
|
|
304
|
-
- **Print keeps the footer.** It was hidden along with the toolbar, which drops
|
|
305
|
-
the legal line, the contact and the citations from every printout.
|
|
306
|
-
- **The small variant stays small on touch.** `(pointer: coarse)` forced
|
|
307
|
-
`min-height: 44px` on everything; `data-size="sm"` opts down to 32px, still
|
|
308
|
-
above the 24px WCAG 2.5.8 floor.
|
|
309
|
-
- `package.json`'s size claim, the one string `tools/sizes.py` does not reach.
|
|
310
|
-
|
|
311
|
-
### Changed
|
|
312
|
-
|
|
313
|
-
- `--a1` / `--a2` renamed — see **Breaking** above.
|
|
314
|
-
|
|
315
|
-
## [1.0.3] — 2026-08-30
|
|
316
|
-
|
|
317
|
-
### Changed
|
|
318
|
-
|
|
319
|
-
- `--mut` lifted from 50%/70% lightness to 47%/73%. The weakest muted pairing
|
|
320
|
-
— on the desktop ground in light, on chrome in dark — was 4.96:1 and 5.99:1,
|
|
321
|
-
a hair over AA; it is 5.65:1 and 6.70:1 now. Not taken to AAA, which would need 41.5%: that
|
|
322
|
-
is close enough to `--fg` that muted text stops reading as secondary at all.
|
|
323
|
-
|
|
324
|
-
### Added
|
|
325
|
-
|
|
326
|
-
- `--nw`, the column the toolbar's contents line up with. It follows `--w`, so
|
|
327
|
-
nothing changes by default, and `<nav class="wide">` re-points it at the wide
|
|
328
|
-
column — an app screen built on `.wide` no longer gets a wordmark floating in
|
|
329
|
-
the middle of the viewport while its content spans the full width.
|
|
330
|
-
|
|
331
|
-
### Fixed
|
|
332
|
-
|
|
333
|
-
- Breadcrumb separators no longer leak into other navigation. The `/` was on
|
|
334
|
-
`nav[aria-label] li + li`, so any labelled `<nav>` containing a `<ul>` — an
|
|
335
|
-
ordinary sidebar — got breadcrumb slashes between its links. Scoped to `ol`,
|
|
336
|
-
matching the layout rule directly above it and the documented markup.
|
|
337
|
-
- A `.grid` no longer collides with the block that follows it. It is a
|
|
338
|
-
block-level container and nothing gave it vertical rhythm. The space is on
|
|
339
|
-
`.grid + *` rather than a margin on `.grid` itself, which would collapse out
|
|
340
|
-
through the top of a padding-less container and open a seam above it.
|
|
341
|
-
- A segmented control (`role="group"`) with four or more buttons no longer
|
|
342
|
-
pushes the page sideways on a narrow screen. It scrolls within its own width
|
|
343
|
-
instead of wrapping, which would break the joined run of corner radii.
|
|
344
|
-
- A `<dl>` with a long value no longer widens the page. The value column was
|
|
345
|
-
a bare `1fr`, whose automatic minimum is its content, so it could not shrink;
|
|
346
|
-
it is `minmax(0, 1fr)` now.
|
|
347
|
-
|
|
348
|
-
## [1.0.2] — 2026-08-30
|
|
349
|
-
|
|
350
|
-
### Fixed
|
|
351
|
-
|
|
352
|
-
- Menus and toasts no longer jump across the viewport as they close. The anchor
|
|
353
|
-
positioning was scoped to `[popover]:popover-open`, but the close is
|
|
354
|
-
transitioned (`display .13s allow-discrete`), so for those 130ms the popover
|
|
355
|
-
still painted while no longer matching the selector — falling back to the UA's
|
|
356
|
-
centred `inset: 0` and visibly flying to the middle of the screen. Both the
|
|
357
|
-
menu and the `[data-toast]` corner override now sit on the base selector.
|
|
358
|
-
|
|
359
|
-
## [1.0.1] — 2026-08-30
|
|
360
|
-
|
|
361
|
-
Packaging only; the stylesheet is unchanged apart from its version banner.
|
|
362
|
-
|
|
363
|
-
### Changed
|
|
364
|
-
|
|
365
|
-
- `homepage` points at the documentation site rather than the README, and the
|
|
366
|
-
repository URLs follow the repo's rename to `moji2002/fertig`.
|
|
367
|
-
- `fertig` and `fertig.css` added as keywords: the package is `fertig`, but
|
|
368
|
-
people search npm for the project's name.
|
|
369
|
-
|
|
370
|
-
## [1.0.1] - 2026-08-30
|
|
371
|
-
|
|
372
|
-
### Changed
|
|
373
|
-
|
|
374
|
-
- npm keywords only: added `css-framework`, `lightweight`, `minimalist`, `html`,
|
|
375
|
-
`frontend`, `ui` and `responsive`. `css-framework` is the term the rest of the
|
|
376
|
-
category (Pico, Water.css) registers under, and it was missing. No stylesheet
|
|
377
|
-
changes — the CSS is byte-identical to 1.0.0.
|
|
378
|
-
|
|
379
|
-
## [1.0.0] — 2026-08-30
|
|
380
|
-
|
|
381
|
-
First release. The project and the npm package are `fertig`. The stylesheet
|
|
382
|
-
file keeps the name `fertig.css`, because it is a CSS file, and the cascade
|
|
383
|
-
layer is `@layer fertig` — a dot in a layer name would declare a sub-layer.
|
|
384
|
-
|
|
385
|
-
### Added
|
|
386
|
-
|
|
387
|
-
- Classless styling for the full semantic element set: headings, prose, lists,
|
|
388
|
-
description lists, quotes, rules, code, tables, every form control,
|
|
389
|
-
fieldsets, buttons, details, dialog, figures, media and asides.
|
|
390
|
-
- Layout model where direct children of `<body>` are containers — `<nav>` is a
|
|
391
|
-
full-bleed toolbar with a vibrancy blur, and
|
|
392
|
-
`header`/`main`/`footer` are the page.
|
|
393
|
-
- Light and dark themes from a single `light-dark()` token block, with
|
|
394
|
-
`data-theme="light|dark"` to override the OS preference.
|
|
395
|
-
- Elevation scale (`--up`, `--up2`, `--dn`) whose shadow alphas step up in dark
|
|
396
|
-
mode, since a shadow on a dark ground reads as nothing on its own. The
|
|
397
|
-
shadows come off a real colour token (`--sh`) through relative colour syntax,
|
|
398
|
-
not an HSL triplet you could not use directly.
|
|
399
|
-
- Component layer addressed by ARIA rather than by class: segmented controls
|
|
400
|
-
(`role="group"`), tabs (`role="tablist"`), switches (`role="switch"`),
|
|
401
|
-
`[popover]` menus anchored to their invoker, breadcrumbs, `<dialog>` with an
|
|
402
|
-
entrance transition, `aria-busy` spinners and `data-tooltip`.
|
|
403
|
-
- Button variants (`data-variant`, `data-size`, `data-icon`, `data-block`) and
|
|
404
|
-
card anatomy (`<header>`/`<footer>`, full-bleed media, `data-tone`,
|
|
405
|
-
`<a class="card">` hover lift).
|
|
406
|
-
- Seven optional classes: `.row`, `.grid`, `.card`, `.badge`, `.muted`,
|
|
407
|
-
`.center`, `.wide`.
|
|
408
|
-
- Dialog anatomy: an optional `<header>` and `<footer>` that run edge to edge
|
|
409
|
-
and stay pinned while the body scrolls. Sticky rather than a grid, because a
|
|
410
|
-
classless sheet has no wrapper around the loose middle children to make a
|
|
411
|
-
grid row out of; the sticky offsets are negative so the chrome pins to the
|
|
412
|
-
dialog's border edge rather than its padding edge, which is where content
|
|
413
|
-
would otherwise scroll through.
|
|
414
|
-
- A max-width scale on Tailwind's names — `.max-w-xs` through `.max-w-7xl`,
|
|
415
|
-
plus `.max-w-full`, `.max-w-none` and `.max-w-prose`. Whole rather than
|
|
416
|
-
partial: a scale where `.max-w-2xl` works and `.max-w-3xl` silently does not
|
|
417
|
-
is worse than no scale. They are `max-inline-size`, so they still mean
|
|
418
|
-
"along the text" in a vertical writing mode.
|
|
419
|
-
- Layout utilities, named after Tailwind's so the names transfer: `.flex`,
|
|
420
|
-
`.flex-col`, `.flex-wrap`, `.flex-1`, `.grid-cols-2|3|4`,
|
|
421
|
-
`.items-start|center|end`, `.justify-start|center|end|between`,
|
|
422
|
-
`.gap-0|1|2|3|4|6`, `.mx-auto`, `.ms-auto`, `.me-auto`, `.w-full`,
|
|
423
|
-
`.hidden`. Layout only — no colour, type or sizing scale, and no responsive
|
|
424
|
-
variants, which would need a build step.
|
|
425
|
-
- Right-to-left support. Every inline-direction rule is flow-relative, with
|
|
426
|
-
`:dir(rtl)` rules for the two that cannot be — the switch knob's `translate`
|
|
427
|
-
and the fallback `<select>` chevron's background position. Verified by
|
|
428
|
-
rendering a Persian page in both directions.
|
|
429
|
-
- A second layer, `fertig-a11y`, declared after `fertig`. The forced-colors
|
|
430
|
-
block lives there and wins on layer order.
|
|
431
|
-
- Print styles, `prefers-reduced-motion` handling, and thin scrollbars.
|
|
432
|
-
- Robustness: `overflow-wrap: break-word`; `:required`, `:read-only` and
|
|
433
|
-
`:autofill` states; slashed, tabular numerals; `object-fit` on card media;
|
|
434
|
-
smooth in-page scrolling; `overscroll-behavior` on overlays; `@page` margins
|
|
435
|
-
with orphan and widow control.
|
|
436
|
-
- Environment queries: `inverted-colors` and `color-gamut: p3`.
|
|
437
|
-
- `anchor-size()` and `position-visibility` for menus, `::spelling-error`,
|
|
438
|
-
and Safari's native `<input switch>` styled to match `role="switch"`.
|
|
439
|
-
|
|
440
|
-
### Browser support
|
|
441
|
-
|
|
442
|
-
- Two-year support policy: the sheet targets browsers from the last two years.
|
|
443
|
-
The only thing carried for the ones before them is the flat-sRGB palette
|
|
444
|
-
above ("a floor under the floor"). It ships no vendor prefixes except the
|
|
445
|
-
three no engine has replaced (`-webkit-text-size-adjust`, the autofill
|
|
446
|
-
repaint, and the `progress` pseudo-elements).
|
|
447
|
-
- The sheet is wrapped in `@layer fertig`, so unlayered author CSS overrides it
|
|
448
|
-
at any specificity. There is no `!important` anywhere in it: inside a cascade
|
|
449
|
-
layer an important declaration outranks your own unlayered CSS, which would
|
|
450
|
-
contradict the point of shipping in a layer.
|
|
451
|
-
|
|
452
|
-
### Site
|
|
453
|
-
|
|
454
|
-
- A blocks gallery with 16 ready-to-use patterns — toolbars, stat rows, tables
|
|
455
|
-
with totals, pagination, empty states, sign-in, settings, alerts, confirm
|
|
456
|
-
dialogs, tabs, menus, pricing and shortcuts. Each snippet is generated from
|
|
457
|
-
its own live preview at runtime, so the code and the demo cannot drift apart.
|
|
458
|
-
- `llms.txt` describing the layout model, the seven classes, the ARIA
|
|
459
|
-
component conventions and the tokens.
|
|
460
|
-
|
|
461
|
-
### Verified
|
|
462
|
-
|
|
463
|
-
- All foreground/background pairs meet WCAG 2.1 AA (≥ 4.5:1) in both themes,
|
|
464
|
-
at rest and on hover; the tightest is muted text on chrome at 4.65:1.
|
|
465
|
-
- Progressive enhancement behind `@supports`: `contrast-color()`,
|
|
466
|
-
`::details-content` with `interpolate-size`, `field-sizing`,
|
|
467
|
-
`corner-shape: squircle`, `text-box: trim-both` and `@property`-typed
|
|
468
|
-
shadow alphas. None of them are required for the sheet to work.
|
|
469
|
-
- Tables scroll themselves below 40rem instead of widening the page.
|
|
470
|
-
- 28.0 KB raw, 7.6 KB gzipped, 6.7 KB brotli (`fertig.min.css`).
|