@thi.ng/meta-css 0.1.3 → 0.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-12-19T12:24:50Z
3
+ - **Last updated**: 2023-12-21T22:48:14Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,13 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ ## [0.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/meta-css@0.2.0) (2023-12-21)
13
+
14
+ #### 🚀 Features
15
+
16
+ - update specs/format, simplify generate, update tests ([394ba09](https://github.com/thi-ng/umbrella/commit/394ba09))
17
+ - update specs format, add support for user data ([7e3ec01](https://github.com/thi-ng/umbrella/commit/7e3ec01))
18
+
12
19
  ### [0.1.1](https://github.com/thi-ng/umbrella/tree/@thi.ng/meta-css@0.1.1) (2023-12-18)
13
20
 
14
21
  #### ♻️ Refactoring
package/README.md CHANGED
@@ -11,13 +11,25 @@ This project is part of the
11
11
  [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo and anti-framework.
12
12
 
13
13
  - [About](#about)
14
- - [Generate](#generate)
15
- - [Convert](#convert)
14
+ - [Generate CSS frameworks](#generate-css-frameworks)
15
+ - [Convert meta stylesheets to CSS](#convert-meta-stylesheets-to-css)
16
16
  - [Including custom CSS files](#including-custom-css-files)
17
- - [Force inclusion of unreferenced classes](#force-inclusion-of-unreferenced-classes)
17
+ - [Force inclusion of unreferenced classes](#force-inclusion-of-unreferenced-classes)
18
18
  - [Export](#export)
19
- - [Media queries](#media-queries)
19
+ - [Media query variations](#media-query-variations)
20
20
  - [Framework generation rules](#framework-generation-rules)
21
+ - [Overall file structure](#overall-file-structure)
22
+ - [Example spec](#example-spec)
23
+ - [Spec structure](#spec-structure)
24
+ - [Variations](#variations)
25
+ - [Parametric IDs](#parametric-ids)
26
+ - [Values](#values)
27
+ - [Properties](#properties)
28
+ - [Key value generation](#key-value-generation)
29
+ - [Media query definitions](#media-query-definitions)
30
+ - [Bundled CSS base framework](#bundled-css-base-framework)
31
+ - [Classes by category](#classes-by-category)
32
+ - [Media queries](#media-queries)
21
33
  - [Status](#status)
22
34
  - [Related packages](#related-packages)
23
35
  - [Installation](#installation)
@@ -37,23 +49,33 @@ This project is part of the
37
49
 
38
50
  Data-driven CSS framework codegen, transpiler & bundler.
39
51
 
52
+ This toolchain and the overall workflow proposed by it is heavily building atop
53
+ the concept of _CSS utility classes_ and how they're utilized (as you might know
54
+ from using Tachyons, Turret or the newer Tailwind projects). How and where those
55
+ CSS classes are applied is however a defining point of difference to other
56
+ existing approaches. This readme aims to provide a thorough overview and some
57
+ concrete usage examples...
58
+
40
59
  This package provides a CLI multi-tool to:
41
60
 
42
- ### Generate
61
+ ### Generate CSS frameworks
43
62
 
44
- The `generate` command is used to generate custom CSS frameworks from a number
45
- of JSON rule specs. This process creates all desired, combinatorial versions of
63
+ The `generate` command is used to generate custom frameworks with (likely)
64
+ hundreds of CSS utility classes from a number of extremely compact, parametric
65
+ JSON rule specs. This process generates all desired, combinatorial versions of
46
66
  various rules/declarations and exports them to another JSON file used as
47
67
  intermediatary for the other commands provided by this toolchain. The
48
- syntax/format of the generator rules is explained further on. These rules can be
49
- split up into multiple files, can incude arbitrary media query criteria (all
50
- later combinable), shared lookup tables for colors, margins, sizes, timings etc.
51
-
52
- The package provides generator specs for a basic, configurable,
53
- [tachyons.io](https://tachyons.io)-derived CSS framework in the
54
- [/specs](https://github.com/thi-ng/umbrella/blob/develop/packages/meta-css/specs/)
55
- directory. These specs are used for some example projects in this repo, but are
56
- intended to be used as basic starting point for other custom frameworks.
68
+ [syntax/format of the generator rules](#framework-generation-rules) is explained
69
+ further on. These rule specs can be split up into multiple files for better
70
+ handling, can define [arbitrary media query criteria]() (all later combinable),
71
+ shared lookup tables for colors, margins, sizes, timings etc.
72
+
73
+ The package provides generator specs for a basic, fully customizable,
74
+ [tachyons.io](https://tachyons.io)-derived [CSS
75
+ framework](#bundled-css-base-framework). These specs and resulting framework are
76
+ used for some example projects in this repo, but are mainly intended as basic
77
+ starting points for creating other custom frameworks (in the hope they'll be
78
+ shared back similarly)...
57
79
 
58
80
  ```text
59
81
  metacss generate --help
@@ -71,16 +93,22 @@ Main:
71
93
  --prec INT Number of fractional digits (default: 3)
72
94
  ```
73
95
 
74
- ### Convert
96
+ ### Convert meta stylesheets to CSS
75
97
 
76
98
  The `convert` command is used to compile & bundle actual CSS from user-provided
77
99
  MetaCSS stylesheets (`*.meta` files) and the JSON framework specs created by the
78
100
  `generate` command. The meta-stylesheets support any CSS selectors, are nestable
79
101
  and compose full CSS declarations from lists of the utility classes in the
80
- generated framework. Each item (aka utility class name) can be prefixed with an
81
- arbitrary number of media query IDs (also custom defined in the framework).
102
+ generated framework.
103
+
104
+ Each item (aka utility class name) can be prefixed with an arbitrary number of
105
+ media query IDs (also custom defined in the framework): e.g. `dark:bg-black`
106
+ might refer to a CSS class to set a black ground, with the `dark:` prefix
107
+ referring to a defined media query which only applies this class when dark mode
108
+ is enabled...
109
+
82
110
  Selectors, declarations and media query criteria will be deduplicated and merged
83
- from multiple input files. The resulting CSS will only contain referenced rules
111
+ from multiple input files. The resulting CSS will only contain referenced rules
84
112
  and can be generated in minified or pretty printed formats (it's also possible
85
113
  to force include CSS classes which are otherwise unreferenced, using the
86
114
  `--force` CLI arg). Additionally, multiple .meta files can be watched for
@@ -112,40 +140,49 @@ Main:
112
140
 
113
141
  One or more existing CSS files can be included & prepended to the output via the
114
142
  `--include`/`-I` arg (which can be given multiple times). These files are used
115
- as-is and will **not** be transformed or reformatted in any way.
143
+ verbatim and will **not** be transformed or reformatted in any way.
116
144
 
117
- ### Force inclusion of unreferenced classes
145
+ #### Force inclusion of unreferenced classes
118
146
 
119
147
  Only the CSS classes (and their optionally associated media queries) referenced
120
148
  in a `.meta` stylesheet will appear in the export CSS bundle. This ensures that
121
- the resulting CSS will only contain what's actually used. However, this also
122
- means any CSS classes (and optionally, their media query qualifiers) which are
123
- otherwise referenced (e.g. from JS/TS source code or HTML docs) **will not** be
124
- included by default and they will need to be listed manually for forced inclusion.
149
+ the resulting CSS will only contain what's actually used (same effect as
150
+ tree-shaking, only vastly more efficient). However, this also means any CSS
151
+ classes (and optionally, their media query qualifiers) which are otherwise
152
+ referenced (e.g. from JS/TS source code or HTML docs) **will not** be included
153
+ by default and they will need to be listed manually for forced inclusion.
125
154
 
126
155
  This can be achieved via the `--force`/`-f` arg (also can be given multiple
127
156
  times). This option also supports basic `*`-wildcard patterns, e.g. `bg-*` to
128
157
  include all classes with prefix `bg-`. Furthermore, for larger projects it's
129
158
  useful to store these names/patterns in a separate file. For that purpose, use
130
159
  the `@` prefix (e.g. `-f @includes.txt`) to indicate reading from file (only
131
- reading from a single file is supported at current)...
160
+ reading from a single file is supported at current)... See the [meta-css-basics
161
+ example
162
+ project](https://github.com/thi-ng/umbrella/blob/develop/examples/meta-css-basics)
163
+ for concrete usage...
132
164
 
133
165
  ### Export
134
166
 
135
- The `export` command is intended for those who're only interested in the CSS
136
- framework generation aspect of this toolchain. This command merely takes an
167
+ The `export` command is intended for those who're mainly interested in the CSS
168
+ framework generation aspects of this toolchain. This command merely takes an
137
169
  existing generated framework JSON file and serializes it to a single CSS file,
138
170
  e.g. to be then used with other CSS tooling (e.g. `postcss`).
139
171
 
140
- #### Media queries
172
+ #### Media query variations
141
173
 
142
174
  Users can choose to generate variations of all defined utility classes for any
143
- of the framework-defined media query IDs. This will create suffixed versions of
144
- all classes (with their appropriate media query wrappers) and cause a
145
- potentially massive output (depending on the overall number/complexity of the
175
+ of the framework-defined media query IDs. This will create additional suffixed
176
+ versions of all classes (with their appropriate media query wrappers) and cause
177
+ a potentially massive output (depending on the overall number/complexity of the
146
178
  generated classes). Again, the idea is that the resulting CSS file will be
147
179
  post-processed with 3rd party CSS tooling...
148
180
 
181
+ For example, if the framework contains a CSS class `w-50` (e.g. to set the width
182
+ to 50%) and media queries for different screen sizes (e.g. named `ns`, `l`),
183
+ then the export with said media queries will also generate classes `w-50-ns`
184
+ and `w-50-l` (incl. their corresponding `@media` wrappers).
185
+
149
186
  As with the `convert` command, additional CSS files can also be included
150
187
  (prepended) in the output file.
151
188
 
@@ -174,8 +211,441 @@ Note: In all cases, final CSS generation itself is handled by
174
211
 
175
212
  ## Framework generation rules
176
213
 
177
- TODO for now please see bundled example specs in
178
- [/specs](https://github.com/thi-ng/umbrella/blob/develop/packages/meta-css/specs/)...
214
+ This section gives an overview of the JSON format used to generate CSS
215
+ frameworks of dozens (usually hundreds) of utility classes, including many
216
+ possible variations (per spec).
217
+
218
+ ### Overall file structure
219
+
220
+ Generation specs use a simple JSON structure as shown below. The specs can be
221
+ split over multiple files within a directory and will all be merged by the
222
+ `generate` command of the toolchain.
223
+
224
+ ```json5
225
+ {
226
+ // optional meta data (later used for comment injection in generated CSS)
227
+ "info": {
228
+ "name": "Framework name",
229
+ "version": "0.0.0",
230
+ },
231
+ // optional media queries and their criteria
232
+ "media": {
233
+ "large": { "min-width": "60rem" },
234
+ "dark": { "prefers-color-scheme": "dark" }
235
+ },
236
+ // optional shared values/LUTs (arrays or objects)
237
+ "tables": {
238
+ "margins": [0, 0.25, 0.5, 1, 2, 4]
239
+ },
240
+ // array of actual generation specs
241
+ "specs": [
242
+ //...
243
+ ]
244
+ }
245
+ ```
246
+
247
+ ### Example spec
248
+
249
+ The following generator document uses a single small generative rule spec to
250
+ create altogether 21 utility classes for various possible margins (where 21 = 3
251
+ margin sizes provided × 7 variations).
252
+
253
+ For each additional value added to the `margins` table, 7 more CSS classes will be
254
+ generated. The `name` (class) and `props` (CSS property name) are parametric and
255
+ will be explained in more detail further below.
256
+
257
+ ```json tangle:export/readme-margins.json
258
+ {
259
+ "tables": {
260
+ "margins": [0, 0.5, 1]
261
+ },
262
+ "specs": [
263
+ {
264
+ "name": "m<vid><k>",
265
+ "props": "margin<var>",
266
+ "values": "margins",
267
+ "unit": "rem",
268
+ "var": ["a", "t", "r", "b", "l", "h", "v"]
269
+ }
270
+ ]
271
+ }
272
+ ```
273
+
274
+ Assuming the above spec has been saved to a JSON file in the `myspecs`
275
+ directory...
276
+
277
+ ```bash
278
+ # the `generate` cmd is directory based and will read all
279
+ # JSON files in the provided dir (recursively)...
280
+
281
+ # if no `--out` file is given, the result will go to stdout
282
+ metacss generate --pretty myspecs
283
+ ```
284
+
285
+ ...this command (with the above spec) will generate the following output (here
286
+ we're only interested in the entries under `classes`):
287
+
288
+ ```json
289
+ {
290
+ "info": {
291
+ "name": "TODO",
292
+ "version": "0.0.0"
293
+ },
294
+ "media": {},
295
+ "classes": {
296
+ "ma0": { "margin": "0rem" },
297
+ "ma1": { "margin": ".5rem" },
298
+ "ma2": { "margin": "1rem" },
299
+ "mh0": { "margin-left": "0rem", "margin-right": "0rem" },
300
+ "mh1": { "margin-left": ".5rem", "margin-right": ".5rem" },
301
+ "mh2": { "margin-left": "1rem", "margin-right": "1rem" },
302
+ "mv0": { "margin-top": "0rem", "margin-bottom": "0rem" },
303
+ "mv1": { "margin-top": ".5rem", "margin-bottom": ".5rem" },
304
+ "mv2": { "margin-top": "1rem", "margin-bottom": "1rem" },
305
+ "mt0": { "margin-top": "0rem" },
306
+ "mt1": { "margin-top": ".5rem" },
307
+ "mt2": { "margin-top": "1rem" },
308
+ "mr0": { "margin-right": "0rem" },
309
+ "mr1": { "margin-right": ".5rem" },
310
+ "mr2": { "margin-right": "1rem" },
311
+ "mb0": { "margin-bottom": "0rem" },
312
+ "mb1": { "margin-bottom": ".5rem" },
313
+ "mb2": { "margin-bottom": "1rem" },
314
+ "ml0": { "margin-left": "0rem" },
315
+ "ml1": { "margin-left": ".5rem" },
316
+ "ml2": { "margin-left": "1rem" }
317
+ }
318
+ }
319
+ ```
320
+
321
+ When later used in stylesheets, we can then refer to each of these classes by
322
+ their generated names, e.g. `ma0` to disable all margins or `mh2` to set both
323
+ left & right margins to `1rem` (in this case)...
324
+
325
+ ### Spec structure
326
+
327
+ An individual generator spec JSON object can contain the following keys:
328
+
329
+ | **ID** | **Type** | **Description** |
330
+ |----------|-------------------------|--------------------------------------------------------------|
331
+ | `name` | string | Parametric name for the generated CSS class(es) |
332
+ | `props` | string or object | CSS property name(s), possibly parametric |
333
+ | `values` | string, array or object | Values to be assigned to CSS properties, possibly parametric |
334
+ | `unit` | string, optional | CSS unit to use for values |
335
+ | `key` | string, optional | Method for deriving keys from current value |
336
+ | `var` | string[], optional | Array of variation IDs (see section below) |
337
+ | `user` | any, optional | Custom user data, comments, metadata etc. |
338
+
339
+ The number of generated CSS classes per spec is number of items in `values`
340
+ multiplied with the number of variations in `var` (if any).
341
+
342
+ Any `user` data will be stored (as is) with each generated CSS class, but
343
+ currently has no other direct use in the toolchain and is meant for additional
344
+ user-defined tooling.
345
+
346
+ #### Variations
347
+
348
+ Variations can be requested by providing an array of valid variation IDs. If
349
+ used, `<vid>` or `<var>` parameters must be used in the `name` or else naming
350
+ conflicts will occur.
351
+
352
+ | **ID** | **Expanded values** |
353
+ |------------|-----------------------|
354
+ | `""` | `[""]` |
355
+ | `"a"` | `[""]` |
356
+ | `"b"` | `["-bottom"]` |
357
+ | `"bottom"` | `["bottom"]` |
358
+ | `"h"` | `["-left", "-right"]` |
359
+ | `"l"` | `["-left"]` |
360
+ | `"left"` | `["left"]` |
361
+ | `"r"` | `["-right"]` |
362
+ | `"right"` | `["right"]` |
363
+ | `"t"` | `["-top"]` |
364
+ | `"top"` | `["top"]` |
365
+ | `"v"` | `["-top", "-bottom"]` |
366
+ | `"x"` | `["-x"]` |
367
+ | `"y"` | `["-y"]` |
368
+
369
+ #### Parametric IDs
370
+
371
+ The following parameters can (and should) be used in a spec's `name` and `props`
372
+ to generate multiple pattern-based values (more examples below).
373
+
374
+ - `<vid>` is a value from the ID column of the above variations table. If no
375
+ variations are requested, its value will be an empty string.
376
+ - `<var>` is one of the expanded values for the current variation (2nd column of
377
+ variations table). If no variations are defined, this too will be an empty
378
+ string.
379
+ - `<v>` is the currently processed value of a spec's `values`.
380
+ - `<k>` is the key (possibly derived) for the currently processed value of a
381
+ spec's `values` and will depend on the type of `values` (see below)
382
+
383
+ #### Values
384
+
385
+ The `values` are used to populate the `props` (CSS properties). If `values` is a
386
+ string it will be used as table-name to look up in the current spec file's
387
+ `tables`, an object storing values which should be shared among specs (only in
388
+ the same file).
389
+
390
+ Other allowed types of `values`: string array, numeric array or object of
391
+ key-value pairs (where values are strings or numbers too). The following
392
+ examples will all produce the same outcome:
393
+
394
+ Using a named `tables` entry:
395
+
396
+ ```json
397
+ {
398
+ "tables": {
399
+ "test": ["red", "green", "blue"]
400
+ },
401
+ "specs": [
402
+ {
403
+ "name": "test<v>",
404
+ "props": "color",
405
+ "values": "test"
406
+ }
407
+ ]
408
+ }
409
+ ```
410
+
411
+ Using an array directly (here only showing the spec itself for brevity):
412
+
413
+ ```json
414
+ {
415
+ "name": "test<v>",
416
+ "props": "color",
417
+ "values": ["red", "green", "blue"]
418
+ }
419
+ ```
420
+
421
+ Using an object (ignoring the keys, only using the values here):
422
+
423
+ ```json
424
+ {
425
+ "name": "test<v>",
426
+ "props": "color",
427
+ "values": { "r": "red", "g": "green", "b": "blue"}
428
+ }
429
+ ```
430
+
431
+ All 3 versions will result in these utility classes:
432
+
433
+ ```json
434
+ {
435
+ "test-red": { "color": "red" },
436
+ "test-green": { "color": "green" },
437
+ "test-blue": { "color": "blue" }
438
+ }
439
+ ```
440
+
441
+ #### Properties
442
+
443
+ The `props` field is used to define one or more CSS property names and
444
+ optionally their intended values (both can be parametric). If `props` is a
445
+ string, the values assigned to the property will be those given in `values`
446
+ (optionally with assigned `unit`, if provided)
447
+
448
+ ```json
449
+ {
450
+ "name": "bg<k>",
451
+ "props": {
452
+ "background-image": "url(<v>)",
453
+ "background-size": "cover",
454
+ },
455
+ "values": ["abc.jpg", "def.jpg", "xyz.jpg"]
456
+ }
457
+ ```
458
+
459
+ Will result in these definitions:
460
+
461
+ ```json
462
+ {
463
+ "bg0": { "background-image": "url(abc.jpg)", "background-size": "cover" },
464
+ "bg1": { "background-image": "url(def.jpg)", "background-size": "cover" },
465
+ "bg2": { "background-image": "url(xyz.jpg)", "background-size": "cover" }
466
+ }
467
+ ```
468
+
469
+ #### Key value generation
470
+
471
+ The `key` field is only used when `values` is resolving to an array. In this
472
+ case this field determines how a "key" value (aka the `<k>` param for string
473
+ interpolation, see below) will be derived for each value in `values`:
474
+
475
+ | **`key`** | **`values`** | **Description** | **Examples** |
476
+ |-----------|-----------------|-------------------------|--------------|
477
+ | `v` | `[10, 20, ...]` | Actual array item value | 10, 20, ... |
478
+ | `i` | `[10, 20, ...]` | Array item index | 0, 1,... |
479
+ | `i1` | `[10, 20, ...]` | Array item index + 1 | 1, 2,... |
480
+
481
+ If `values` resolves to an object, the `<k>` param will always be the key of the
482
+ currently processed value.
483
+
484
+ ```json
485
+ {
486
+ "name": "test-<k>",
487
+ "props": "test-prop",
488
+ "values": { "abc": 23, "xyz": 42 }
489
+ }
490
+ ```
491
+
492
+ The above spec will generate the following (some parts omitted):
493
+
494
+ ```json
495
+ {
496
+ "test-abc": { "test-prop": 23 },
497
+ "test-xyz": { "test-prop": 42 },
498
+ }
499
+ ```
500
+
501
+ ### Media query definitions
502
+
503
+ Media queries can be defined via the top-level `media` object in a spec file.
504
+ Each query has an ID and an object of one or more query criteria.
505
+
506
+ The key-value pairs of the conditional object are interpreted as follows and
507
+ ALWAYS combined using `and`:
508
+
509
+ | Key/Value pair | Result |
510
+ |----------------------------------|--------------------------------|
511
+ | `"min-width": "10rem"` | `(min-width: 10rem)` |
512
+ | `"prefers-color-scheme": "dark"` | `(prefers-color-scheme: dark)` |
513
+ | `print: true` | `print` |
514
+ | `print: false` | `not print` |
515
+ | `print: "only"` | `only print` |
516
+
517
+ See [media queries in the bundled base
518
+ specs](https://github.com/thi-ng/umbrella/blob/982fff7bfcc48f108b6ad88f854ef00be4078510/packages/meta-css/specs/_info.json#L6-L24)
519
+
520
+ ## Bundled CSS base framework
521
+
522
+ The package includes a large number of useful specs in [/specs](https://github.com/thi-ng/umbrella/blob/develop/packages/meta-css/specs/). These are provided as starting point to define your custom framework(s)...
523
+
524
+ Currently available CSS classes in MetaCSS base v0.0.1:
525
+
526
+ ### Classes by category
527
+
528
+ #### Animations / transitions <!-- notoc -->
529
+
530
+ `bg-anim1` / `bg-anim2` / `bg-anim3`
531
+
532
+ #### Border radius <!-- notoc -->
533
+
534
+ `br0` / `br1` / `br2` / `br3` / `br4` / `brb0` / `brb1` / `brb2` / `brb3` / `brb4` / `brl0` / `brl1` / `brl2` / `brl3` / `brl4` / `brr0` / `brr1` / `brr2` / `brr3` / `brr4` / `brt0` / `brt1` / `brt2` / `brt3` / `brt4`
535
+
536
+ #### Border width <!-- notoc -->
537
+
538
+ `bw0` / `bw1` / `bw2` / `bw3` / `bw4` / `bw5` / `bwb0` / `bwb1` / `bwb2` / `bwb3` / `bwb4` / `bwb5` / `bwl0` / `bwl1` / `bwl2` / `bwl3` / `bwl4` / `bwl5` / `bwr0` / `bwr1` / `bwr2` / `bwr3` / `bwr4` / `bwr5` / `bwt0` / `bwt1` / `bwt2` / `bwt3` / `bwt4` / `bwt5`
539
+
540
+ #### Colors <!-- notoc -->
541
+
542
+ `b--black` / `b--blue` / `b--dark-blue` / `b--dark-gray` / `b--dark-green` / `b--dark-pink` / `b--dark-red` / `b--gold` / `b--gray` / `b--green` / `b--hot-pink` / `b--light-blue` / `b--light-gray` / `b--light-green` / `b--light-pink` / `b--light-purple` / `b--light-red` / `b--light-silver` / `b--light-yellow` / `b--lightest-blue` / `b--mid-gray` / `b--moon-gray` / `b--navy` / `b--near-black` / `b--near-white` / `b--orange` / `b--pink` / `b--purple` / `b--red` / `b--silver` / `b--transparent` / `b--vcol1` / `b--vcol10` / `b--vcol11` / `b--vcol12` / `b--vcol13` / `b--vcol14` / `b--vcol15` / `b--vcol16` / `b--vcol2` / `b--vcol3` / `b--vcol4` / `b--vcol5` / `b--vcol6` / `b--vcol7` / `b--vcol8` / `b--vcol9` / `b--washed-blue` / `b--washed-green` / `b--washed-red` / `b--washed-yellow` / `b--white` / `b--yellow` / `bg-black` / `bg-blue` / `bg-dark-blue` / `bg-dark-gray` / `bg-dark-green` / `bg-dark-pink` / `bg-dark-red` / `bg-gold` / `bg-gray` / `bg-green` / `bg-hot-pink` / `bg-light-blue` / `bg-light-gray` / `bg-light-green` / `bg-light-pink` / `bg-light-purple` / `bg-light-red` / `bg-light-silver` / `bg-light-yellow` / `bg-lightest-blue` / `bg-mid-gray` / `bg-moon-gray` / `bg-navy` / `bg-near-black` / `bg-near-white` / `bg-orange` / `bg-pink` / `bg-purple` / `bg-red` / `bg-silver` / `bg-transparent` / `bg-vcol1` / `bg-vcol10` / `bg-vcol11` / `bg-vcol12` / `bg-vcol13` / `bg-vcol14` / `bg-vcol15` / `bg-vcol16` / `bg-vcol2` / `bg-vcol3` / `bg-vcol4` / `bg-vcol5` / `bg-vcol6` / `bg-vcol7` / `bg-vcol8` / `bg-vcol9` / `bg-washed-blue` / `bg-washed-green` / `bg-washed-red` / `bg-washed-yellow` / `bg-white` / `bg-yellow` / `black` / `blue` / `dark-blue` / `dark-gray` / `dark-green` / `dark-pink` / `dark-red` / `gold` / `gray` / `green` / `hot-pink` / `light-blue` / `light-gray` / `light-green` / `light-pink` / `light-purple` / `light-red` / `light-silver` / `light-yellow` / `lightest-blue` / `mid-gray` / `moon-gray` / `navy` / `near-black` / `near-white` / `o-0` / `o-10` / `o-100` / `o-20` / `o-30` / `o-40` / `o-50` / `o-60` / `o-70` / `o-80` / `o-90` / `orange` / `pink` / `purple` / `red` / `silver` / `transparent` / `vcol1` / `vcol10` / `vcol11` / `vcol12` / `vcol13` / `vcol14` / `vcol15` / `vcol16` / `vcol2` / `vcol3` / `vcol4` / `vcol5` / `vcol6` / `vcol7` / `vcol8` / `vcol9` / `washed-blue` / `washed-green` / `washed-red` / `washed-yellow` / `white` / `yellow`
543
+
544
+ #### Cursors <!-- notoc -->
545
+
546
+ `cursor-alias` / `cursor-auto` / `cursor-cell` / `cursor-col` / `cursor-context` / `cursor-copy` / `cursor-cross` / `cursor-default` / `cursor-e` / `cursor-ew` / `cursor-forbidden` / `cursor-grab` / `cursor-grabbing` / `cursor-help` / `cursor-in` / `cursor-move` / `cursor-n` / `cursor-ne` / `cursor-news` / `cursor-no-drop` / `cursor-none` / `cursor-ns` / `cursor-nw` / `cursor-nwse` / `cursor-out` / `cursor-pointer` / `cursor-progress` / `cursor-row` / `cursor-s` / `cursor-scroll` / `cursor-se` / `cursor-sw` / `cursor-text` / `cursor-vtext` / `cursor-w` / `cursor-wait`
547
+
548
+ #### Width <!-- notoc -->
549
+
550
+ `w-10` / `w-100` / `w-20` / `w-25` / `w-30` / `w-33` / `w-34` / `w-40` / `w-50` / `w-60` / `w-66` / `w-70` / `w-75` / `w-80` / `w-90` / `w1` / `w2` / `w3` / `w4` / `w5`
551
+
552
+ #### Max. width <!-- notoc -->
553
+
554
+ `mw-10` / `mw-100` / `mw-20` / `mw-25` / `mw-30` / `mw-33` / `mw-34` / `mw-40` / `mw-50` / `mw-60` / `mw-66` / `mw-70` / `mw-75` / `mw-80` / `mw-90` / `mw1` / `mw2` / `mw3` / `mw4` / `mw5`
555
+
556
+ #### Height <!-- notoc -->
557
+
558
+ `h-10` / `h-100` / `h-20` / `h-25` / `h-30` / `h-33` / `h-34` / `h-40` / `h-50` / `h-60` / `h-66` / `h-70` / `h-75` / `h-80` / `h-90` / `h1` / `h2` / `h3` / `h4` / `h5`
559
+
560
+ #### Display mode <!-- notoc -->
561
+
562
+ `db` / `df` / `dg` / `di` / `dib` / `dif` / `dig` / `dn` / `dt` / `dtc` / `dtr`
563
+
564
+ #### Grid layout <!-- notoc -->
565
+
566
+ `gap0` / `gap1` / `gap2` / `gap3` / `gap4` / `gap5` / `gc1` / `gc10` / `gc2` / `gc3` / `gc4` / `gc5` / `gc6` / `gc7` / `gc8` / `gc9` / `gr1` / `gr10` / `gr2` / `gr3` / `gr4` / `gr5` / `gr6` / `gr7` / `gr8` / `gr9`
567
+
568
+ #### Lists <!-- notoc -->
569
+
570
+ `list`
571
+
572
+ #### Padding <!-- notoc -->
573
+
574
+ `pa0` / `pa1` / `pa2` / `pa3` / `pa4` / `pb0` / `pb1` / `pb2` / `pb3` / `pb4` / `ph0` / `ph1` / `ph2` / `ph3` / `ph4` / `pl0` / `pl1` / `pl2` / `pl3` / `pl4` / `pr0` / `pr1` / `pr2` / `pr3` / `pr4` / `pt0` / `pt1` / `pt2` / `pt3` / `pt4` / `pv0` / `pv1` / `pv2` / `pv3` / `pv4`
575
+
576
+ #### Margin <!-- notoc -->
577
+
578
+ `center` / `ma0` / `ma1` / `ma2` / `ma3` / `ma4` / `mb0` / `mb1` / `mb2` / `mb3` / `mb4` / `mh0` / `mh1` / `mh2` / `mh3` / `mh4` / `ml0` / `ml1` / `ml2` / `ml3` / `ml4` / `mr0` / `mr1` / `mr2` / `mr3` / `mr4` / `mt0` / `mt1` / `mt2` / `mt3` / `mt4` / `mv0` / `mv1` / `mv2` / `mv3` / `mv4`
579
+
580
+ #### Overflow <!-- notoc -->
581
+
582
+ `overflow-auto` / `overflow-hidden` / `overflow-scroll` / `overflow-visible` / `overflow-x-auto` / `overflow-x-hidden` / `overflow-x-scroll` / `overflow-x-visible` / `overflow-y-auto` / `overflow-y-hidden` / `overflow-y-scroll` / `overflow-y-visible`
583
+
584
+ #### Positions <!-- notoc -->
585
+
586
+ `absolute` / `bottom--1` / `bottom--2` / `bottom-0` / `bottom-1` / `bottom-2` / `fixed` / `left--1` / `left--2` / `left-0` / `left-1` / `left-2` / `relative` / `right--1` / `right--2` / `right-0` / `right-1` / `right-2` / `sticky` / `top--1` / `top--2` / `top-0` / `top-1` / `top-2`
587
+
588
+ #### Z-indices <!-- notoc -->
589
+
590
+ `z-0` / `z-1` / `z-2` / `z-3` / `z-4` / `z-5` / `z-999` / `z-9999`
591
+
592
+ #### Shadow <!-- notoc -->
593
+
594
+ `i-shadow-1` / `i-shadow-2` / `i-shadow-3` / `i-shadow-4` / `shadow-1` / `shadow-2` / `shadow-3` / `shadow-4`
595
+
596
+ #### Font families <!-- notoc -->
597
+
598
+ `monospace` / `sans-serif` / `serif` / `system`
599
+
600
+ #### Font sizes <!-- notoc -->
601
+
602
+ `f-subtitle` / `f-title` / `f1` / `f2` / `f3` / `f4` / `f5` / `f6` / `f7`
603
+
604
+ #### Font weights <!-- notoc -->
605
+
606
+ `b` / `fw100` / `fw200` / `fw300` / `fw400` / `fw500` / `fw600` / `fw700` / `fw800` / `fw900` / `normal`
607
+
608
+ #### Font variants <!-- notoc -->
609
+
610
+ `small-caps`
611
+
612
+ #### Text decorations <!-- notoc -->
613
+
614
+ `no-underline` / `strike` / `underline`
615
+
616
+ #### Text transforms <!-- notoc -->
617
+
618
+ `ttc` / `ttfsk` / `ttfw` / `tti` / `ttl` / `ttn` / `ttu`
619
+
620
+ #### Text align <!-- notoc -->
621
+
622
+ `tc` / `tj` / `tl` / `tr`
623
+
624
+ #### Vertical align <!-- notoc -->
625
+
626
+ `v-btm` / `v-mid` / `v-top`
627
+
628
+ #### Line heights <!-- notoc -->
629
+
630
+ `lh-copy` / `lh-double` / `lh-solid` / `lh-title`
631
+
632
+ #### Whitespace <!-- notoc -->
633
+
634
+ `ws-0` / `ws-1` / `ws-2`
635
+
636
+ #### Letter spacing <!-- notoc -->
637
+
638
+ `ls--1` / `ls--2` / `ls-0` / `ls-1` / `ls-2` / `ls-3`
639
+
640
+ ### Media queries
641
+
642
+ - **ns**: `{"min-width":"30rem"}`
643
+ - **m**: `{"min-width":"30rem","max-width":"60rem"}`
644
+ - **l**: `{"min-width":"60rem"}`
645
+ - **dark**: `{"prefers-color-scheme":"dark"}`
646
+ - **light**: `{"prefers-color-scheme":"light"}`
647
+ - **anim**: `{"prefers-reduced-motion":false}`
648
+ - **noanim**: `{"prefers-reduced-motion":true}`
179
649
 
180
650
  ## Status
181
651
 
@@ -297,7 +767,7 @@ body { ma0 dark:bg-black dark:white bg-white black }
297
767
  #app { ma3 }
298
768
 
299
769
  .bt-group-v > a {
300
- db w100 l:w50 ph3 pv2 bwb1
770
+ db w-100 l:w-50 ph3 pv2 bwb1
301
771
  dark:bg-purple dark:white dark:b--black
302
772
  light:bg-light-blue light:black light:b--white
303
773
  {