fertig 4.0.2 → 4.0.4

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