fertig 4.0.3 → 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 CHANGED
@@ -1,473 +1,76 @@
1
1
  # fertig
2
2
 
3
- [![Bundlephobia minified size](https://img.shields.io/bundlephobia/min/fertig?label=minified&cacheSeconds=86400)](https://bundlephobia.com/package/fertig)
4
- [![Bundlephobia minified and compressed size](https://img.shields.io/bundlephobia/minzip/fertig?label=min%2Bgzip&cacheSeconds=86400)](https://bundlephobia.com/package/fertig)
3
+ [![minified size](https://img.shields.io/bundlephobia/min/fertig?label=minified&cacheSeconds=86400)](https://bundlephobia.com/package/fertig)
4
+ [![min+gzip size](https://img.shields.io/bundlephobia/minzip/fertig?label=min%2Bgzip&cacheSeconds=86400)](https://bundlephobia.com/package/fertig)
5
5
 
6
- A classless CSS file that gives you **components**, not just styled elements —
7
- menus, dialogs, drawers, toasts and tooltips from plain semantic HTML,
8
- built from native HTML and the ARIA that makes it accessible, and working with
9
- JavaScript switched off.
10
-
11
- Link it, write ordinary HTML, and the page is finished.
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.
12
9
 
13
10
  **36.7 KB raw · 8.6 KB gzipped · no build step · no dependencies · no JavaScript.**
14
11
 
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
- ## What it is
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
- <body>
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
- ## Components
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
- Addressed by semantic HTML and ARIA attributes, not by component classes — the
176
- markup stays accessible by construction.
32
+ ## What it includes
177
33
 
178
- | Component | Markup |
179
- |---|---|
180
- | Segmented control | `<div role="group">` of buttons, `aria-pressed` |
181
- | ARIA tabs | `<div role="tablist">`, `<button role="tab" aria-selected>`; switching and arrow keys need script |
182
- | Switch | `<input type="checkbox" role="switch">` |
183
- | Menu | any `[popover]` + `popovertarget` (anchored, no JS) |
184
- | Breadcrumb | `<nav aria-label="Breadcrumb"><ol>` |
185
- | Dialog | `<dialog>` animates in; optional `<header>`/`<footer>` pin while the body scrolls |
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
- And a second set, added for parity with the component libraries — same rule,
193
- no classes:
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
- | Component | Markup |
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
- ## The seven optional classes
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: light-dark(var(--fertig-blue-700), var(--fertig-blue-300)); /* blue accent */
248
- --fertig-w: 48rem; /* toolbar content width */
249
- --fertig-g: 1.25rem; /* page gutter */
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.7 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 run hooks:install # enable the committed pre-commit hook in this clone
423
- npm run check # run the same complete gate manually
424
- npm run build # regenerate fertig.min.css and print sizes
425
- npm run site # build the site into dist/ with Eleventy
426
- npm run site:serve # build + live-reload on :8080 (the Eleventy dev server)
427
- npm run sizes # sync the size claims in README + site copy
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 pre-commit gate is read-only for tracked files. It rejects whitespace
431
- errors, inconsistent release versions, stale minified CSS, stale size claims,
432
- bundle-budget regressions, test failures, invalid site output and unexpected
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.7 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 © Mojtaba Beheshti
76
+ MIT
package/fertig.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! fertig v4.0.3 — a classless CSS stylesheet. MIT */
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.
@@ -906,7 +906,9 @@ nav menu :is(a, button)[aria-current] {
906
906
  /* on the toolbar .wide cannot mean "be 80rem wide" — the bar stays full-bleed
907
907
  and its contents move out to the wide column, so an app screen's wordmark
908
908
  lines up with the app's own content rather than floating mid-screen. */
909
- :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav.wide { --fertig-nw: 80rem }
909
+ :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav.wide {
910
+ max-width: none; --fertig-nw: 80rem;
911
+ }
910
912
  .row { display: flex; flex-wrap: wrap; gap: .7rem; align-items: center }
911
913
  /* Form controls are full-width blocks by default, which is right in a form and
912
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.3 — 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{--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",
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": "eleventy --config=.eleventy.js",
71
- "site:serve": "eleventy --config=.eleventy.js --serve",
72
- "site:clean": "rm -rf dist",
73
- "dev": "python3 -m http.server 8899",
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
- "@11ty/eleventy": "^3.1.6"
77
+ "astro": "^5.18.2"
79
78
  }
80
79
  }
package/CHANGELOG.md DELETED
@@ -1,481 +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.3] — 2026-09-01
12
-
13
- ### Fixed
14
-
15
- - **Disabled filled buttons look disabled.** Primary and submit controls now
16
- return to the quiet control surface with muted text instead of retaining the
17
- enabled accent fill.
18
- - **Every published tab example is a real tab widget.** Examples now pair each
19
- tab with a labelled panel, keep only the active tab in the Tab sequence and
20
- support Left, Right, Home and End keys through one shared controller.
21
-
22
- ## [4.0.2] — 2026-09-01
23
-
24
- ### Changed
25
-
26
- - **Body-level page containers are full width by default.** fertig keeps the
27
- responsive page gutter but no longer applies a maximum width to direct body
28
- children or supported app-root children. Explicit `max-w-*`
29
- utilities remain available when a page needs a constrained measure.
30
-
31
- ## [4.0.1] — 2026-09-01
32
-
33
- ### Changed
34
-
35
- - **Buttons are flat and stay put.** The raised shadow, filled-button highlight
36
- and active press nudge are gone. Hover contrast, focus-visible outlines,
37
- disabled feedback and coarse-pointer target sizing remain intact.
38
- - **The public documentation speaks only about fertig.** Comparative product
39
- names, size rankings and survey links were removed from every published page.
40
-
41
- ### Fixed
42
-
43
- - **Shared mobile controls now have reliable touch targets.** Navigation,
44
- theme, colour, catalogue filter and sidebar controls reach 44 by 44 pixels;
45
- catalogue filters stay in one horizontal row instead of building a tall
46
- stack on narrow screens.
47
- - **Theme and copy feedback are clearer.** The theme control names its target,
48
- while clipboard fallbacks select the text and use platform-neutral wording.
49
-
50
- ## [4.0.0] — 2026-09-01
51
-
52
- ### Changed
53
-
54
- - **The palette is new and intentionally direct.** `gray`, `blue`, `cyan`,
55
- `green`, `amber`, `red` and `violet` replace the former
56
- `stone/sage/sky/clay/plum/gold` ramps. Each ships at 100/300/500/700/900,
57
- stays inside sRGB and uses a consistent OKLCH progression. Blue is the new
58
- default accent; `ok`, `warn` and `err` now map directly to green, amber and
59
- red.
60
- - **The default finish is platform-neutral.** Opaque toolbar and surface
61
- colors, restrained 8px control geometry, ordinary rounded buttons and generic
62
- system font fallbacks replace the OS-specific translucent treatment. The
63
- optional squircle enhancement and decorative backdrop blur are gone.
64
- - **The default hierarchy is clearer and the page gutter is responsive.**
65
- `h1` and `h2` now use a restrained fluid type scale, while the new
66
- `--fertig-g` token grows from 1.15rem on narrow phones to 1.9rem on larger
67
- screens. Desktop density is unchanged; small screens recover useful space.
68
- - **The generic toolbar stays composed on phones.** A navigation list gets one
69
- horizontally scrollable row beneath the identity and trailing control instead
70
- of wrapping around them in an uneven cluster.
71
-
72
- ### Removed
73
-
74
- - **The former palette and named accents.** Old ramp tokens and
75
- `data-accent="indigo|sky|sage|clay|plum|gold|slate"` are not retained as
76
- aliases. Use `data-accent="blue|cyan|green|amber|red|violet|gray"`.
77
- - **Legacy mockup pages and static social-preview screenshots.** The site build
78
- no longer copies them or emits metadata pointing at deleted preview images.
79
-
80
- ### Fixed
81
-
82
- - **Responsive tables scroll before their cells become unreadable.** Below
83
- 40rem, cell content keeps its intrinsic width inside the existing table scroll
84
- container instead of wrapping almost word-by-word.
85
- - **Size synchronization cannot rewrite third-party measurements.** Published
86
- claims are now an explicit manifest of fertig-specific contexts. A changed or
87
- missing context fails the command, and a regression test protects unrelated
88
- values that happen to match fertig's previous size.
89
-
90
- ## [3.1.0] — 2026-09-01
91
-
92
- ### Changed
93
-
94
- - **The 72rem default is now a page shell, not a prose measure.**
95
- `.max-w-prose` keeps long-form copy at 38rem, while `.wide` provides an 80rem
96
- application column. The documentation and customiser now use the same
97
- defaults and terminology as the stylesheet.
98
- - **The documentation toolbar stays compact on phones.** Its primary controls
99
- occupy the first row and its links scroll horizontally on the second instead
100
- of wrapping into a tall stack. The Components page is now present in the
101
- shared navigation.
102
-
103
- ### Fixed
104
-
105
- - **The minified build preserves descendant selectors.** The old punctuation
106
- regex changed selectors such as `nav :is(…)` into `nav:is(…)`, silently
107
- breaking row controls and popover menus. The minifier now understands CSS
108
- strings and comments, with focused regression tests for both failure modes.
109
- - **Reduced-transparency preferences reach framework wrappers.** A toolbar
110
- inside `#root`, `#app`, `#__next` or `[data-fertig]` now drops its backdrop
111
- blur just like a toolbar that is a direct child of `body`.
112
-
113
- ## [3.0.0] — 2026-08-31
114
-
115
- The breaking change is one mechanical line: **every public token now carries a
116
- `--fertig-` prefix, and the old names are gone** — no aliases, no shims. The
117
- classes, the layout utilities and the ARIA attributes the component layer reads
118
- are all untouched. The sheet does exactly what it did; the migration is a
119
- rename.
120
-
121
- `--fertig-a1` / `--fertig-a2` already carried the prefix for the reason the rest
122
- receive it now: a short, unprefixed custom property is a bet you only lose
123
- once. `--ac` collided with your own `--ac`; the prefix makes every token yours
124
- to override, and no future rename is ever needed again.
125
-
126
- **To migrate:** prefix whatever you override. `--w` → `--fertig-w`,
127
- `--ac` / `--on-ac` → `--fertig-ac` / `--fertig-on-ac`, the radii
128
- `--r` / `--rs` / `--rw` → `--fertig-*`, the surfaces (`--bg`, `--el`, `--face`,
129
- `--fg`, `--mut`, `--bd`, `--tb`, `--nw`), the depth tokens (`--up`, `--up2`,
130
- `--dn`, `--sh`, `--sh1`, `--sh2`, and the `@property` alphas `--a1` / `--a2`),
131
- the motion tokens (`--ease`, `--ease-in`, `--ease-out`, `--dur-1`, `--dur-2`),
132
- `--caps`, and the colour ramps (`--stone-*`, `--sage-*`, `--sky-*`, `--clay-*`,
133
- `--plum-*`, `--gold-*`). The rule is one line: **any `--name` you set becomes
134
- `--fertig-name`.** Nothing changed meaning.
135
-
136
- ### Changed
137
-
138
- - **The palette moves to a cooler voice.** Neutrals are a cool graphite
139
- (hue ≈ 258) with a faint violet cast, replacing the warm stone; the accent is
140
- a violet-blue (hue 266), replacing indigo. Measured: the accent clears 6.21:1
141
- as link text on paper and 6.39:1 for a white label on the fill in light,
142
- 8.62:1 in dark — both sit inside sRGB. The
143
- `@supports not (color: light-dark(…))` flat-sRGB fallback is restated to match,
144
- and every pair still clears WCAG AA in both schemes.
145
- - **Buttons are fully rounded.** The shared button rule takes a new
146
- `--fertig-rp` (pill) token instead of the control radius. It matches the
147
- badge, the switch and the progress bar, which were already pills. Set
148
- `--fertig-rp: var(--fertig-r)` for square-shouldered buttons.
149
- - **One radius, and the rest derived from it.** `--fertig-r` (12px) is the base;
150
- `--fertig-rs` is `calc(var(--fertig-r) * .5)` and `--fertig-rw` is
151
- `calc(var(--fertig-r) * 1.33)`, so setting the base on `:root` rescales the
152
- whole sheet instead of desynchronising it. Windows — cards, dialogs, popover
153
- menus, the select picker, `pre`, `details`, `fieldset`, `aside`, toasts —
154
- now take `--fertig-rw` rather than the control radius, and full-bleed card
155
- media follows the card it bleeds into.
156
- - **Badges are uppercase.** They already used the caps *size*; they never got
157
- the transform that `h5`, `h6` and `th` get.
158
- - **The dialog lost its banded rules.** No hairline under the header or over
159
- the footer by default; the separation is spacing. The rule now arrives as
160
- scroll state — a scroll-driven animation fades it in under the header once the
161
- body has scrolled and out of the footer at the end — so a dialog that fits
162
- shows no rules at all. Title takes `--fertig-f`, the interface face, at
163
- 600/1.1rem: a monospaced heading font reads as a terminal on a dialog.
164
- - **The `err` tone is red, not clay.** `[data-tone=err]` borrowed
165
- `--fertig-clay-700`, which at 50% lightness reads brown on a destructive
166
- button. Now `oklch(52% .16 27)` / `oklch(74% .13 25)` — 5.97:1 with the white
167
- label, and `--fertig-on-ac` still derives correctly in both themes.
168
- - **The select picker animates open and closed**, with `display` and `overlay`
169
- transitioned discretely so the close is not a pop.
170
-
171
- ### Fixed
172
-
173
- - **`accent-color` and `caret-color` ignored every local accent.** Both were
174
- declared once on `:root`. They are inherited properties, so they resolved
175
- there against the root accent and every descendant inherited that *computed
176
- colour* — a `[data-accent]` or `[data-tone]` subtree repainted its buttons and
177
- links but left its checkboxes, radios, ranges and caret on the root's tint.
178
- Both are now re-declared on the elements that consume them.
179
- - **The segmented control showed a vertical scrollbar.** `overflow-x: auto`
180
- makes `overflow-y` compute to `auto` as well, and Safari paints a scrollbar
181
- for a sub-pixel of overflow. The block axis is now clipped (`overflow: auto
182
- clip`), and group children take their focus ring inside the edge
183
- (`outline-offset: -3px`) so the clip cannot slice it.
184
- - **The `<select>` marker was a different shape per engine.** Engines without
185
- `appearance: base-select` fell back to a solid filled triangle while the
186
- styleable picker drew a thin chevron. The fallback now draws the same
187
- stroked chevron.
188
- - **The docs site is built with Eleventy.** The pages moved out of hand-edited
189
- HTML at the repo root into `src/` templates that build to `dist/`, with the
190
- version flowing from `package.json` as the single source of truth. This is how
191
- the sheet's own site is maintained; it is not part of the npm package, which
192
- ships the two CSS files plus the README and licence.
193
- - **The demo template pages are gone.** `app.html`, `app-invoice.html` and the
194
- whole `templates/` set (`dashboard`, `article`, `pricing`, `signin`) are
195
- removed from the site and repo; the docs no longer point at them.
196
-
197
- ## [2.0.0] — 2026-08-31
198
-
199
- ### Breaking
200
-
201
- - **`--a1` / `--a2` are now `--fertig-a1` / `--fertig-a2`, with no alias.**
202
- These are `@property` registrations, and a registration is global — it cannot
203
- be layered, scoped or overridden. A two-character name meant a consumer's own
204
- `--a1` was silently retyped to `<number>`, which is a bug that only a rename
205
- can fix.
206
-
207
- **To migrate:** if you set `--a1` or `--a2`, rename them. Nothing else
208
- changes — the values mean the same thing and the elevation scale is
209
- untouched. If you never set them, there is nothing to do.
210
-
211
- Every other token name is unchanged. They are ordinary custom properties,
212
- they are the documented API, and they are deliberately short.
213
-
214
- A visual refresh, an audit pass, and a component-first repositioning. One token
215
- rename aside, the surface is the same — the same classes and attributes — but
216
- the default look changes visibly, so treat this as a redesign rather than a
217
- drop-in bump.
218
-
219
- ### Added
220
-
221
- - **Named accents.** `data-accent="indigo|sky|sage|clay|plum|gold|slate"` on any
222
- element retints everything inside it: links, focus rings, filled buttons, the
223
- caret, the selection. Scoped rather than global, so one section can differ
224
- from the rest of a page. Each pair is measured — the light tone clears AA as
225
- link text on paper, the dark tone clears it on the dark ground.
226
- - **Motion tokens.** `--ease-out`, `--ease-in`, `--ease` and the durations
227
- `--dur-1` / `--dur-2`. The sheet had been animating with a bare `ease`, which
228
- is the browser default and the flattest curve available.
229
- - `--rs`, a small radius for inline chips and code, so they do not inherit the
230
- larger control radius and read as lozenges.
231
-
232
- ### Changed
233
-
234
- - **The default accent is indigo**, not the desaturated navy it was. Measured
235
- 6.28:1 as link text on paper and 6.39:1 for a white label on the fill in
236
- light; 8.72:1 and 10.26:1 in dark. Both sit inside sRGB.
237
- - **Cards no longer paint a tinted strip behind their header and footer.** A
238
- filled bar across the top of a card is the old panel-heading pattern and is
239
- what dated the sheet on sight; a hairline separates just as well and lets the
240
- card read as one surface.
241
- - Radii up: `--r` 6px → 9px, `--rw` 10px → 14px. Controls have more room —
242
- buttons and fields gained roughly a tenth of an em of padding.
243
- - More things transition, on the named curves: tabs, badges, cards, segmented
244
- controls and popover items, alongside the controls that already did.
245
- `:focus-visible` is explicitly excluded — a focus ring has to be there the
246
- instant focus lands, not fade in after it.
247
-
248
- ### Fixed
249
-
250
- - The tone bar on `.card[data-tone]` follows the corner radius again. It was an
251
- inset shadow, which does not track the curve cleanly at the larger radius —
252
- it read as a detached line with gaps at both top corners. It is a background
253
- layer now, which the radius clips. The duplicate indicator on
254
- `.card > header` is gone with it: the filled header used to hide it, and
255
- without the fill both were painting.
256
- - Navigation lists. `[data-layout=sidebar]` shipped without any styling for the
257
- nav inside it, so the obvious markup — a `<menu>` in a `<nav>` — came out as
258
- a boxed list group. It is navigation now: no rules between items, no bullets,
259
- and the link fills the row.
260
- - `aside` and `search` are block landmarks that had no vertical rhythm of their
261
- own, so whatever followed sat flush against them.
262
-
263
- ### Fixed — audit pass
264
-
265
- An audit pass. Everything here came out of `docs/known-flaws.md`, which lists
266
- what was found, what was verified in a browser, and what was left alone on
267
- purpose.
268
-
269
- - **The shell survives a framework wrapper.** The page shell was `body > *`, so
270
- a React, Vue, Svelte or Next app rendering into `<div id="root">` lost the
271
- measure, the paper surface and the gutters with nothing on screen to say why.
272
- The shell now also matches the children of a single `#root`, `#app`,
273
- `#__next` or `[data-fertig]` wrapper. Every added selector sits inside
274
- `:where()`, so specificity is unchanged.
275
- - **A floor under the floor.** Every colour token was an unguarded
276
- `light-dark()`. In an engine without it the tokens were invalid at
277
- computed-value time, so backgrounds went transparent and colour was
278
- inherited — a page could land unreadable rather than plain. A
279
- `@supports not (color: light-dark(…))` block at the end of the layer restates
280
- the palette in flat sRGB, in both schemes.
281
- - **`data-size`, `data-variant` and `data-block` are scoped to controls.** As
282
- bare attribute selectors they restyled any element carrying those very common
283
- attribute names — a `<span data-size="sm">` picked up button padding.
284
- - **The focus ring no longer reshapes what it rings.** `:focus-visible` set
285
- `border-radius: var(--r)`, which is the element's own radius, not the ring's:
286
- a focused `<dialog>` snapped from `--rw` (14px) to `--r` (9px). Outlines
287
- already follow the element's corners, so the declaration is simply gone.
288
- - **`<svg>` stays inline.** It was in the `display: block` rule with `img`,
289
- `video` and `iframe`, which dropped every inline icon onto its own line.
290
- - **Toasts can stack.** Two `[popover][data-toast]` elements shared one set of
291
- corner coordinates and overlapped, and an open popover is in the top layer so
292
- no ordinary wrapper could stack them. `<div popover="manual"
293
- data-toast-region>` is now the popover, with a `<div data-toast>` per message.
294
- - **A selected tab is visible in Windows High Contrast.** Its cue was a
295
- `box-shadow` that the forced-colors layer removes, and the replacement set
296
- `border-color` on an element with `border: 0`. It now sets a real
297
- `border-bottom`.
298
- - **`--on-ac` survives a custom `--ac` in shipping browsers.** The
299
- `contrast-color()` guard is real but almost nothing implements it. A relative
300
- colour branch reaches the same black-or-white decision from the accent's own
301
- lightness, and has been cross-engine since 2024.
302
- - **`interpolate-size: allow-keywords` is set on `details`, not `:root`.** It is
303
- inherited, so the old placement changed how *your* `height: auto` transitions
304
- behaved as a side effect of animating a disclosure.
305
- - **Two universal rules narrowed to what the sheet actually styles.**
306
- `scrollbar-width: thin` no longer thins the page's own scrollbar (a
307
- target-size problem for imprecise pointers), and `corner-shape: squircle` no
308
- longer reshapes your components.
309
- - **`input[type=image]` is a button, not a text field.** It was missing from the
310
- `:not()` list and got full-width sunken-field treatment.
311
- - **The tooltip is flow-relative and reachable on touch** — logical inset
312
- properties with a `:dir(rtl)` offset, and `:active` alongside `:hover`. It is
313
- still decorative, and now says so in the sheet, the README and the docs.
314
- - **`a[target=_blank]`** no longer appends an arrow to a link wrapping an image.
315
- - **Print keeps the footer.** It was hidden along with the toolbar, which drops
316
- the legal line, the contact and the citations from every printout.
317
- - **The small variant stays small on touch.** `(pointer: coarse)` forced
318
- `min-height: 44px` on everything; `data-size="sm"` opts down to 32px, still
319
- above the 24px WCAG 2.5.8 floor.
320
- - `package.json`'s size claim, the one string `tools/sizes.py` does not reach.
321
-
322
- ### Changed
323
-
324
- - `--a1` / `--a2` renamed — see **Breaking** above.
325
-
326
- ## [1.0.3] — 2026-08-30
327
-
328
- ### Changed
329
-
330
- - `--mut` lifted from 50%/70% lightness to 47%/73%. The weakest muted pairing
331
- — on the desktop ground in light, on chrome in dark — was 4.96:1 and 5.99:1,
332
- a hair over AA; it is 5.65:1 and 6.70:1 now. Not taken to AAA, which would need 41.5%: that
333
- is close enough to `--fg` that muted text stops reading as secondary at all.
334
-
335
- ### Added
336
-
337
- - `--nw`, the column the toolbar's contents line up with. It follows `--w`, so
338
- nothing changes by default, and `<nav class="wide">` re-points it at the wide
339
- column — an app screen built on `.wide` no longer gets a wordmark floating in
340
- the middle of the viewport while its content spans the full width.
341
-
342
- ### Fixed
343
-
344
- - Breadcrumb separators no longer leak into other navigation. The `/` was on
345
- `nav[aria-label] li + li`, so any labelled `<nav>` containing a `<ul>` — an
346
- ordinary sidebar — got breadcrumb slashes between its links. Scoped to `ol`,
347
- matching the layout rule directly above it and the documented markup.
348
- - A `.grid` no longer collides with the block that follows it. It is a
349
- block-level container and nothing gave it vertical rhythm. The space is on
350
- `.grid + *` rather than a margin on `.grid` itself, which would collapse out
351
- through the top of a padding-less container and open a seam above it.
352
- - A segmented control (`role="group"`) with four or more buttons no longer
353
- pushes the page sideways on a narrow screen. It scrolls within its own width
354
- instead of wrapping, which would break the joined run of corner radii.
355
- - A `<dl>` with a long value no longer widens the page. The value column was
356
- a bare `1fr`, whose automatic minimum is its content, so it could not shrink;
357
- it is `minmax(0, 1fr)` now.
358
-
359
- ## [1.0.2] — 2026-08-30
360
-
361
- ### Fixed
362
-
363
- - Menus and toasts no longer jump across the viewport as they close. The anchor
364
- positioning was scoped to `[popover]:popover-open`, but the close is
365
- transitioned (`display .13s allow-discrete`), so for those 130ms the popover
366
- still painted while no longer matching the selector — falling back to the UA's
367
- centred `inset: 0` and visibly flying to the middle of the screen. Both the
368
- menu and the `[data-toast]` corner override now sit on the base selector.
369
-
370
- ## [1.0.1] — 2026-08-30
371
-
372
- Packaging only; the stylesheet is unchanged apart from its version banner.
373
-
374
- ### Changed
375
-
376
- - `homepage` points at the documentation site rather than the README, and the
377
- repository URLs follow the repo's rename to `moji2002/fertig`.
378
- - `fertig` and `fertig.css` added as keywords: the package is `fertig`, but
379
- people search npm for the project's name.
380
-
381
- ## [1.0.1] - 2026-08-30
382
-
383
- ### Changed
384
-
385
- - npm keywords only: added `css-framework`, `lightweight`, `minimalist`, `html`,
386
- `frontend`, `ui` and `responsive`. `css-framework` is the term the rest of the
387
- category (Pico, Water.css) registers under, and it was missing. No stylesheet
388
- changes — the CSS is byte-identical to 1.0.0.
389
-
390
- ## [1.0.0] — 2026-08-30
391
-
392
- First release. The project and the npm package are `fertig`. The stylesheet
393
- file keeps the name `fertig.css`, because it is a CSS file, and the cascade
394
- layer is `@layer fertig` — a dot in a layer name would declare a sub-layer.
395
-
396
- ### Added
397
-
398
- - Classless styling for the full semantic element set: headings, prose, lists,
399
- description lists, quotes, rules, code, tables, every form control,
400
- fieldsets, buttons, details, dialog, figures, media and asides.
401
- - Layout model where direct children of `<body>` are containers — `<nav>` is a
402
- full-bleed toolbar with a vibrancy blur, and
403
- `header`/`main`/`footer` are the page.
404
- - Light and dark themes from a single `light-dark()` token block, with
405
- `data-theme="light|dark"` to override the OS preference.
406
- - Elevation scale (`--up`, `--up2`, `--dn`) whose shadow alphas step up in dark
407
- mode, since a shadow on a dark ground reads as nothing on its own. The
408
- shadows come off a real colour token (`--sh`) through relative colour syntax,
409
- not an HSL triplet you could not use directly.
410
- - Component layer addressed by ARIA rather than by class: segmented controls
411
- (`role="group"`), tabs (`role="tablist"`), switches (`role="switch"`),
412
- `[popover]` menus anchored to their invoker, breadcrumbs, `<dialog>` with an
413
- entrance transition, `aria-busy` spinners and `data-tooltip`.
414
- - Button variants (`data-variant`, `data-size`, `data-icon`, `data-block`) and
415
- card anatomy (`<header>`/`<footer>`, full-bleed media, `data-tone`,
416
- `<a class="card">` hover lift).
417
- - Seven optional classes: `.row`, `.grid`, `.card`, `.badge`, `.muted`,
418
- `.center`, `.wide`.
419
- - Dialog anatomy: an optional `<header>` and `<footer>` that run edge to edge
420
- and stay pinned while the body scrolls. Sticky rather than a grid, because a
421
- classless sheet has no wrapper around the loose middle children to make a
422
- grid row out of; the sticky offsets are negative so the chrome pins to the
423
- dialog's border edge rather than its padding edge, which is where content
424
- would otherwise scroll through.
425
- - A max-width scale on Tailwind's names — `.max-w-xs` through `.max-w-7xl`,
426
- plus `.max-w-full`, `.max-w-none` and `.max-w-prose`. Whole rather than
427
- partial: a scale where `.max-w-2xl` works and `.max-w-3xl` silently does not
428
- is worse than no scale. They are `max-inline-size`, so they still mean
429
- "along the text" in a vertical writing mode.
430
- - Layout utilities, named after Tailwind's so the names transfer: `.flex`,
431
- `.flex-col`, `.flex-wrap`, `.flex-1`, `.grid-cols-2|3|4`,
432
- `.items-start|center|end`, `.justify-start|center|end|between`,
433
- `.gap-0|1|2|3|4|6`, `.mx-auto`, `.ms-auto`, `.me-auto`, `.w-full`,
434
- `.hidden`. Layout only — no colour, type or sizing scale, and no responsive
435
- variants, which would need a build step.
436
- - Right-to-left support. Every inline-direction rule is flow-relative, with
437
- `:dir(rtl)` rules for the two that cannot be — the switch knob's `translate`
438
- and the fallback `<select>` chevron's background position. Verified by
439
- rendering a Persian page in both directions.
440
- - A second layer, `fertig-a11y`, declared after `fertig`. The forced-colors
441
- block lives there and wins on layer order.
442
- - Print styles, `prefers-reduced-motion` handling, and thin scrollbars.
443
- - Robustness: `overflow-wrap: break-word`; `:required`, `:read-only` and
444
- `:autofill` states; slashed, tabular numerals; `object-fit` on card media;
445
- smooth in-page scrolling; `overscroll-behavior` on overlays; `@page` margins
446
- with orphan and widow control.
447
- - Environment queries: `inverted-colors` and `color-gamut: p3`.
448
- - `anchor-size()` and `position-visibility` for menus, `::spelling-error`,
449
- and Safari's native `<input switch>` styled to match `role="switch"`.
450
-
451
- ### Browser support
452
-
453
- - Two-year support policy: the sheet targets browsers from the last two years.
454
- The only thing carried for the ones before them is the flat-sRGB palette
455
- above ("a floor under the floor"). It ships no vendor prefixes except the
456
- three no engine has replaced (`-webkit-text-size-adjust`, the autofill
457
- repaint, and the `progress` pseudo-elements).
458
- - The sheet is wrapped in `@layer fertig`, so unlayered author CSS overrides it
459
- at any specificity. There is no `!important` anywhere in it: inside a cascade
460
- layer an important declaration outranks your own unlayered CSS, which would
461
- contradict the point of shipping in a layer.
462
-
463
- ### Site
464
-
465
- - A blocks gallery with 16 ready-to-use patterns — toolbars, stat rows, tables
466
- with totals, pagination, empty states, sign-in, settings, alerts, confirm
467
- dialogs, tabs, menus, pricing and shortcuts. Each snippet is generated from
468
- its own live preview at runtime, so the code and the demo cannot drift apart.
469
- - `llms.txt` describing the layout model, the seven classes, the ARIA
470
- component conventions and the tokens.
471
-
472
- ### Verified
473
-
474
- - All foreground/background pairs meet WCAG 2.1 AA (≥ 4.5:1) in both themes,
475
- at rest and on hover; the tightest is muted text on chrome at 4.65:1.
476
- - Progressive enhancement behind `@supports`: `contrast-color()`,
477
- `::details-content` with `interpolate-size`, `field-sizing`,
478
- `corner-shape: squircle`, `text-box: trim-both` and `@property`-typed
479
- shadow alphas. None of them are required for the sheet to work.
480
- - Tables scroll themselves below 40rem instead of widening the page.
481
- - 28.0 KB raw, 7.6 KB gzipped, 6.7 KB brotli (`fertig.min.css`).