fertig 4.0.3 → 4.0.7

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