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