fertig 2.0.0 → 3.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/fertig.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! fertig v2.0.0 — a classless CSS stylesheet. MIT */
1
+ /*! fertig v3.0.0 — a classless CSS stylesheet. MIT */
2
2
 
3
3
  /* Opinions, so you don't have to have them:
4
4
  system type · one accent · one measure · a window on a desktop.
@@ -9,8 +9,8 @@
9
9
  /* typed so they interpolate; untyped custom properties cannot animate */
10
10
  /* Registrations are global: they cannot be layered, scoped or overridden.
11
11
  Hence the prefix — a bare --a1 would silently retype a property of yours. */
12
- @property --fertig-a1 { syntax: "<number>"; inherits: true; initial-value: .08 }
13
- @property --fertig-a2 { syntax: "<number>"; inherits: true; initial-value: .06 }
12
+ @property --fertig-a1 { syntax: "<number>"; inherits: true; initial-value: .06 }
13
+ @property --fertig-a2 { syntax: "<number>"; inherits: true; initial-value: .05 }
14
14
 
15
15
  /* Two layers, in this order. Your own unlayered CSS wins over both regardless
16
16
  of specificity, so overriding never needs !important — and neither does this
@@ -24,102 +24,116 @@
24
24
  /* ---- tokens ------------------------------------------------- */
25
25
  :root {
26
26
  color-scheme: light dark; /* powers light-dark() below */
27
- accent-color: var(--ac);
28
- caret-color: var(--ac);
29
-
30
- --f: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
27
+ /* These two are also re-declared on the elements that consume them, further
28
+ down. They are inherited properties: declared only here, they resolve once
29
+ against the root's accent and every descendant inherits that *computed
30
+ colour* so a [data-accent] or [data-tone] subtree, or any element that
31
+ sets --fertig-ac, got the root's tint on its checkboxes and its caret
32
+ while everything else in it followed the override. */
33
+ accent-color: var(--fertig-ac);
34
+ caret-color: var(--fertig-ac);
35
+
36
+ --fertig-f: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
31
37
  Roboto, "Helvetica Neue", Arial, sans-serif; /* yours */
32
- --fm: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
38
+ --fertig-fm: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
33
39
  "Liberation Mono", monospace; /* code */
34
- --w: 38rem; /* ~70 characters — yours */
35
- --r: 9px; /* control radius */
36
- --rs: 5px; /* small radius: inline chips and code */
37
- --rw: 14px; /* window radius */
40
+ --fertig-w: 38rem; /* ~70 characters — yours */
41
+ /* One radius, and the rest derived from it: set --fertig-r and the whole
42
+ sheet rescales together. Four independent numbers meant --fertig-r: 4px
43
+ left tight fields sitting inside cards that were still round. */
44
+ --fertig-r: 12px; /* control radius: fields, menu rows */
45
+ --fertig-rs: calc(var(--fertig-r) * .5); /* small: inline chips and code */
46
+ --fertig-rw: calc(var(--fertig-r) * 1.33); /* window: cards, dialogs, menus */
47
+ --fertig-rp: calc(infinity * 1px); /* pill: buttons, badges, switches, meters */
38
48
 
39
49
  /* ---- palette ------------------------------------------------
40
50
  Low chroma on purpose. Vivid palettes shout; these are meant to sit
41
- under text all day. OKLCH, so a step means the same thing in every hue. */
42
- --stone-100: oklch(97.5% .004 75); --stone-300: oklch(91% .006 75);
43
- --stone-500: oklch(72% .008 75); --stone-700: oklch(47% .009 75);
44
- --stone-900: oklch(26% .008 75);
51
+ under text all day. OKLCH, so a step means the same thing in every hue.
52
+ The neutrals are a cool graphite (hue 258) with a faint violet cast —
53
+ crisper and less dated than a warm stone, and better under the accent. */
54
+ --fertig-stone-100: oklch(97.5% .006 258); --fertig-stone-300: oklch(91% .009 258);
55
+ --fertig-stone-500: oklch(72% .012 258); --fertig-stone-700: oklch(47% .014 258);
56
+ --fertig-stone-900: oklch(26% .016 258);
45
57
 
46
- --sage-100: oklch(96% .022 155); --sage-300: oklch(87% .042 155);
47
- --sage-500: oklch(66% .058 155); --sage-700: oklch(47% .055 155);
48
- --sage-900: oklch(29% .038 155);
58
+ --fertig-sage-100: oklch(96% .024 160); --fertig-sage-300: oklch(87% .046 160);
59
+ --fertig-sage-500: oklch(66% .064 160); --fertig-sage-700: oklch(47% .06 160);
60
+ --fertig-sage-900: oklch(29% .042 160);
49
61
 
50
- --sky-100: oklch(96% .022 240); --sky-300: oklch(87% .045 240);
51
- --sky-500: oklch(64% .085 245); --sky-700: oklch(48% .095 250);
52
- --sky-900: oklch(30% .06 250);
62
+ --fertig-sky-100: oklch(96% .024 242); --fertig-sky-300: oklch(87% .05 244);
63
+ --fertig-sky-500: oklch(64% .095 246); --fertig-sky-700: oklch(48% .1 250);
64
+ --fertig-sky-900: oklch(30% .064 250);
53
65
 
54
- --clay-100: oklch(96% .022 45); --clay-300: oklch(88% .045 45);
55
- --clay-500: oklch(68% .085 45); --clay-700: oklch(50% .09 40);
56
- --clay-900: oklch(31% .055 40);
66
+ --fertig-clay-100: oklch(96% .024 45); --fertig-clay-300: oklch(88% .05 45);
67
+ --fertig-clay-500: oklch(68% .095 45); --fertig-clay-700: oklch(50% .098 40);
68
+ --fertig-clay-900: oklch(31% .06 40);
57
69
 
58
- --plum-100: oklch(96% .02 320); --plum-300: oklch(88% .038 320);
59
- --plum-500: oklch(66% .06 320); --plum-700: oklch(47% .065 320);
60
- --plum-900: oklch(29% .042 320);
70
+ --fertig-plum-100: oklch(96% .022 318); --fertig-plum-300: oklch(88% .042 318);
71
+ --fertig-plum-500: oklch(66% .066 318); --fertig-plum-700: oklch(47% .07 318);
72
+ --fertig-plum-900: oklch(29% .046 318);
61
73
 
62
- --gold-100: oklch(96.5% .028 90); --gold-300: oklch(89% .055 88);
63
- --gold-500: oklch(74% .085 85); --gold-700: oklch(55% .085 80);
64
- --gold-900: oklch(33% .05 80);
74
+ --fertig-gold-100: oklch(96.5% .03 92); --fertig-gold-300: oklch(89% .06 88);
75
+ --fertig-gold-500: oklch(74% .092 85); --fertig-gold-700: oklch(55% .092 80);
76
+ --fertig-gold-900: oklch(33% .056 80);
65
77
 
66
78
  /* ---- semantic ----------------------------------------------- */
67
- --bg: light-dark(oklch(93.5% .006 75), oklch(16% .006 75)); /* desktop */
68
- --el: light-dark(oklch(99.4% .002 75), oklch(21% .006 75)); /* paper */
69
- --face:light-dark(oklch(97.2% .005 75), oklch(25% .007 75)); /* chrome */
70
- --fg: light-dark(oklch(22% .008 75), oklch(95% .004 75));
79
+ --fertig-bg: light-dark(oklch(93.5% .008 258), oklch(15.5% .014 258)); /* desktop */
80
+ --fertig-el: light-dark(oklch(99% .004 258), oklch(21% .016 258)); /* paper */
81
+ --fertig-face:light-dark(oklch(97.2% .006 258), oklch(25% .018 258)); /* chrome */
82
+ --fertig-fg: light-dark(oklch(22% .02 258), oklch(95% .012 258));
71
83
  /* lifted from 50%/70%: the weakest pairing (muted on the desktop ground in
72
84
  light, muted on chrome in dark) was 4.96:1 and 5.99:1, a hair over AA.
73
- 47%/73% takes them to 5.65:1 and 6.70:1 while keeping a clear step down
74
- from --fg — AAA would need 41.5%, which is close enough to --fg that
75
- "muted" stops reading as secondary at all. */
76
- --mut: light-dark(oklch(47% .009 75), oklch(73% .008 75));
77
- --bd: light-dark(oklch(22% .008 75 / .13), oklch(95% .004 75 / .13));
78
- --tb: light-dark(oklch(97.2% .005 75 / .85), oklch(25% .007 75 / .85));
79
- /* indigo, not the azure every other classless sheet lands on. Measured:
80
- 6.28:1 as link text on paper and 6.39:1 for a white label on the fill in
81
- light; 8.72:1 and 10.26:1 in dark. Both sit inside sRGB. */
82
- --ac: light-dark(oklch(50% .19 275), oklch(78% .11 275)); /* yours */
83
- --on-ac: light-dark(#fff, #06121f); /* text on the accent, both themes */
85
+ 46%/72% takes them to 5.7:1 and 6.8:1 while keeping a clear step down
86
+ from --fertig-fg — AAA would need ~41%, which is close enough to
87
+ --fertig-fg that "muted" stops reading as secondary at all. */
88
+ --fertig-mut: light-dark(oklch(46% .018 258), oklch(72% .02 258));
89
+ --fertig-bd: light-dark(oklch(22% .02 258 / .13), oklch(95% .012 258 / .13));
90
+ --fertig-tb: light-dark(oklch(97.2% .006 258 / .85), oklch(25% .018 258 / .85));
91
+ /* a violet-indigo, not the azure every other classless sheet lands on.
92
+ Higher chroma than the old indigo so it reads electric without shouting.
93
+ Measured: 6.21:1 as link text on paper and 6.39:1 for a white label on
94
+ the fill in light; 8.62:1 in dark. Both sit inside sRGB. */
95
+ --fertig-ac: light-dark(oklch(50% .22 266), oklch(78% .13 266)); /* yours */
96
+ --fertig-on-ac: light-dark(#fff, #07071c); /* text on the accent, both themes */
84
97
 
85
98
  /* depth: hairline + soft shadow, macOS weight.
86
- --sh is an ordinary colour — override it with any notation you like, and
87
- every shadow in the sheet retints. The alphas are taken with color-mix
88
- against transparent rather than relative colour: same result, and it is
89
- three years older, which keeps Safari 17.5 inside the floor. */
90
- --sh: oklch(23.1% .007 286);
91
- --fertig-a1: .08; --fertig-a2: .06;
92
- --sh1: color-mix(in srgb, var(--sh) calc(var(--fertig-a1) * 100%), transparent);
93
- --sh2: color-mix(in srgb, var(--sh) calc(var(--fertig-a2) * 100%), transparent);
94
- --up: 0 1px 1px var(--sh1);
95
- --up2: 0 1px 2px var(--sh1), 0 6px 16px -6px var(--sh2);
96
- --dn: inset 0 1px 2px color-mix(in srgb, var(--sh) 8%, transparent);
97
- --caps: .74em/1.4 var(--f);
99
+ --fertig-sh is an ordinary colour — override it with any notation you like, and
100
+ every shadow in the sheet retints. Lighter than a pure black so the shadows
101
+ read as diffuse atmosphere rather than dark bars. The alphas are taken with
102
+ color-mix against transparent rather than relative colour: same result, and
103
+ it is three years older, which keeps Safari 17.5 inside the floor. */
104
+ --fertig-sh: oklch(30% .012 270);
105
+ --fertig-a1: .06; --fertig-a2: .05;
106
+ --fertig-sh1: color-mix(in srgb, var(--fertig-sh) calc(var(--fertig-a1) * 100%), transparent);
107
+ --fertig-sh2: color-mix(in srgb, var(--fertig-sh) calc(var(--fertig-a2) * 100%), transparent);
108
+ --fertig-up: 0 1px 1px var(--fertig-sh1);
109
+ --fertig-up2: 0 1px 1px var(--fertig-sh1), 0 8px 22px -8px var(--fertig-sh2);
110
+ --fertig-dn: inset 0 1px 2px color-mix(in srgb, var(--fertig-sh) 7%, transparent);
111
+ --fertig-caps: .74em/1.4 var(--fertig-f);
98
112
 
99
113
  /* motion. One decelerating curve for things arriving, one accelerating for
100
114
  things leaving, and a symmetric one for state that toggles in place. */
101
- --ease-out: cubic-bezier(.22, 1, .36, 1);
102
- --ease-in: cubic-bezier(.55, 0, 1, .45);
103
- --ease: cubic-bezier(.4, 0, .2, 1);
104
- --dur-1: .12s; /* a control reacting under the pointer */
105
- --dur-2: .2s; /* something appearing or leaving */
115
+ --fertig-ease-out: cubic-bezier(.22, 1, .36, 1);
116
+ --fertig-ease-in: cubic-bezier(.55, 0, 1, .45);
117
+ --fertig-ease: cubic-bezier(.4, 0, .2, 1);
118
+ --fertig-dur-1: .12s; /* a control reacting under the pointer */
119
+ --fertig-dur-2: .2s; /* something appearing or leaving */
106
120
  }
107
121
  @media (prefers-color-scheme: dark) {
108
- :root:not([data-theme=light]) { --fertig-a1: .5; --fertig-a2: .45 }
122
+ :root:not([data-theme=light]) { --fertig-a1: .42; --fertig-a2: .38 }
109
123
  }
110
- /* --on-ac has to survive any --ac override, or a custom accent ships an
124
+ /* --fertig-on-ac has to survive any --fertig-ac override, or a custom accent ships an
111
125
  unreadable label. contrast-color() does that properly but has almost no
112
126
  support; relative colour reaches the same black-or-white decision from the
113
127
  accent's own lightness, and has been cross-engine since 2024. Both are
114
128
  additive — the measured light-dark() pair above stands if neither exists. */
115
129
  @supports (color: oklch(from red l c h)) {
116
- :root { --on-ac: oklch(from var(--ac) clamp(0, (l - .62) * -100, 1) 0 h) }
130
+ :root { --fertig-on-ac: oklch(from var(--fertig-ac) clamp(0, (l - .62) * -100, 1) 0 h) }
117
131
  }
118
132
  @supports (color: contrast-color(red)) {
119
- :root { --on-ac: contrast-color(var(--ac)) }
133
+ :root { --fertig-on-ac: contrast-color(var(--fertig-ac)) }
120
134
  }
121
- [data-theme=light] { color-scheme: light; --fertig-a1: .08; --fertig-a2: .06 }
122
- [data-theme=dark] { color-scheme: dark; --fertig-a1: .5; --fertig-a2: .45 }
135
+ [data-theme=light] { color-scheme: light; --fertig-a1: .06; --fertig-a2: .05 }
136
+ [data-theme=dark] { color-scheme: dark; --fertig-a1: .42; --fertig-a2: .38 }
123
137
 
124
138
  /* Named accents. The ramps already exist, so this is a mapping table: put
125
139
  data-accent on any element and everything inside it — links, focus rings,
@@ -127,13 +141,13 @@
127
141
  global, so one section of a page can differ from the rest.
128
142
  Each pair is measured: the light tone clears AA as link text on paper, the
129
143
  dark tone clears it on the dark ground. */
130
- [data-accent=indigo] { --ac: light-dark(oklch(50% .19 275), oklch(78% .11 275)) }
131
- [data-accent=sky] { --ac: light-dark(var(--sky-700), oklch(78% .085 245)) }
132
- [data-accent=sage] { --ac: light-dark(var(--sage-700), oklch(80% .075 155)) }
133
- [data-accent=clay] { --ac: light-dark(var(--clay-700), oklch(80% .085 45)) }
134
- [data-accent=plum] { --ac: light-dark(var(--plum-700), oklch(80% .065 320)) }
135
- [data-accent=gold] { --ac: light-dark(oklch(55% .085 80), oklch(84% .09 85)) }
136
- [data-accent=slate] { --ac: light-dark(oklch(35% .01 250), oklch(86% .006 250)) }
144
+ [data-accent=indigo] { --fertig-ac: light-dark(oklch(50% .19 275), oklch(78% .11 275)) }
145
+ [data-accent=sky] { --fertig-ac: light-dark(var(--fertig-sky-700), oklch(78% .085 245)) }
146
+ [data-accent=sage] { --fertig-ac: light-dark(var(--fertig-sage-700), oklch(80% .075 155)) }
147
+ [data-accent=clay] { --fertig-ac: light-dark(var(--fertig-clay-700), oklch(80% .085 45)) }
148
+ [data-accent=plum] { --fertig-ac: light-dark(var(--fertig-plum-700), oklch(80% .065 320)) }
149
+ [data-accent=gold] { --fertig-ac: light-dark(oklch(55% .085 80), oklch(84% .09 85)) }
150
+ [data-accent=slate] { --fertig-ac: light-dark(oklch(35% .01 250), oklch(86% .006 250)) }
137
151
 
138
152
  /* ---- base --------------------------------------------------- */
139
153
  *, ::before, ::after { box-sizing: border-box }
@@ -141,25 +155,25 @@
141
155
  because no engine ships an alternative today: this one (Safari has no
142
156
  unprefixed text-size-adjust), the autofill repaint below, and the progress
143
157
  pseudo-elements. Everything else here is unprefixed modern CSS. */
144
- html { font: 16px/1.65 var(--f); -webkit-text-size-adjust: 100%; tab-size: 2 }
158
+ html { font: 16px/1.65 var(--fertig-f); -webkit-text-size-adjust: 100%; tab-size: 2 }
145
159
  body {
146
- margin: 0; background: var(--bg); color: var(--fg);
160
+ margin: 0; background: var(--fertig-bg); color: var(--fertig-fg);
147
161
  overflow-wrap: break-word; /* a pasted URL cannot widen the page */
148
162
  font-variant-numeric: slashed-zero tabular-nums;
149
163
  }
150
- ::selection { background: color-mix(in srgb, var(--ac) 28%, transparent) }
164
+ ::selection { background: color-mix(in srgb, var(--fertig-ac) 28%, transparent) }
151
165
  /* The macOS ring. No border-radius here: an outline already follows the
152
166
  element's own corners, and setting one would reshape whatever takes focus —
153
- a focused dialog would snap from --rw to --r for as long as it is focused. */
167
+ a focused dialog would snap from --fertig-rw to --fertig-r for as long as it is focused. */
154
168
  :focus-visible {
155
- outline: 3px solid color-mix(in srgb, var(--ac) 45%, transparent);
169
+ outline: 3px solid color-mix(in srgb, var(--fertig-ac) 45%, transparent);
156
170
  outline-offset: 1px;
157
171
  }
158
172
  img, video, iframe { display: block; max-width: 100%; height: auto }
159
173
  /* svg is left inline: it is as often an icon inside a sentence or a button as
160
174
  it is a standalone figure, and display:block drops the icon onto its own row */
161
175
  svg { max-width: 100%; vertical-align: middle }
162
- img, video { border-radius: var(--r); box-shadow: var(--up2) }
176
+ img, video { border-radius: var(--fertig-r); box-shadow: var(--fertig-up2) }
163
177
 
164
178
  /* ---- layout: a window on a desktop --------------------------- */
165
179
  /* The shell is body's own children — or the children of the single wrapper a
@@ -169,37 +183,37 @@ img, video { border-radius: var(--r); box-shadow: var(--up2) }
169
183
  :where() so every selector keeps the specificity it had as `body > *`. */
170
184
  body > *,
171
185
  body > :where(#root, #app, #__next, [data-fertig]) > * {
172
- max-width: var(--w); margin-inline: auto; padding-inline: 1.9rem;
186
+ max-width: var(--fertig-w); margin-inline: auto; padding-inline: 1.9rem;
173
187
  }
174
188
  /* the wrapper is not itself a shell element; it just gets out of the way */
175
189
  body > :where(#root, #app, #__next, [data-fertig]) { max-width: none; padding-inline: 0 }
176
190
  :is(body, body > :where(#root, #app, #__next, [data-fertig])) > :is(header, main, footer) {
177
- background: var(--el); border-inline: 1px solid var(--bd);
191
+ background: var(--fertig-el); border-inline: 1px solid var(--fertig-bd);
178
192
  }
179
193
  :is(body, body > :where(#root, #app, #__next, [data-fertig])) > header { padding-block: 2.4rem .8rem }
180
194
  :is(body, body > :where(#root, #app, #__next, [data-fertig])) > main { padding-bottom: 2.8rem }
181
195
  :is(body, body > :where(#root, #app, #__next, [data-fertig])) > footer {
182
- padding-block: 1.2rem 2rem; color: var(--mut); font-size: .85em;
183
- border-top: 1px solid var(--bd); border-bottom: 1px solid var(--bd);
184
- border-radius: 0 0 var(--rw) var(--rw); margin-bottom: 2.5rem;
185
- box-shadow: 0 18px 30px -22px color-mix(in srgb, var(--sh) 50%, transparent);
196
+ padding-block: 1.2rem 2rem; color: var(--fertig-mut); font-size: .85em;
197
+ border-top: 1px solid var(--fertig-bd); border-bottom: 1px solid var(--fertig-bd);
198
+ border-radius: 0 0 var(--fertig-rw) var(--fertig-rw); margin-bottom: 2.5rem;
199
+ box-shadow: 0 20px 32px -24px color-mix(in srgb, var(--fertig-sh) 38%, transparent);
186
200
  }
187
201
  /* nav = unified toolbar: full-bleed, vibrant, contents on the measure */
188
202
  :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav {
189
203
  position: sticky; top: 0; z-index: 9; max-width: none;
190
204
  /* the toolbar is full-bleed but its contents line up with the page column.
191
- --nw is that column: it follows --w, so overriding the measure moves the
205
+ --fertig-nw is that column: it follows --fertig-w, so overriding the measure moves the
192
206
  toolbar with it, and .wide re-points it at the wide column instead. */
193
- --nw: var(--w);
194
- padding-inline: max(1.9rem, calc(50% - var(--nw) / 2 + 1.9rem),
207
+ --fertig-nw: var(--fertig-w);
208
+ padding-inline: max(1.9rem, calc(50% - var(--fertig-nw) / 2 + 1.9rem),
195
209
  env(safe-area-inset-left), env(safe-area-inset-right));
196
210
  display: flex; flex-wrap: wrap; gap: 1.1rem; align-items: center;
197
211
  padding-block: calc(.6rem + env(safe-area-inset-top, 0px)) .6rem;
198
- background: var(--tb); color: var(--fg);
212
+ background: var(--fertig-tb); color: var(--fertig-fg);
199
213
  backdrop-filter: saturate(180%) blur(20px);
200
- border-bottom: 1px solid var(--bd); font-size: .92em;
214
+ border-bottom: 1px solid var(--fertig-bd); font-size: .92em;
201
215
  }
202
- :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav a { color: var(--fg); text-decoration: none; opacity: .75 }
216
+ :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav a { color: var(--fertig-fg); text-decoration: none; opacity: .75 }
203
217
  :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav a:hover { opacity: 1 }
204
218
  :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav :is(strong, b) a { opacity: 1 } /* the wordmark is not a link among links */
205
219
  :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav ul {
@@ -213,7 +227,7 @@ h1 { font-size: 1.55rem; letter-spacing: -.015em }
213
227
  h2 { font-size: 1.25rem; letter-spacing: -.01em; margin-top: 2.4rem }
214
228
  h3 { font-size: 1.08rem; margin-top: 1.9rem }
215
229
  h4 { font-size: 1rem }
216
- h5, h6 { font: 700 var(--caps); text-transform: uppercase; letter-spacing: .1em; color: var(--mut) }
230
+ h5, h6 { font: 700 var(--fertig-caps); text-transform: uppercase; letter-spacing: .1em; color: var(--fertig-mut) }
217
231
  :is(h1,h2,h3,h4,h5,h6):first-child { margin-top: 0 }
218
232
  @supports (text-box: trim-both cap alphabetic) {
219
233
  h1, h2, h3, h4 { text-box: trim-both cap alphabetic } /* optical, not metric */
@@ -223,37 +237,37 @@ h5, h6 { font: 700 var(--caps); text-transform: uppercase; letter-spacing: .1em;
223
237
 
224
238
  p, ul, ol, dl, pre, blockquote, table, figure, details, fieldset, hr { margin: 1.1rem 0 }
225
239
  p { text-wrap: pretty }
226
- a { color: var(--ac); text-underline-offset: 3px; text-decoration-thickness: 1px }
240
+ a { color: var(--fertig-ac); text-underline-offset: 3px; text-decoration-thickness: 1px }
227
241
  a:hover { text-decoration-thickness: 2px } /* quiet — no invert mid-paragraph */
228
- small { font-size: .85em; color: var(--mut) }
229
- hr { border: 0; border-top: 1px solid var(--bd); margin: 2.2rem 0 }
242
+ small { font-size: .85em; color: var(--fertig-mut) }
243
+ hr { border: 0; border-top: 1px solid var(--fertig-bd); margin: 2.2rem 0 }
230
244
  mark { background: light-dark(#ffe58f, #5c4a15); color: inherit; border-radius: 3px; padding: 0 .15em }
231
245
  abbr[title] { text-decoration: underline dotted; cursor: help }
232
246
  blockquote {
233
- border-inline-start: 2px solid var(--bd);
234
- padding-block: .15rem; padding-inline: 1.2rem 0; color: var(--mut);
247
+ border-inline-start: 2px solid var(--fertig-bd);
248
+ padding-block: .15rem; padding-inline: 1.2rem 0; color: var(--fertig-mut);
235
249
  }
236
250
  ul, ol { padding-inline-start: 1.5rem }
237
- li::marker { color: var(--mut) }
251
+ li::marker { color: var(--fertig-mut) }
238
252
  /* minmax(0, 1fr), not 1fr: a bare 1fr track has min-width:auto, so a long
239
253
  value cannot shrink and pushes the page sideways on a narrow screen. */
240
254
  dl { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: .35rem 1rem }
241
- dt { color: var(--mut) }
255
+ dt { color: var(--fertig-mut) }
242
256
  dd { margin: 0 }
243
- figcaption { font-size: .85em; color: var(--mut); text-align: center }
257
+ figcaption { font-size: .85em; color: var(--fertig-mut); text-align: center }
244
258
 
245
259
  /* ---- code --------------------------------------------------- */
246
- code, kbd, samp, pre { font-family: var(--fm); font-size: .9em }
260
+ code, kbd, samp, pre { font-family: var(--fertig-fm); font-size: .9em }
247
261
  :not(pre) > code, samp {
248
- background: var(--face); border: 1px solid var(--bd);
249
- border-radius: var(--rs); padding: .08em .35em;
262
+ background: var(--fertig-face); border: 1px solid var(--fertig-bd);
263
+ border-radius: var(--fertig-rs); padding: .08em .35em;
250
264
  }
251
265
  kbd {
252
- background: var(--face); border: 1px solid var(--bd); border-bottom-width: 2px;
253
- border-radius: var(--rs); padding: .08em .4em; box-shadow: var(--up);
266
+ background: var(--fertig-face); border: 1px solid var(--fertig-bd); border-bottom-width: 2px;
267
+ border-radius: var(--fertig-rs); padding: .08em .4em; box-shadow: var(--fertig-up);
254
268
  }
255
269
  pre {
256
- background: var(--face); border: 1px solid var(--bd); border-radius: var(--r);
270
+ background: var(--fertig-face); border: 1px solid var(--fertig-bd); border-radius: var(--fertig-rw);
257
271
  padding: 1rem; overflow-x: auto;
258
272
  }
259
273
  pre code { background: none; border: 0; padding: 0; font-size: 1em }
@@ -261,37 +275,37 @@ pre code { background: none; border: 0; padding: 0; font-size: 1em }
261
275
  /* Syntax theme. The sheet ships no highlighter — bring highlight.js or Prism
262
276
  and the tokens land in this palette, in both themes. */
263
277
  :root {
264
- --syn-comment: light-dark(#6b7280, #8b949e);
265
- --syn-key: light-dark(#7c3aed, #c4a7fb);
266
- --syn-str: light-dark(#15803d, #7ee787);
267
- --syn-num: light-dark(#b45309, #f0b866);
268
- --syn-fn: light-dark(#1d4ed8, #93c5fd);
269
- --syn-attr: light-dark(#b91c1c, #ff9492);
278
+ --fertig-syn-comment: light-dark(#6b7280, #8b949e);
279
+ --fertig-syn-key: light-dark(#7c3aed, #c4a7fb);
280
+ --fertig-syn-str: light-dark(#15803d, #7ee787);
281
+ --fertig-syn-num: light-dark(#b45309, #f0b866);
282
+ --fertig-syn-fn: light-dark(#1d4ed8, #93c5fd);
283
+ --fertig-syn-attr: light-dark(#b91c1c, #ff9492);
270
284
  }
271
285
  :is(.hljs-comment, .hljs-quote, .token.comment, .token.prolog, .token.doctype) {
272
- color: var(--syn-comment); font-style: italic;
286
+ color: var(--fertig-syn-comment); font-style: italic;
273
287
  }
274
288
  :is(.hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-type, .hljs-built_in,
275
289
  .token.keyword, .token.atrule, .token.rule, .token.important, .token.selector) {
276
- color: var(--syn-key);
290
+ color: var(--fertig-syn-key);
277
291
  }
278
292
  :is(.hljs-string, .hljs-meta-string, .token.string, .token.attr-value, .token.char) {
279
- color: var(--syn-str);
293
+ color: var(--fertig-syn-str);
280
294
  }
281
295
  :is(.hljs-number, .hljs-symbol, .hljs-bullet, .token.number, .token.boolean,
282
296
  .token.constant, .token.unit) {
283
- color: var(--syn-num);
297
+ color: var(--fertig-syn-num);
284
298
  }
285
299
  :is(.hljs-title, .hljs-name, .hljs-section, .hljs-function,
286
300
  .token.tag, .token.function, .token.class-name) {
287
- color: var(--syn-fn);
301
+ color: var(--fertig-syn-fn);
288
302
  }
289
303
  :is(.hljs-attr, .hljs-attribute, .hljs-variable, .hljs-template-variable,
290
304
  .token.attr-name, .token.property, .token.variable) {
291
- color: var(--syn-attr);
305
+ color: var(--fertig-syn-attr);
292
306
  }
293
307
  :is(.hljs-punctuation, .hljs-operator, .token.punctuation, .token.operator) {
294
- color: var(--mut);
308
+ color: var(--fertig-mut);
295
309
  }
296
310
  :is(.hljs-emphasis, .token.italic) { font-style: italic }
297
311
  :is(.hljs-strong, .token.bold) { font-weight: 700 }
@@ -301,31 +315,31 @@ pre code { background: none; border: 0; padding: 0; font-size: 1em }
301
315
  /* ---- table -------------------------------------------------- */
302
316
  table { width: 100%; border-collapse: collapse; font-size: .92em }
303
317
  th, td {
304
- border-bottom: 1px solid var(--bd); padding-block: .55rem;
318
+ border-bottom: 1px solid var(--fertig-bd); padding-block: .55rem;
305
319
  padding-inline: 0 .7rem; text-align: start;
306
320
  }
307
321
  th:last-child, td:last-child { padding-inline-end: 0 }
308
322
  thead th {
309
- border-bottom: 1px solid color-mix(in srgb, var(--fg) 45%, transparent);
310
- font: 700 var(--caps); text-transform: uppercase; letter-spacing: .09em; color: var(--mut);
323
+ border-bottom: 1px solid color-mix(in srgb, var(--fertig-fg) 45%, transparent);
324
+ font: 700 var(--fertig-caps); text-transform: uppercase; letter-spacing: .09em; color: var(--fertig-mut);
311
325
  padding-bottom: .4rem;
312
326
  }
313
327
  tbody tr:last-child td { border-bottom: 0 }
314
328
  /* a totals row is not just another row */
315
- tfoot td { font-weight: 700; border-top: 1px solid var(--bd); border-bottom: 0 }
329
+ tfoot td { font-weight: 700; border-top: 1px solid var(--fertig-bd); border-bottom: 0 }
316
330
  /* our text-align was overriding HTML own alignment; honour it for numbers */
317
331
  :is(th, td)[align=right] { text-align: right }
318
332
  :is(th, td)[align=center] { text-align: center }
319
- tbody tr:hover { background: var(--face) }
333
+ tbody tr:hover { background: var(--fertig-face) }
320
334
  @media (width <= 40rem) {
321
335
  table { display: block; overflow-x: auto; overscroll-behavior-x: contain }
322
336
  }
323
- caption { text-align: start; color: var(--mut); font-size: .85em; padding-bottom: .35rem }
337
+ caption { text-align: start; color: var(--fertig-mut); font-size: .85em; padding-bottom: .35rem }
324
338
 
325
339
  /* ---- forms: fields sink, buttons rise ------------------------ */
326
340
  button, input, select, textarea { font: inherit; color: inherit }
327
- label { display: block; font-size: .85em; color: var(--mut) }
328
- label:has(input) { font-size: 1rem; color: var(--fg) }
341
+ label { display: block; font-size: .85em; color: var(--fertig-mut) }
342
+ label:has(input) { font-size: 1rem; color: var(--fertig-fg) }
329
343
  /* a label following a field belongs to the next one: give it air, except in a
330
344
  .row, where the toolbar is horizontal and the margin would knock it askew */
331
345
  :is(input, select, textarea) + label { margin-top: .9rem }
@@ -335,17 +349,22 @@ textarea { width: 100%; min-height: 5rem; resize: vertical }
335
349
  }
336
350
  input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=image],[type=submit],[type=button],[type=reset]),
337
351
  select, textarea {
338
- display: block; width: 100%; padding: .52em .7em; background: var(--el);
339
- border: 1px solid var(--bd); border-radius: var(--r); box-shadow: var(--dn);
352
+ display: block; width: 100%; padding: .52em .7em; background: var(--fertig-el);
353
+ border: 1px solid var(--fertig-bd); border-radius: var(--fertig-r); box-shadow: var(--fertig-dn);
340
354
  }
341
355
  select {
342
356
  appearance: none; padding-inline-end: 2.2rem;
343
- background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
344
- linear-gradient(135deg, currentColor 50%, transparent 50%);
345
- background-position: calc(100% - 17px) 55%, calc(100% - 12.5px) 55%;
346
- background-size: 5px 5px; background-repeat: no-repeat;
347
- }
348
- select:dir(rtl) { background-position: 12.5px 55%, 17px 55% }
357
+ /* a stroked chevron, drawn as two 1.5px bars, so the engines without
358
+ appearance: base-select show the same mark as the ones with it */
359
+ background-image:
360
+ linear-gradient(45deg, transparent calc(50% - 1px), currentColor calc(50% - 1px),
361
+ currentColor calc(50% + .5px), transparent calc(50% + .5px)),
362
+ linear-gradient(-45deg, transparent calc(50% - 1px), currentColor calc(50% - 1px),
363
+ currentColor calc(50% + .5px), transparent calc(50% + .5px));
364
+ background-position: calc(100% - 17px) 54%, calc(100% - 12px) 54%;
365
+ background-size: 6px 6px; background-repeat: no-repeat;
366
+ }
367
+ select:dir(rtl) { background-position: 12px 54%, 17px 54% }
349
368
  select[multiple] { background-image: none; padding-inline-end: .6em }
350
369
 
351
370
  /* a <select> whose dropdown can finally be styled like the rest of the sheet */
@@ -359,83 +378,101 @@ select[multiple] { background-image: none; padding-inline-end: .6em }
359
378
  content: ""; inline-size: .45em; block-size: .45em; flex: none;
360
379
  border: solid currentColor; border-width: 0 1px 1px 0;
361
380
  rotate: 45deg; translate: 0 -.15em; opacity: .7;
362
- transition: rotate var(--dur-1) var(--ease), translate var(--dur-1) var(--ease);
381
+ transition: rotate var(--fertig-dur-1) var(--fertig-ease), translate var(--fertig-dur-1) var(--fertig-ease);
363
382
  }
364
383
  select:open::picker-icon { rotate: 225deg; translate: 0 .1em }
365
384
  ::picker(select) {
366
385
  min-width: anchor-size(width); /* never narrower than the field */
367
- border: 1px solid var(--bd); border-radius: var(--r); padding: .3rem;
368
- background: var(--el); margin-block-start: .35rem;
369
- box-shadow: var(--up2), 0 20px 40px -14px color-mix(in srgb, var(--sh) 40%, transparent);
386
+ border: 1px solid var(--fertig-bd); border-radius: var(--fertig-rw); padding: .35rem;
387
+ background: var(--fertig-el); margin-block-start: .35rem;
388
+ box-shadow: var(--fertig-up2), 0 24px 44px -18px color-mix(in srgb, var(--fertig-sh) 28%, transparent);
370
389
  }
371
390
  option {
372
391
  display: flex; align-items: center; gap: .5em; padding: .4em .6em;
373
- border-radius: calc(var(--r) - 2px);
392
+ border-radius: calc(var(--fertig-r) - 2px);
374
393
  }
375
- option:hover { background: var(--face) }
376
- option:checked { background: var(--ac); color: var(--on-ac) }
394
+ option:hover { background: var(--fertig-face) }
395
+ option:checked { background: var(--fertig-ac); color: var(--fertig-on-ac) }
377
396
  option::checkmark { order: 1; margin-inline-start: auto; content: "✓" }
397
+ /* The picker drops out of the field the way the menu popover does. It lives
398
+ in the top layer, so display and overlay have to transition discretely or
399
+ it would pop out on close with the fade never running. */
400
+ @media (prefers-reduced-motion: no-preference) and (update: fast) {
401
+ ::picker(select) {
402
+ opacity: 0; translate: 0 -4px; transform-origin: top center;
403
+ transition: opacity .13s var(--fertig-ease-out), translate .13s var(--fertig-ease-out),
404
+ display .13s allow-discrete, overlay .13s allow-discrete;
405
+ }
406
+ select:open::picker(select) { opacity: 1; translate: 0 }
407
+ @starting-style { select:open::picker(select) { opacity: 0; translate: 0 -4px } }
408
+ }
378
409
  }
379
- :is(input,select,textarea):hover:not(:disabled) { border-color: color-mix(in srgb, var(--fg) 25%, transparent) }
380
- :is(input,select,textarea):focus-visible { border-color: var(--ac) }
410
+ :is(input,select,textarea):hover:not(:disabled) { border-color: color-mix(in srgb, var(--fertig-fg) 25%, transparent) }
411
+ :is(input,select,textarea):focus-visible { border-color: var(--fertig-ac) }
381
412
  input[type=checkbox], input[type=radio] {
382
- width: 1.15em; height: 1.15em; margin: 0 .45em 0 0; vertical-align: -.18em;
413
+ width: 1.15em; height: 1.15em; margin: 0; margin-inline-end: .45em; vertical-align: -.18em;
383
414
  }
415
+ /* re-resolved here rather than inherited from :root, so a native control inside
416
+ a [data-accent] or [data-tone] block is tinted with that block's accent */
417
+ :is(input[type=checkbox], input[type=radio], input[type=range], progress, select[multiple]) {
418
+ accent-color: var(--fertig-ac);
419
+ }
420
+ :is(input, textarea, [contenteditable]) { caret-color: var(--fertig-ac) }
384
421
  label:has(input[type=checkbox]), label:has(input[type=radio]) { line-height: 1.9 }
385
422
  input[type=range] { width: 100%; height: 1.15em }
386
- ::placeholder { color: var(--mut) }
423
+ ::placeholder { color: var(--fertig-mut) }
387
424
  @supports selector(::spelling-error) {
388
425
  ::spelling-error { text-decoration: wavy underline light-dark(#c0392b, #ff6b6b) }
389
426
  ::grammar-error { text-decoration: wavy underline light-dark(#9a6700, #d29922) }
390
427
  }
391
- :is(input, textarea):read-only:not(:disabled) { background: var(--face); cursor: default }
428
+ :is(input, textarea):read-only:not(:disabled) { background: var(--fertig-face); cursor: default }
392
429
  label:has(+ :required)::after, label:has(:required)::after {
393
- content: " *"; color: var(--ac); /* mark what is actually required */
430
+ content: " *"; color: var(--fertig-ac); /* mark what is actually required */
394
431
  }
395
432
  /* the browser paints autofilled fields yellow; repaint them ourselves */
396
433
  input:autofill, input:autofill:hover, input:autofill:focus {
397
- -webkit-text-fill-color: var(--fg);
398
- box-shadow: var(--dn), inset 0 0 0 100px var(--el);
399
- caret-color: var(--ac);
434
+ -webkit-text-fill-color: var(--fertig-fg);
435
+ box-shadow: var(--fertig-dn), inset 0 0 0 100px var(--fertig-el);
436
+ caret-color: var(--fertig-ac);
400
437
  }
401
- :disabled { color: var(--mut); cursor: not-allowed; box-shadow: none }
438
+ :disabled { color: var(--fertig-mut); cursor: not-allowed; box-shadow: none }
402
439
  /* No notched border: the legend becomes the panel title. The float is not
403
440
  nostalgia — a legend keeps its magic placement under block, grid and flex
404
441
  fieldsets alike, and floating it is still the only way out. */
405
442
  fieldset {
406
- border: 1px solid var(--bd); border-radius: var(--r); padding: .9rem 1rem 1rem;
407
- background: var(--face);
443
+ border: 1px solid var(--fertig-bd); border-radius: var(--fertig-rw); padding: .9rem 1rem 1rem;
444
+ background: var(--fertig-face);
408
445
  }
409
- fieldset:focus-within { border-color: color-mix(in srgb, var(--ac) 45%, var(--bd)) }
446
+ fieldset:focus-within { border-color: color-mix(in srgb, var(--fertig-ac) 45%, var(--fertig-bd)) }
410
447
  legend {
411
448
  float: left; width: 100%; margin-bottom: .8rem; padding: 0 0 .6rem;
412
- border-bottom: 1px solid var(--bd);
413
- font-size: .95em; font-weight: 700; color: var(--fg);
449
+ border-bottom: 1px solid var(--fertig-bd);
450
+ font-size: .95em; font-weight: 700; color: var(--fertig-fg);
414
451
  }
415
452
  legend + * { clear: left }
416
453
 
417
454
  button, [type=submit], [type=button], [type=reset],
418
455
  :where(a.primary, a[role=button]), ::file-selector-button {
419
456
  display: inline-block; text-decoration: none; text-align: center;
420
- padding: .48em 1.1em; background: var(--el); color: var(--fg); cursor: pointer;
421
- border: 1px solid var(--bd); border-radius: var(--r); box-shadow: var(--up);
457
+ padding: .48em 1.1em; background: var(--fertig-el); color: var(--fertig-fg); cursor: pointer;
458
+ border: 1px solid var(--fertig-bd); border-radius: var(--fertig-rp); box-shadow: var(--fertig-up);
422
459
  font: inherit; min-width: 5rem;
423
460
  }
424
- :is(button,[type=submit],[type=button],[type=reset],a.primary,a[role=button]):hover:not(:disabled) { background: var(--face) }
461
+ :is(button,[type=submit],[type=button],[type=reset],a.primary,a[role=button]):hover:not(:disabled) { background: var(--fertig-face) }
425
462
  :is(button,[type=submit],[type=button],[type=reset],a.primary,a[role=button]):active:not(:disabled) {
426
- box-shadow: var(--dn); translate: 0 .5px;
463
+ box-shadow: var(--fertig-dn); translate: 0 .5px;
427
464
  }
428
- [type=submit], .primary { background: var(--ac); border-color: transparent; color: var(--on-ac) }
465
+ [type=submit], .primary { background: var(--fertig-ac); border-color: transparent; color: var(--fertig-on-ac) }
429
466
  /* The filled button lightens on hover. color-mix does that in oklab, which is
430
467
  close enough and is Baseline; relative colour does it by adding to L
431
- directly, which holds the hue exactly when --ac is a wide-gamut override.
432
- Both derive from --ac, so a custom accent never needs a second declaration. */
468
+ directly, which holds the hue exactly when --fertig-ac is a wide-gamut override.
469
+ Both derive from --fertig-ac, so a custom accent never needs a second declaration. */
433
470
  :is([type=submit], .primary, a.primary):hover:not(:disabled) {
434
- background: color-mix(in oklab, var(--ac), #fff 9%);
471
+ background: color-mix(in oklab, var(--fertig-ac), #fff 9%);
435
472
  }
436
473
  @supports (color: oklch(from red l c h)) {
437
474
  :is([type=submit], .primary, a.primary):hover:not(:disabled) {
438
- background: oklch(from var(--ac) calc(l + .05) c h);
475
+ background: oklch(from var(--fertig-ac) calc(l + .05) c h);
439
476
  }
440
477
  }
441
478
 
@@ -448,18 +485,18 @@ button, [type=submit], [type=button], [type=reset],
448
485
  button[data-icon] { min-width: 0; padding: .38em .62em; line-height: 1 }
449
486
  :is(button, a, input, select, label)[data-block] { display: block; width: 100%; min-width: 0 }
450
487
  :is(button, a, input)[data-variant=ghost] { background: none; border-color: transparent; box-shadow: none }
451
- :is(button, a, input)[data-variant=ghost]:hover:not(:disabled) { background: var(--face); border-color: var(--bd) }
488
+ :is(button, a, input)[data-variant=ghost]:hover:not(:disabled) { background: var(--fertig-face); border-color: var(--fertig-bd) }
452
489
  :is(button, a, input)[data-variant=link] {
453
490
  background: none; border: 0; box-shadow: none; min-width: 0; padding-inline: .2em;
454
- color: var(--ac); text-decoration: underline; text-underline-offset: 3px;
491
+ color: var(--fertig-ac); text-decoration: underline; text-underline-offset: 3px;
455
492
  }
456
493
  :is(button, a, input)[data-variant=link]:hover:not(:disabled) { background: none; text-decoration-thickness: 2px }
457
- button[aria-pressed=true] { background: var(--face); color: var(--ac); font-weight: 700 }
494
+ button[aria-pressed=true] { background: var(--fertig-face); color: var(--fertig-ac); font-weight: 700 }
458
495
  button[aria-pressed=true]:hover:not(:disabled) {
459
- background: color-mix(in srgb, var(--fg) 7%, var(--face));
496
+ background: color-mix(in srgb, var(--fertig-fg) 7%, var(--fertig-face));
460
497
  }
461
498
  /* filled buttons get a lit top edge, the way a real control does */
462
- :is([type=submit], .primary) { box-shadow: var(--up), inset 0 1px 0 light-dark(#ffffff33, #ffffff26) }
499
+ :is([type=submit], .primary) { box-shadow: var(--fertig-up), inset 0 1px 0 light-dark(#ffffff33, #ffffff26) }
463
500
  :is([type=submit], .primary):active:not(:disabled) { box-shadow: inset 0 1px 3px #0006 }
464
501
 
465
502
  @supports (corner-shape: squircle) {
@@ -474,51 +511,79 @@ button[aria-pressed=true]:hover:not(:disabled) {
474
511
 
475
512
  /* ---- disclosure / misc -------------------------------------- */
476
513
  details {
477
- border: 1px solid var(--bd); border-radius: var(--r);
478
- padding: .7rem 1.1rem; background: var(--el);
514
+ border: 1px solid var(--fertig-bd); border-radius: var(--fertig-rw);
515
+ padding: .7rem 1.1rem; background: var(--fertig-el);
479
516
  }
480
517
  summary { cursor: pointer; font-weight: 700; list-style: none }
481
- summary::before { content: "▸ "; color: var(--mut) }
518
+ summary::before { content: "▸ "; color: var(--fertig-mut) }
482
519
  details[open] > summary::before { content: "▾ " }
483
520
  details[open] > summary { margin-bottom: .6rem }
484
521
  dialog {
485
- background: var(--el); color: var(--fg); border: 1px solid var(--bd);
486
- border-radius: var(--rw); padding: 1.4rem; max-width: min(30rem, 92dvw);
487
- box-shadow: 0 32px 64px -16px color-mix(in srgb, var(--sh) 45%, transparent);
522
+ background: var(--fertig-el); color: var(--fertig-fg); border: 1px solid var(--fertig-bd);
523
+ border-radius: var(--fertig-rw); padding: 1.6rem; max-width: min(30rem, 92dvw);
524
+ box-shadow: 0 1px 1px color-mix(in srgb, var(--fertig-sh) 8%, transparent),
525
+ 0 28px 60px -22px color-mix(in srgb, var(--fertig-sh) 28%, transparent);
488
526
  }
489
527
  dialog > :last-child:not(footer) { margin-bottom: 0 }
490
528
  dialog, [popover] { overscroll-behavior: contain }
491
- dialog::backdrop { background: color-mix(in srgb, var(--sh) 35%, transparent); backdrop-filter: blur(3px) }
529
+ dialog::backdrop { background: color-mix(in srgb, var(--fertig-sh) 32%, transparent); backdrop-filter: blur(4px) }
492
530
 
493
531
  /* dialog anatomy: an optional header and footer, pinned while the body scrolls.
494
532
  Sticky rather than a grid, because a classless sheet has no wrapper around
495
- the loose middle children to make a grid row out of. */
533
+ the loose middle children to make a grid row out of.
534
+ No dividing rules: a short dialog cut into three banded strips is the look
535
+ of a decade-old modal. The separation is spacing, and the hairline only
536
+ arrives when there is actually something scrolling under it — see below. */
496
537
  dialog:has(> :is(header, footer)) { max-block-size: min(44rem, 85dvh); overflow: auto }
497
538
  dialog > :is(header, footer) {
498
539
  position: sticky; z-index: 1;
499
- margin-inline: -1.4rem; padding: .7rem 1.4rem;
500
- background: var(--el); /* the dialog's own surface, so it reads as one sheet */
540
+ margin-inline: -1.6rem;
541
+ background: var(--fertig-el); /* the dialog's own surface, so it reads as one sheet */
501
542
  }
502
543
  dialog > header {
503
- inset-block-start: -1.4rem; margin-block: -1.4rem 1rem;
504
- font-weight: 700; border-bottom: 1px solid var(--bd);
505
- border-radius: var(--rw) var(--rw) 0 0;
544
+ inset-block-start: -1.6rem; margin-block: -1.6rem .35rem;
545
+ padding: 1.6rem 1.6rem .5rem; font-weight: 700;
546
+ border-radius: var(--fertig-rw) var(--fertig-rw) 0 0;
547
+ }
548
+ /* The title carries the header's weight, so it needs no margins of its own,
549
+ and it is UI text: it takes --fertig-f, the interface face, not whatever
550
+ display font the page gave its headings — a monospaced heading face reads
551
+ as a terminal once it sits on a dialog. :is([open], :modal) is there for
552
+ weight — a page's `.prose h3` outranks a bare element chain, and the title
553
+ would come out sized and lettered for the article column it is nowhere near. */
554
+ dialog:is([open], :modal) > header > :is(h1, h2, h3, h4, p) {
555
+ margin: 0; font-family: var(--fertig-f); font-size: 1.1rem; font-weight: 600;
556
+ line-height: 1.3; letter-spacing: -.01em;
506
557
  }
507
- /* the title carries the header's weight; it does not need its own margins */
508
- dialog > header > :is(h1, h2, h3, h4, p) { margin: 0; font-size: 1.05rem }
509
558
  dialog > footer {
510
- inset-block-end: -1.4rem; margin-block: 1rem -1.4rem;
511
- border-top: 1px solid var(--bd); border-radius: 0 0 var(--rw) var(--rw);
559
+ inset-block-end: -1.6rem; margin-block: 1.35rem -1.6rem;
560
+ padding: .5rem 1.6rem 1.6rem; border-radius: 0 0 var(--fertig-rw) var(--fertig-rw);
512
561
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
513
562
  justify-content: flex-end; /* actions sit at the end edge */
514
563
  }
564
+ /* The hairline is scroll state, not decoration: it appears under the header
565
+ once the body has scrolled, and leaves the footer once you reach the end.
566
+ A scroll timeline on a container with nothing to scroll is inactive, so a
567
+ dialog that fits shows no rules at all and no script decides that. */
568
+ @supports (animation-timeline: scroll()) {
569
+ dialog > header {
570
+ animation: fertig-rule-under linear both;
571
+ animation-timeline: scroll(nearest); animation-range: 0 1.2rem;
572
+ }
573
+ dialog > footer {
574
+ animation: fertig-rule-over linear both;
575
+ animation-timeline: scroll(nearest); animation-range: calc(100% - 1.2rem) 100%;
576
+ }
577
+ @keyframes fertig-rule-under { from { box-shadow: none } to { box-shadow: 0 1px 0 var(--fertig-bd) } }
578
+ @keyframes fertig-rule-over { from { box-shadow: 0 -1px 0 var(--fertig-bd) } to { box-shadow: none } }
579
+ }
515
580
  /* a note beside the buttons pushes them over, rather than sitting under them */
516
- dialog > footer > :is(p, span):first-child { margin: 0; margin-inline-end: auto; color: var(--mut) }
581
+ dialog > footer > :is(p, span):first-child { margin: 0; margin-inline-end: auto; color: var(--fertig-mut) }
517
582
  /* sheets come up, they do not appear */
518
583
  @media (prefers-reduced-motion: no-preference) and (update: fast) {
519
584
  dialog, dialog::backdrop {
520
- transition: opacity var(--dur-2) var(--ease-out), translate var(--dur-2) var(--ease-out),
521
- display var(--dur-2) allow-discrete, overlay var(--dur-2) allow-discrete;
585
+ transition: opacity var(--fertig-dur-2) var(--fertig-ease-out), translate var(--fertig-dur-2) var(--fertig-ease-out),
586
+ display var(--fertig-dur-2) allow-discrete, overlay var(--fertig-dur-2) allow-discrete;
522
587
  }
523
588
  dialog { opacity: 0; translate: 0 10px }
524
589
  dialog[open] { opacity: 1; translate: 0 }
@@ -528,24 +593,24 @@ dialog > footer > :is(p, span):first-child { margin: 0; margin-inline-end: auto;
528
593
  @starting-style { dialog[open]::backdrop { opacity: 0 } }
529
594
  [popover] {
530
595
  opacity: 0; translate: 0 -4px;
531
- transition: opacity .13s var(--ease-out), translate .13s var(--ease-out),
596
+ transition: opacity .13s var(--fertig-ease-out), translate .13s var(--fertig-ease-out),
532
597
  display .13s allow-discrete, overlay .13s allow-discrete;
533
598
  }
534
599
  [popover]:popover-open { opacity: 1; translate: 0 }
535
600
  @starting-style { [popover]:popover-open { opacity: 0; translate: 0 -4px } }
536
601
  }
537
602
  search { display: block; margin-block: 1.1rem } /* a landmark needs its own rhythm */
538
- ::target-text { background: color-mix(in srgb, var(--ac) 28%, transparent) }
603
+ ::target-text { background: color-mix(in srgb, var(--fertig-ac) 28%, transparent) }
539
604
  aside {
540
- border: 1px solid var(--bd); border-inline-start: 3px solid var(--ac);
541
- border-radius: var(--r); border-start-start-radius: 0; border-end-start-radius: 0;
542
- background: var(--el); padding: .7rem 1.1rem;
605
+ border: 1px solid var(--fertig-bd); border-inline-start: 3px solid var(--fertig-ac);
606
+ border-radius: var(--fertig-rw); border-start-start-radius: 0; border-end-start-radius: 0;
607
+ background: var(--fertig-el); padding: .7rem 1.1rem;
543
608
  margin-block: 1.1rem; /* or the next block sits flush against it */
544
609
  }
545
- progress { width: 100%; height: .5rem; border: 0; border-radius: calc(infinity * 1px); background: var(--face) }
546
- progress::-webkit-progress-bar { background: var(--face); border-radius: calc(infinity * 1px) }
547
- progress::-webkit-progress-value { background: var(--ac); border-radius: calc(infinity * 1px) }
548
- progress::-moz-progress-bar { background: var(--ac); border-radius: calc(infinity * 1px) }
610
+ progress { width: 100%; height: .5rem; border: 0; border-radius: var(--fertig-rp); background: var(--fertig-face) }
611
+ progress::-webkit-progress-bar { background: var(--fertig-face); border-radius: var(--fertig-rp) }
612
+ progress::-webkit-progress-value { background: var(--fertig-ac); border-radius: var(--fertig-rp) }
613
+ progress::-moz-progress-bar { background: var(--fertig-ac); border-radius: var(--fertig-rp) }
549
614
 
550
615
  /* details can only animate to auto height once keywords interpolate */
551
616
  @supports selector(::details-content) {
@@ -556,63 +621,71 @@ progress::-moz-progress-bar { background: var(--ac); border-radius: calc(infinit
556
621
  details { interpolate-size: allow-keywords }
557
622
  details::details-content {
558
623
  block-size: 0; overflow: clip;
559
- transition: block-size .28s var(--ease), content-visibility .28s allow-discrete;
624
+ transition: block-size .28s var(--fertig-ease), content-visibility .28s allow-discrete;
560
625
  }
561
626
  details[open]::details-content { block-size: auto }
562
627
  }
563
628
  }
564
629
 
565
- /* #core-omit-start */
566
630
  /* ---- components, addressed by ARIA rather than by class ----- */
567
631
 
568
632
  /* segmented control: <div role=group> of buttons */
569
633
  /* max-inline-size + scroll, or a group of four or more buttons pushes the
570
634
  whole page sideways on a narrow screen. It scrolls rather than wraps:
571
- wrapping would break the joined-pill run of radii into separate rows. */
572
- [role=group] { display: inline-flex; vertical-align: middle;
573
- max-inline-size: 100%; overflow-x: auto; overscroll-behavior-x: contain }
635
+ wrapping would break the joined-pill run of radii into separate rows.
636
+ The block axis is clipped rather than left to compute to auto alongside it:
637
+ Safari paints a vertical scrollbar for a sub-pixel of overflow, and the row
638
+ has no vertical overflow worth scrolling to in the first place. */
639
+ [role=group] { display: inline-flex; vertical-align: middle; max-inline-size: 100%;
640
+ overflow: auto clip; overscroll-behavior-x: contain }
574
641
  [role=group] > * { border-radius: 0; margin-inline-start: -1px; box-shadow: none; min-width: 0 }
642
+ /* The buttons fill the group exactly and the group clips on the block axis,
643
+ so an outset ring would be sliced off. Inside the edge, it is all there. */
644
+ [role=group] > :focus-visible { outline-offset: -3px }
575
645
  [role=group] > :first-child {
576
646
  margin-inline-start: 0;
577
- border-start-start-radius: var(--r); border-end-start-radius: var(--r);
647
+ border-start-start-radius: var(--fertig-rp); border-end-start-radius: var(--fertig-rp);
578
648
  }
579
649
  [role=group] > :last-child {
580
- border-start-end-radius: var(--r); border-end-end-radius: var(--r);
650
+ border-start-end-radius: var(--fertig-rp); border-end-end-radius: var(--fertig-rp);
581
651
  }
582
- [role=group] > [aria-pressed=true] { background: var(--face); color: var(--ac); font-weight: 700 }
652
+ [role=group] > [aria-pressed=true] { background: var(--fertig-face); color: var(--fertig-ac); font-weight: 700 }
653
+ /* The press nudge would push a button half a pixel past the scroll port and
654
+ flash a scrollbar, so joined buttons stay put and read the press by shadow. */
655
+ [role=group] > :active:not(:disabled) { translate: none }
583
656
 
584
657
  /* tabs: <div role=tablist> of <button role=tab aria-selected> */
585
- [role=tablist] { display: flex; gap: .1rem; border-bottom: 1px solid var(--bd); margin: 1.1rem 0 }
658
+ [role=tablist] { display: flex; gap: .1rem; border-bottom: 1px solid var(--fertig-bd); margin: 1.1rem 0 }
586
659
  [role=tab] {
587
- background: none; border: 0; box-shadow: none; min-width: 0; color: var(--mut);
588
- padding: .45em .9em; border-radius: var(--r) var(--r) 0 0; margin-bottom: -1px;
660
+ background: none; border: 0; box-shadow: none; min-width: 0; color: var(--fertig-mut);
661
+ padding: .45em .9em; border-radius: var(--fertig-r) var(--fertig-r) 0 0; margin-bottom: -1px;
589
662
  }
590
- [role=tab]:hover:not(:disabled) { background: var(--face); color: var(--fg) }
591
- [role=tab][aria-selected=true] { color: var(--fg); box-shadow: inset 0 -2px 0 var(--ac) }
663
+ [role=tab]:hover:not(:disabled) { background: var(--fertig-face); color: var(--fertig-fg) }
664
+ [role=tab][aria-selected=true] { color: var(--fertig-fg); box-shadow: inset 0 -2px 0 var(--fertig-ac) }
592
665
 
593
666
  /* switch: <input type=checkbox role=switch> */
594
667
  input[type=checkbox][switch],
595
668
  input[type=checkbox][role=switch] {
596
- appearance: none; width: 2.2em; height: 1.3em; border-radius: calc(infinity * 1px); border: 0;
597
- background: color-mix(in srgb, var(--fg) 20%, transparent);
669
+ appearance: none; width: 2.2em; height: 1.3em; border-radius: var(--fertig-rp); border: 0;
670
+ background: color-mix(in srgb, var(--fertig-fg) 20%, transparent);
598
671
  position: relative; cursor: pointer; vertical-align: -.3em; margin-inline-end: .5em;
599
672
  }
600
673
  input[switch]::after, input[role=switch]::after {
601
674
  content: ""; position: absolute; inset-block-start: .14em; inset-inline-start: .14em;
602
- width: 1.02em; height: 1.02em; border-radius: 50%; background: #fff; box-shadow: var(--up);
603
- transition: translate .16s var(--ease-out);
675
+ width: 1.02em; height: 1.02em; border-radius: 50%; background: #fff; box-shadow: var(--fertig-up);
676
+ transition: translate .16s var(--fertig-ease-out);
604
677
  }
605
- input[switch]:checked, input[role=switch]:checked { background: var(--ac) }
678
+ input[switch]:checked, input[role=switch]:checked { background: var(--fertig-ac) }
606
679
  /* translate is physical, so the knob is told which way to travel */
607
680
  input[switch]:checked::after, input[role=switch]:checked::after { translate: .9em 0 }
608
681
  :is(input[switch], input[role=switch]):checked:dir(rtl)::after { translate: -.9em 0 }
609
682
 
610
683
  /* menu: any [popover] */
611
684
  [popover] {
612
- background: var(--el); color: var(--fg); border: 1px solid var(--bd);
613
- border-radius: var(--r); padding: .3rem; min-width: 12rem;
685
+ background: var(--fertig-el); color: var(--fertig-fg); border: 1px solid var(--fertig-bd);
686
+ border-radius: var(--fertig-rw); padding: .35rem; min-width: 12rem;
614
687
  max-block-size: 60dvh; overflow: auto; font-size: .95em;
615
- box-shadow: var(--up2), 0 20px 40px -14px color-mix(in srgb, var(--sh) 40%, transparent);
688
+ box-shadow: var(--fertig-up2), 0 24px 44px -18px color-mix(in srgb, var(--fertig-sh) 28%, transparent);
616
689
  }
617
690
  /* anchor to the invoking button; without support it centres, which is fine.
618
691
  Deliberately NOT scoped to :popover-open — the close is transitioned, so a
@@ -639,14 +712,14 @@ input[switch]:checked::after, input[role=switch]:checked::after { translate: .9e
639
712
  [popover] :is(a, button):not(:disabled) {
640
713
  display: block; width: 100%; text-align: start; background: none; border: 0;
641
714
  box-shadow: none; min-width: 0; padding: .4em .6em; text-decoration: none;
642
- color: inherit; border-radius: calc(var(--r) - 2px); font-weight: 400;
715
+ color: inherit; border-radius: calc(var(--fertig-r) - 2px); font-weight: 400;
643
716
  }
644
- [popover] :is(a, button):hover:not(:disabled) { background: var(--ac); color: var(--on-ac) }
717
+ [popover] :is(a, button):hover:not(:disabled) { background: var(--fertig-ac); color: var(--fertig-on-ac) }
645
718
  [popover] hr { margin: .3rem 0 }
646
719
 
647
720
  /* breadcrumbs: <nav aria-label="Breadcrumb"><ol> */
648
721
  nav[aria-label] ol { display: flex; flex-wrap: wrap; gap: .5em; list-style: none; padding: 0; font-size: .9em }
649
- nav[aria-label] ol li + li::before { content: "/"; margin-inline-end: .5em; color: var(--mut) }
722
+ nav[aria-label] ol li + li::before { content: "/"; margin-inline-end: .5em; color: var(--fertig-mut) }
650
723
 
651
724
  /* busy: [aria-busy=true] */
652
725
  [aria-busy=true] { cursor: progress }
@@ -671,16 +744,18 @@ nav[aria-label] ol li + li::before { content: "/"; margin-inline-end: .5em; colo
671
744
  inset-block-end: 100%; inset-inline-start: 50%;
672
745
  translate: -50% -.45em; z-index: 10; white-space: nowrap; pointer-events: none;
673
746
  background: light-dark(#1d1d1f, #3a3a40); color: #fff; font-size: .8em;
674
- padding: .25em .55em; border-radius: var(--r); box-shadow: var(--up2);
747
+ padding: .25em .55em; border-radius: var(--fertig-r); box-shadow: var(--fertig-up2);
675
748
  }
676
749
  /* translate is physical; the offset has to be told which way to go */
677
750
  [data-tooltip]:dir(rtl)::after { translate: 50% -.45em }
678
751
 
679
752
  /* tones: retint any component by redefining its accent */
680
- [data-tone=ok] { --ac: light-dark(var(--sage-700), oklch(76% .085 155)) }
681
- [data-tone=warn] { --ac: light-dark(var(--gold-700), oklch(80% .095 85)) }
682
- [data-tone=err] { --ac: light-dark(var(--clay-700), oklch(75% .105 35)) }
683
- [data-tone] .badge, .badge[data-tone] { color: var(--ac); border-color: var(--ac) }
753
+ [data-tone=ok] { --fertig-ac: light-dark(var(--fertig-sage-700), oklch(76% .085 155)) }
754
+ [data-tone=warn] { --fertig-ac: light-dark(var(--fertig-gold-700), oklch(80% .095 85)) }
755
+ /* err is the one tone that does not come from the palette: clay at this
756
+ lightness reads as brown, and a destructive button has to read as red. */
757
+ [data-tone=err] { --fertig-ac: light-dark(oklch(52% .16 27), oklch(74% .13 25)) }
758
+ [data-tone] .badge, .badge[data-tone] { color: var(--fertig-ac); border-color: var(--fertig-ac) }
684
759
 
685
760
  /* ---- parity with the component libraries --------------------- */
686
761
 
@@ -688,18 +763,18 @@ nav[aria-label] ol li + li::before { content: "/"; margin-inline-end: .5em; colo
688
763
  [data-avatar] {
689
764
  display: inline-grid; place-items: center; flex: none; overflow: hidden;
690
765
  inline-size: 2.5rem; aspect-ratio: 1; border-radius: 50%;
691
- background: var(--face); border: 1px solid var(--bd);
692
- font-size: .8em; font-weight: 700; color: var(--mut); object-fit: cover;
766
+ background: var(--fertig-face); border: 1px solid var(--fertig-bd);
767
+ font-size: .8em; font-weight: 700; color: var(--fertig-mut); object-fit: cover;
693
768
  }
694
769
  [data-avatar=sm] { inline-size: 1.75rem; font-size: .7em }
695
770
  [data-avatar=lg] { inline-size: 3.5rem; font-size: 1em }
696
771
 
697
772
  /* skeleton: put it on the element that is still loading */
698
773
  [data-skeleton] {
699
- color: transparent; border-radius: var(--r); pointer-events: none;
774
+ color: transparent; border-radius: var(--fertig-r); pointer-events: none;
700
775
  user-select: none; min-height: 1em;
701
- background: linear-gradient(90deg, var(--face),
702
- color-mix(in srgb, var(--fg) 9%, var(--face)), var(--face));
776
+ background: linear-gradient(90deg, var(--fertig-face),
777
+ color-mix(in srgb, var(--fertig-fg) 9%, var(--fertig-face)), var(--fertig-face));
703
778
  background-size: 200% 100%;
704
779
  }
705
780
  [data-skeleton] * { visibility: hidden }
@@ -708,7 +783,13 @@ nav[aria-label] ol li + li::before { content: "/"; margin-inline-end: .5em; colo
708
783
  @keyframes fertig-shimmer { to { background-position: -200% 0 } }
709
784
  }
710
785
 
711
- /* sheet / drawer: the same <dialog>, docked to an edge */
786
+ /* sheet / drawer: the same <dialog>, docked to an edge.
787
+ Docked to a physical edge on purpose — "right" means the right edge of the
788
+ screen, not the end of the writing direction. inset is physical, so a drawer
789
+ slides in from the edge its name promises no matter the direction. The
790
+ translate is physical for the same reason: 100% of the drawer's own inline
791
+ width moves it off the edge it came from. RTL readers still get the same
792
+ right/left drawer as anyone else; direction would make "right" ambiguous. */
712
793
  dialog[data-side] { max-width: none; margin: 0; border-radius: 0; padding: 1.4rem }
713
794
  dialog[data-side=right] {
714
795
  inset: 0 0 0 auto; block-size: 100dvh; inline-size: min(28rem, 92dvw);
@@ -720,7 +801,7 @@ dialog[data-side=left] {
720
801
  }
721
802
  dialog[data-side=bottom] {
722
803
  inset: auto 0 0 0; inline-size: 100%; max-block-size: 85dvh;
723
- border-radius: var(--rw) var(--rw) 0 0; border-bottom: 0;
804
+ border-radius: var(--fertig-rw) var(--fertig-rw) 0 0; border-bottom: 0;
724
805
  }
725
806
  @media (prefers-reduced-motion: no-preference) and (update: fast) {
726
807
  dialog[data-side=right] { translate: 100% 0 }
@@ -760,9 +841,9 @@ dialog[data-side=bottom] {
760
841
  [popover][data-toast-region] > [data-toast] {
761
842
  pointer-events: auto; position: static; inset: auto;
762
843
  min-width: 16rem; max-width: min(24rem, 92dvw); padding: .8rem 1rem;
763
- background: var(--el); color: var(--fg); border: 1px solid var(--bd);
764
- border-radius: var(--r); font-size: .95em;
765
- box-shadow: var(--up2), 0 20px 40px -14px color-mix(in srgb, var(--sh) 40%, transparent);
844
+ background: var(--fertig-el); color: var(--fertig-fg); border: 1px solid var(--fertig-bd);
845
+ border-radius: var(--fertig-rw); font-size: .95em;
846
+ box-shadow: var(--fertig-up2), 0 24px 44px -18px color-mix(in srgb, var(--fertig-sh) 28%, transparent);
766
847
  }
767
848
  @supports (position-area: block-end span-inline-end) {
768
849
  [popover][data-toast-region] { position-area: none; inset: auto 1rem 1rem auto }
@@ -771,10 +852,10 @@ dialog[data-side=bottom] {
771
852
  /* list group: a plain <menu> outside a popover is a bordered list */
772
853
  menu {
773
854
  list-style: none; padding: 0; margin: 1.1rem 0;
774
- border: 1px solid var(--bd); border-radius: var(--r); background: var(--el);
855
+ border: 1px solid var(--fertig-bd); border-radius: var(--fertig-rw); background: var(--fertig-el);
775
856
  }
776
857
  menu > li { padding: .55rem .85rem }
777
- menu > li + li { border-top: 1px solid var(--bd) }
858
+ menu > li + li { border-top: 1px solid var(--fertig-bd) }
778
859
  [popover] menu { border: 0; padding: 0; margin: 0; background: none }
779
860
  [popover] menu > li { padding: 0 }
780
861
  [popover] menu > li + li { border-top: 0 }
@@ -790,13 +871,13 @@ nav menu > li { padding: 0 }
790
871
  nav menu > li + li { border-top: 0 }
791
872
  nav menu :is(a, button) {
792
873
  display: block; inline-size: 100%; text-align: start;
793
- padding: .38rem .6rem; border: 0; border-radius: var(--r);
874
+ padding: .38rem .6rem; border: 0; border-radius: var(--fertig-r);
794
875
  background: none; box-shadow: none; font: inherit;
795
- color: var(--fg); text-decoration: none; opacity: .72;
876
+ color: var(--fertig-fg); text-decoration: none; opacity: .72;
796
877
  }
797
- nav menu :is(a, button):hover { background: var(--face); opacity: 1 }
878
+ nav menu :is(a, button):hover { background: var(--fertig-face); opacity: 1 }
798
879
  nav menu :is(a, button)[aria-current] {
799
- background: var(--face); color: var(--ac); font-weight: 600; opacity: 1;
880
+ background: var(--fertig-face); color: var(--fertig-ac); font-weight: 600; opacity: 1;
800
881
  }
801
882
 
802
883
  /* app layout: a sticky sidebar beside the content */
@@ -814,16 +895,14 @@ nav menu :is(a, button)[aria-current] {
814
895
  }
815
896
  [data-carousel] > * { scroll-snap-align: start; flex: 0 0 min(20rem, 82%) }
816
897
 
817
- /* #core-omit-end */
818
-
819
898
  /* ---- the only classes (all optional) ------------------------ */
820
- .muted { color: var(--mut) }
899
+ .muted { color: var(--fertig-mut) }
821
900
  .center { text-align: center }
822
901
  .wide { max-width: 66rem }
823
902
  /* on the toolbar .wide cannot mean "be 66rem wide" — the bar stays full-bleed
824
903
  and its contents move out to the wide column, so an app screen's wordmark
825
904
  lines up with the app's own content rather than floating mid-screen. */
826
- :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav.wide { max-width: none; --nw: 66rem }
905
+ :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav.wide { max-width: none; --fertig-nw: 66rem }
827
906
  .row { display: flex; flex-wrap: wrap; gap: .7rem; align-items: center }
828
907
  /* Form controls are full-width blocks by default, which is right in a form and
829
908
  wrong in a toolbar. Inside a .row they size to the row instead. */
@@ -841,8 +920,8 @@ nav menu :is(a, button)[aria-current] {
841
920
  .grid + * { margin-top: 1.1rem }
842
921
  .card {
843
922
  container-type: inline-size; /* query it: @container (min-width: …) */
844
- border: 1px solid var(--bd); border-radius: var(--r); padding: 1.1rem;
845
- background: var(--el); box-shadow: var(--up2);
923
+ border: 1px solid var(--fertig-bd); border-radius: var(--fertig-rw); padding: 1.1rem;
924
+ background: var(--fertig-el); box-shadow: var(--fertig-up2);
846
925
  display: flex; flex-direction: column; /* so footers line up across a row */
847
926
  gap: .85rem; /* spacing is the container's job */
848
927
  }
@@ -899,12 +978,13 @@ nav menu :is(a, button)[aria-current] {
899
978
  .max-w-full { max-inline-size: 100% }
900
979
  .max-w-none { max-inline-size: none }
901
980
  /* the measure the sheet already sets prose on, as a class you can reach for */
902
- .max-w-prose { max-inline-size: var(--w) }
981
+ .max-w-prose { max-inline-size: var(--fertig-w) }
903
982
  .hidden { display: none }
904
983
 
905
984
  .badge {
906
- border: 1px solid var(--bd); border-radius: calc(infinity * 1px); background: var(--face);
907
- padding: .1em .6em; font: 700 var(--caps); color: var(--mut);
985
+ border: 1px solid var(--fertig-bd); border-radius: var(--fertig-rp); background: var(--fertig-face);
986
+ padding: .1em .6em; font: 700 var(--fertig-caps); color: var(--fertig-mut);
987
+ text-transform: uppercase; letter-spacing: .07em; /* a label, like h5/h6 and th */
908
988
  }
909
989
 
910
990
  /* card anatomy: an optional header, footer, and full-bleed media */
@@ -914,25 +994,25 @@ nav menu :is(a, button)[aria-current] {
914
994
  .card > :is(header, footer) { margin-inline: -1.1rem; padding-inline: 1.1rem }
915
995
  .card > header {
916
996
  margin-top: -.25rem; padding-bottom: .7rem; font-weight: 600;
917
- border-bottom: 1px solid var(--bd);
997
+ border-bottom: 1px solid var(--fertig-bd);
918
998
  }
919
999
  .card > footer {
920
1000
  margin-top: auto; margin-bottom: -.25rem; padding-top: .7rem;
921
- color: var(--mut); font-size: .85em;
922
- border-top: 1px solid var(--bd);
1001
+ color: var(--fertig-mut); font-size: .85em;
1002
+ border-top: 1px solid var(--fertig-bd);
923
1003
  }
924
1004
  .card > :is(img, video):first-child {
925
1005
  align-self: stretch; width: auto; max-width: none; margin: -1.1rem -1.1rem 0;
926
1006
  aspect-ratio: 16 / 9; object-fit: cover;
927
- border: 0; border-radius: var(--r) var(--r) 0 0; box-shadow: none;
1007
+ border: 0; border-radius: var(--fertig-rw) var(--fertig-rw) 0 0; box-shadow: none;
928
1008
  }
929
1009
  /* A background layer rather than a border or an inset shadow: a border would
930
1010
  shift the card's geometry, and an inset shadow does not follow the corner
931
1011
  radius cleanly at this size — it reads as a detached bar with gaps at the
932
1012
  top corners. A gradient is clipped by the radius, so the tone hugs the curve. */
933
1013
  .card[data-tone] {
934
- background: linear-gradient(var(--ac), var(--ac)) top / 100% 3px no-repeat,
935
- var(--el);
1014
+ background: linear-gradient(var(--fertig-ac), var(--fertig-ac)) top / 100% 3px no-repeat,
1015
+ var(--fertig-el);
936
1016
  }
937
1017
 
938
1018
  /* a card that is itself a link or button reacts like one */
@@ -942,8 +1022,8 @@ nav menu :is(a, button)[aria-current] {
942
1022
  text-decoration: none; font: inherit;
943
1023
  }
944
1024
  :is(a, button).card:hover:not(:disabled) {
945
- border-color: color-mix(in srgb, var(--ac) 45%, var(--bd));
946
- box-shadow: var(--up2), 0 12px 26px -14px color-mix(in srgb, var(--sh) 40%, transparent);
1025
+ border-color: color-mix(in srgb, var(--fertig-ac) 45%, var(--fertig-bd));
1026
+ box-shadow: var(--fertig-up2), 0 16px 30px -16px color-mix(in srgb, var(--fertig-sh) 28%, transparent);
947
1027
  translate: 0 -2px;
948
1028
  }
949
1029
  :is(a, button).card:active:not(:disabled) { translate: 0 0 }
@@ -953,26 +1033,26 @@ nav menu :is(a, button)[aria-current] {
953
1033
  win over your own sheet; hidden=until-found must stay findable */
954
1034
  [hidden]:not([hidden=until-found]) { display: none }
955
1035
  @media (prefers-reduced-motion: no-preference) and (update: fast) { html { scroll-behavior: smooth } }
956
- :target { scroll-margin-top: 4rem } /* clears the toolbar */
957
- :is(h1,h2,h3,h4):target { background: color-mix(in srgb, var(--ac) 12%, transparent) }
1036
+ :target { scroll-margin-block-start: 4rem } /* clears the toolbar */
1037
+ :is(h1,h2,h3,h4):target { background: color-mix(in srgb, var(--fertig-ac) 12%, transparent) }
958
1038
  a[target=_blank]:not(:has(> img, > svg))::after { content: " ↗"; font-size: .85em; opacity: .6 }
959
1039
  a:has(> img), a:has(> code) { text-decoration: none }
960
1040
  sup, sub { line-height: 0; font-size: .75em } /* stop them stretching lines */
961
1041
  q { quotes: "“" "”" "‘" "’" }
962
1042
  dfn { font-style: normal; font-weight: 700 }
963
- ins { text-decoration: underline; text-decoration-style: wavy; text-decoration-color: var(--ac) }
964
- del { color: var(--mut) }
965
- address { font-style: normal; color: var(--mut) }
1043
+ ins { text-decoration: underline; text-decoration-style: wavy; text-decoration-color: var(--fertig-ac) }
1044
+ del { color: var(--fertig-mut) }
1045
+ address { font-style: normal; color: var(--fertig-mut) }
966
1046
  hgroup > * { margin: 0 }
967
- hgroup > p { color: var(--mut) }
1047
+ hgroup > p { color: var(--fertig-mut) }
968
1048
  output { font-weight: 700 }
969
1049
  meter { width: 100%; height: .5rem }
970
- optgroup { font-weight: 700; color: var(--mut) }
1050
+ optgroup { font-weight: 700; color: var(--fertig-mut) }
971
1051
  ::file-selector-button { margin-inline-end: .8em }
972
- ::file-selector-button:hover { background: var(--face) }
1052
+ ::file-selector-button:hover { background: var(--fertig-face) }
973
1053
  input:user-invalid, textarea:user-invalid { border-color: light-dark(#c0392b, #ff6b6b) }
974
1054
  input:user-invalid + small { color: light-dark(#c0392b, #ff6b6b) }
975
- summary:hover { color: var(--ac) }
1055
+ summary:hover { color: var(--fertig-ac) }
976
1056
  /* thin scrollbars, macOS weight */
977
1057
  /* scrollbar-width is Safari 18.2, scrollbar-color Safari 26.2 — both younger
978
1058
  than the floor, and both left ungated on purpose: there is no fallback to
@@ -985,12 +1065,12 @@ summary:hover { color: var(--ac) }
985
1065
  :is(pre, table, textarea, dialog, [popover], menu, fieldset,
986
1066
  [role=group], [data-carousel], [data-layout=sidebar] > *) {
987
1067
  scrollbar-width: thin;
988
- scrollbar-color: color-mix(in srgb, var(--fg) 25%, transparent) transparent;
1068
+ scrollbar-color: color-mix(in srgb, var(--fertig-fg) 25%, transparent) transparent;
989
1069
  }
990
1070
 
991
1071
  @page { margin: 2cm }
992
1072
  @media print {
993
- :root { --bg: #fff; --el: #fff; --fg: #000; --bd: #999 }
1073
+ :root { --fertig-bg: #fff; --fertig-el: #fff; --fertig-fg: #000; --fertig-bd: #999 }
994
1074
  :is(body, body > :where(#root, #app, #__next, [data-fertig])) > nav { display: none }
995
1075
  /* the footer stays: the legal line, the contact and the citations live there,
996
1076
  and a printout without them is missing the part people keep */
@@ -1023,7 +1103,7 @@ summary:hover { color: var(--ac) }
1023
1103
  /* a wider gamut can hold a cleaner accent than sRGB can */
1024
1104
  @media (color-gamut: p3) {
1025
1105
  @supports (color: oklch(60% .2 250)) {
1026
- :root { --ac: light-dark(oklch(52% .21 258), oklch(76% .15 258)) }
1106
+ :root { --fertig-ac: light-dark(oklch(52% .21 258), oklch(76% .15 258)) }
1027
1107
  }
1028
1108
  }
1029
1109
 
@@ -1032,14 +1112,14 @@ summary:hover { color: var(--ac) }
1032
1112
 
1033
1113
  /* translucency is decorative; drop it when it is unwanted */
1034
1114
  @media (prefers-reduced-transparency: reduce) {
1035
- body > nav { background: var(--face); backdrop-filter: none }
1115
+ body > nav { background: var(--fertig-face); backdrop-filter: none }
1036
1116
  dialog::backdrop { backdrop-filter: none }
1037
1117
  }
1038
1118
 
1039
1119
  @media (prefers-contrast: more) {
1040
1120
  :root {
1041
- --bd: light-dark(#00000059, #ffffff6b);
1042
- --mut: light-dark(#45454a, #c6c6ce);
1121
+ --fertig-bd: light-dark(#00000059, #ffffff6b);
1122
+ --fertig-mut: light-dark(#45454a, #c6c6ce);
1043
1123
  }
1044
1124
  }
1045
1125
 
@@ -1047,11 +1127,11 @@ summary:hover { color: var(--ac) }
1047
1127
  a, button, input, select, textarea, summary, tr,
1048
1128
  [type=submit], [type=button], [type=reset], .card, .badge,
1049
1129
  [role=tab], [role=group] > *, [popover] :is(a, button) {
1050
- transition: box-shadow var(--dur-1) var(--ease),
1051
- background-color var(--dur-1) var(--ease),
1052
- border-color var(--dur-1) var(--ease),
1053
- color var(--dur-1) var(--ease),
1054
- translate .08s var(--ease-out);
1130
+ transition: box-shadow var(--fertig-dur-1) var(--fertig-ease),
1131
+ background-color var(--fertig-dur-1) var(--fertig-ease),
1132
+ border-color var(--fertig-dur-1) var(--fertig-ease),
1133
+ color var(--fertig-dur-1) var(--fertig-ease),
1134
+ translate .08s var(--fertig-ease-out);
1055
1135
  }
1056
1136
  /* the ring must never be animated — it has to be there the instant focus
1057
1137
  lands, not fade in after it */
@@ -1065,25 +1145,25 @@ summary:hover { color: var(--ac) }
1065
1145
  computed-value time, so backgrounds go transparent and colour is inherited,
1066
1146
  and the page can land unreadable rather than plain. These are the same
1067
1147
  colours flattened to sRGB. Last in the layer, so it wins on order over the
1068
- token block at the top. Nothing else needs a twin: an invalid --ac on a
1148
+ token block at the top. Nothing else needs a twin: an invalid --fertig-ac on a
1069
1149
  [data-tone] or [data-accent] element just inherits the one from :root. */
1070
1150
  @supports not (color: light-dark(#000, #fff)) {
1071
1151
  :root {
1072
- --bg: #ece9e5; --el: #fefdfc; --face: #f8f5f2; --fg: #1d1a17;
1073
- --mut: #5e5a55; --bd: #1d1a1721; --tb: #f8f5f2d9;
1074
- --ac: #494fcc; --on-ac: #fff;
1152
+ --fertig-bg: #e6eaef; --fertig-el: #fafcfe; --fertig-face: #f3f6fa; --fertig-fg: #151b24;
1153
+ --fertig-mut: #525962; --fertig-bd: #151b2421; --fertig-tb: #f3f6fad9;
1154
+ --fertig-ac: #2850de; --fertig-on-ac: #fff;
1075
1155
  }
1076
1156
  @media (prefers-color-scheme: dark) {
1077
1157
  :root:not([data-theme=light]) {
1078
- --bg: #0f0d0a; --el: #1a1815; --face: #24211e; --fg: #f0eeec;
1079
- --mut: #aba7a2; --bd: #f0eeec21; --tb: #24211ed9;
1080
- --ac: #a3b2fe; --on-ac: #06121f;
1158
+ --fertig-bg: #090c12; --fertig-el: #141920; --fertig-face: #1c222a; --fertig-fg: #eaeff7;
1159
+ --fertig-mut: #9da5b1; --fertig-bd: #eaeff721; --fertig-tb: #1c222ad9;
1160
+ --fertig-ac: #90b5ff; --fertig-on-ac: #07071c;
1081
1161
  }
1082
1162
  }
1083
1163
  [data-theme=dark] {
1084
- --bg: #0f0d0a; --el: #1a1815; --face: #24211e; --fg: #f0eeec;
1085
- --mut: #aba7a2; --bd: #f0eeec21; --tb: #24211ed9;
1086
- --ac: #a3b2fe; --on-ac: #06121f;
1164
+ --fertig-bg: #090c12; --fertig-el: #141920; --fertig-face: #1c222a; --fertig-fg: #eaeff7;
1165
+ --fertig-mut: #9da5b1; --fertig-bd: #eaeff721; --fertig-tb: #1c222ad9;
1166
+ --fertig-ac: #90b5ff; --fertig-on-ac: #07071c;
1087
1167
  }
1088
1168
  }
1089
1169