@codenhub/styles 0.4.0 → 0.6.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/README.md +7 -7
- package/dist/aesthetics/chunky-tile.css +1 -1
- package/dist/aesthetics/cyber.css +1 -1
- package/dist/aesthetics/glass.css +1 -1
- package/dist/aesthetics/index.css +1 -1
- package/dist/aesthetics/neobrutalism.css +1 -1
- package/dist/aesthetics/pixel.css +1 -1
- package/dist/aesthetics/sketch.css +1 -0
- package/dist/components.css +1 -1
- package/dist/index.css +1 -1
- package/dist/native.css +1 -1
- package/dist/palette.css +1 -1
- package/dist/theme.css +1 -1
- package/dist/tw/aesthetics/chunky-tile.css +144 -128
- package/dist/tw/aesthetics/cyber.css +138 -96
- package/dist/tw/aesthetics/glass.css +332 -66
- package/dist/tw/aesthetics/index.css +3 -1
- package/dist/tw/aesthetics/neobrutalism.css +113 -54
- package/dist/tw/aesthetics/pixel.css +137 -87
- package/dist/tw/aesthetics/sketch.css +333 -0
- package/dist/tw/box.css +139 -52
- package/dist/tw/components/button.css +67 -28
- package/dist/tw/components/feedback.css +85 -67
- package/dist/tw/components/form.css +300 -230
- package/dist/tw/components/index.css +17 -9
- package/dist/tw/components/loader.css +38 -30
- package/dist/tw/components/surface.css +89 -129
- package/dist/tw/components/tooltip.css +91 -47
- package/dist/tw/corner.css +26 -0
- package/dist/tw/elevation.css +19 -28
- package/dist/tw/index.css +15 -19
- package/dist/tw/intent.css +47 -32
- package/dist/tw/native.css +58 -42
- package/dist/tw/palette.css +455 -446
- package/dist/tw/presentation.css +20 -29
- package/dist/tw/reset.css +21 -28
- package/dist/tw/surface.css +61 -0
- package/dist/tw/theme.css +156 -153
- package/dist/tw/utilities/content.css +283 -205
- package/dist/tw/utilities/layout.css +17 -27
- package/docs/accessibility.md +63 -46
- package/docs/changelog/0.5.0.md +38 -0
- package/docs/changelog/0.6.0.md +52 -0
- package/docs/changelog/index.md +2 -0
- package/docs/concepts.md +6 -6
- package/docs/index.md +12 -3
- package/docs/integrating/nextjs.md +1 -1
- package/docs/integrating/tailwind.md +14 -6
- package/docs/setup.md +28 -8
- package/docs/usage/aesthetics.md +88 -18
- package/docs/usage/buttons.md +14 -14
- package/docs/usage/composing.md +12 -12
- package/docs/usage/content-and-layout.md +25 -24
- package/docs/usage/customizing.md +92 -55
- package/docs/usage/feedback.md +5 -3
- package/docs/usage/forms.md +61 -45
- package/docs/usage/theming.md +41 -42
- package/docs/usage/tooltips.md +37 -17
- package/llms-full.txt +590 -304
- package/llms.txt +6 -0
- package/package.json +15 -5
package/docs/setup.md
CHANGED
|
@@ -30,7 +30,7 @@ Import the compiled stylesheet for the complete token, reset, utility, and compo
|
|
|
30
30
|
|
|
31
31
|
The full stylesheet applies global reset and focus-visible rules, but does not apply the optional classless native-element mappings, and does not include aesthetics. Import focused entrypoints when global rules are not appropriate; see [Import paths](#import-paths) below.
|
|
32
32
|
|
|
33
|
-
Aesthetics are opt-in. Import the combined aesthetics stylesheet, or one aesthetic on its own,
|
|
33
|
+
Aesthetics are opt-in. Import the combined aesthetics stylesheet, or one aesthetic on its own. Order does not matter, because every entrypoint declares the [cascade layers](#cascade-layers) before it uses one:
|
|
34
34
|
|
|
35
35
|
```css
|
|
36
36
|
@import "@codenhub/styles";
|
|
@@ -85,12 +85,12 @@ Compiled entrypoints are ready-to-import CSS and require only tooling that can r
|
|
|
85
85
|
| Import path | Composition and effects |
|
|
86
86
|
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
87
87
|
| `@codenhub/styles` | Compiled complete surface: Tailwind base/theme output, tokens, typography, utilities, components, and reset. Applies global reset, root theme, and focus rules. |
|
|
88
|
-
| `@codenhub/styles/theme` | Compiled Tailwind theme variables, Codenhub tokens, and the presentation classes. Sets root theme properties and system/explicit theme selectors; no reset or component classes.
|
|
88
|
+
| `@codenhub/styles/theme` | Compiled Tailwind theme variables, Codenhub tokens, and the intent, presentation, elevation, and corner-pattern classes. Sets root theme properties and system/explicit theme selectors; no reset or component classes. |
|
|
89
89
|
| `@codenhub/styles/palette` | Generated, self-contained `--palette-*` custom properties: every intent/presentation cell's fill, text, and edge color, plus the flat `border`/`surface`/`text` neutral tokens, pre-composed to a flat value. For a consumer that cannot take this package as a build-time dependency (an optional peer, for example) but wants to look consistent with it. Not a replacement for the components themselves when Tailwind is available -- see [Customizing → Generated palette](./usage/customizing.md#generated-palette). |
|
|
90
|
-
| `@codenhub/styles/components` | Compiled theme tokens, typography utilities, and every component class.
|
|
90
|
+
| `@codenhub/styles/components` | Compiled theme tokens, typography utilities, and every component class. Each component carries its own reduced-motion rule and the `<dialog>` fix travels with `.card`; no reset, layout/content utilities, or native mappings. |
|
|
91
91
|
| `@codenhub/styles/native` | Compiled complete surface plus classless mappings for headings, text, content elements, form controls, and buttons. Applies the reset and broad element selectors. |
|
|
92
|
-
| `@codenhub/styles/aesthetics` | Compiled `.neobrutalism`, `.glass`, `.pixel`, `.chunky-tile`, and `.
|
|
93
|
-
| `@codenhub/styles/aesthetics/*` | One compiled aesthetic and its solo class: `/neobrutalism`, `/glass`, `/pixel`, `/chunky-tile`, or `/
|
|
92
|
+
| `@codenhub/styles/aesthetics` | Compiled `.neobrutalism`, `.glass`, `.pixel`, `.chunky-tile`, `.cyber`, and `.sketch` classes, and each one's `-solo` class. Adds no tokens or components of its own; import in either order. |
|
|
93
|
+
| `@codenhub/styles/aesthetics/*` | One compiled aesthetic and its solo class: `/neobrutalism`, `/glass`, `/pixel`, `/chunky-tile`, `/cyber`, or `/sketch`. Same rules and ordering as the combined file. |
|
|
94
94
|
| `@codenhub/styles/tw` | Source equivalent of the complete stylesheet. Imports Tailwind itself, theme, typography, utilities, components, and reset; applies the same global rules. |
|
|
95
95
|
| `@codenhub/styles/tw/theme` | Source theme, tokens, and presentation classes. Imports Tailwind's theme layer; emits root/system/explicit theme selectors and defines the package's custom `dark:` variant. |
|
|
96
96
|
| `@codenhub/styles/tw/components` | Published Tailwind source for theme, typography, buttons, feedback, forms, loaders, surfaces, and tooltips, including static reduced-motion loader masks. No reset, layout/content utilities, or native mappings. |
|
|
@@ -104,13 +104,33 @@ Compiled entrypoints are ready-to-import CSS and require only tooling that can r
|
|
|
104
104
|
| `@codenhub/styles/tw/native` | Source complete surface plus reset and classless native-element mappings; broadest global effects. |
|
|
105
105
|
| `@codenhub/styles/tw/typography` | Source theme plus typography utilities; sets theme selectors but no reset or classless mappings. |
|
|
106
106
|
| `@codenhub/styles/tw/utilities` | Source theme and typography composition plus layout and content utilities; safelists the package utility names. |
|
|
107
|
-
| `@codenhub/styles/tw/aesthetics` | Source aesthetics, combined. `/tw/aesthetics/neobrutalism`, `/glass`, `/pixel`, `/chunky-tile`, and `/
|
|
107
|
+
| `@codenhub/styles/tw/aesthetics` | Source aesthetics, combined. `/tw/aesthetics/neobrutalism`, `/glass`, `/pixel`, `/chunky-tile`, `/cyber`, and `/sketch` publish one apiece. Plain CSS with no theme or reset side effects. |
|
|
108
108
|
|
|
109
109
|
Avoid importing overlapping entrypoints in the same build unless duplicate generated CSS is acceptable; pick the narrowest entrypoint that covers what a page needs.
|
|
110
110
|
|
|
111
|
+
## Cascade layers
|
|
112
|
+
|
|
113
|
+
Every entrypoint maps its CSS into Tailwind's four cascade layers (with documented unlayered exceptions), in Tailwind's order, and declares that order before using a layer, so the result does not depend on which file loads first:
|
|
114
|
+
|
|
115
|
+
| Layer | Holds |
|
|
116
|
+
| ------------ | ---------------------------------------------------------------------------------------------- |
|
|
117
|
+
| `theme` | Tailwind's theme, the foundation tokens, the theme selectors, and `/palette`. |
|
|
118
|
+
| `base` | The reset and the classless element styles. |
|
|
119
|
+
| `components` | The intent, presentation, elevation, and aesthetic classes. |
|
|
120
|
+
| `utilities` | Every component (`.btn`, `.card`, `.ipt`, ...), next to your own Tailwind utilities. |
|
|
121
|
+
| _unlayered_ | The `forced-colors` and reduced-motion overrides, the `<dialog>` fix, and the `-solo` classes. |
|
|
122
|
+
|
|
123
|
+
What that means in practice:
|
|
124
|
+
|
|
125
|
+
- **Your utility or unlayered CSS beats an intent, presentation, elevation, or aesthetic class** on the same element for normal declarations. `[--ui-fill:50%]` on a `.solid` button, `font-serif` on a `.pixel` region, or `.my-card { --ui-radius: 0 }` in your own stylesheet all apply.
|
|
126
|
+
- **A component and your utility share the `utilities` layer.** Which wins is decided by specificity and then source order, as between any two utilities. Your unlayered normal CSS always beats a component.
|
|
127
|
+
- **State beats your intent.** An `aria-invalid` field stays destructive even with an intent utility on it.
|
|
128
|
+
- **The `-solo` classes are unlayered on purpose**, so they beat a foreign component's own styles; tune them through their knobs rather than with utilities.
|
|
129
|
+
|
|
111
130
|
## Requirements
|
|
112
131
|
|
|
113
132
|
- Consumer tooling must resolve package CSS imports.
|
|
114
|
-
-
|
|
115
|
-
-
|
|
133
|
+
- Every shipped stylesheet can be pasted into an HTML `<style>` element, for critical-CSS inlining or a server-rendered head: none contains the `</style` sequence that would end the element early.
|
|
134
|
+
- Chrome 123, Safari 17.5, or Firefox 128 and newer. Color tokens are declared with `light-dark()` and selected by `color-scheme` (Firefox 120), `.input-group` propagates a nested control's invalid and disabled state with `:has()` (Firefox 121), and the elevation multiplier is registered non-inheriting with `@property` (Firefox 128; without it an elevation class would reach the unclassed elements inside it).
|
|
135
|
+
- Tailwind CSS 4.3.2 or newer, below 5, is required only for `/tw` source entrypoints.
|
|
116
136
|
- The package has no JavaScript runtime. Apps must provide semantic HTML, ARIA, keyboard behavior, focus management, validation, and announcements; see [Accessibility](./accessibility.md).
|
package/docs/usage/aesthetics.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Aesthetics
|
|
3
|
-
description: The
|
|
3
|
+
description: The six shipped aesthetics in depth, their solo classes, and their documented exceptions.
|
|
4
4
|
order: 4
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ An aesthetic decides what a component is _made of_: its radius, border thickness
|
|
|
13
13
|
@import "@codenhub/styles/aesthetics";
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Load order does not matter: the aesthetic classes sit in the `components` cascade layer, and every entrypoint declares the layer order before it uses one, so an aesthetic imported before the base stylesheet wins exactly as one imported after it. See [Setup → Cascade layers](../setup.md#cascade-layers).
|
|
17
17
|
|
|
18
18
|
Like presentation, an aesthetic class cascades to any subtree:
|
|
19
19
|
|
|
@@ -31,6 +31,7 @@ Like presentation, an aesthetic class cascades to any subtree:
|
|
|
31
31
|
| `.pixel` | Corners cut by one grid unit, a chunky outline drawn as an inset ring, and the consumer-supplied `--font-pixel` over monospace. |
|
|
32
32
|
| `.chunky-tile` | Rounded slabs seated on a darker shade of themselves, with a press that moves the element down into its own bar. |
|
|
33
33
|
| `.cyber` | Bevelled corners, a thin bright edge, and a glow in the component's own colour. |
|
|
34
|
+
| `.sketch` | Varying elliptical corners, a solid ink line with dashed accents, a small offset shadow, and an optional handwriting face. |
|
|
34
35
|
|
|
35
36
|
Aesthetics compose with every supported fill and edge pair. `.ghost.edgeless` intentionally removes the visible material traits from components whose aesthetic is expressed only through their fill, edge, or elevation.
|
|
36
37
|
|
|
@@ -38,11 +39,13 @@ An explicit presentation on the element still wins over the aesthetic's defaults
|
|
|
38
39
|
|
|
39
40
|
An aesthetic directly on a component likewise wins over an inherited aesthetic. This includes tooltip bubbles: `.tooltip-bubble.glass` gets the complete glass bubble under a pixel ancestor, and `.tooltip-bubble.pixel` gets the complete stepped bubble under a glass ancestor.
|
|
40
41
|
|
|
42
|
+
Your own CSS wins over an aesthetic. The aesthetic classes sit in the `components` cascade layer, so a Tailwind utility on the same element -- `font-mono` on a `.pixel` region, `[--ui-radius:0]` on a `.cyber` one -- or a rule in your own unlayered stylesheet beats them. See [Setup → Cascade layers](../setup.md#cascade-layers).
|
|
43
|
+
|
|
41
44
|
Each aesthetic that scales from one number publishes it as a knob — see [Customizing → Aesthetic tokens](./customizing.md#aesthetic-tokens) for how knobs resolve and where they can be set. This page covers what each aesthetic looks like and where it makes documented exceptions.
|
|
42
45
|
|
|
43
46
|
## Neobrutalism
|
|
44
47
|
|
|
45
|
-
The shadow is cast in the component's own intent, so a success button throws a green shadow and a destructive card a red one. With no intent, both the outline and the shadow use the ink, which follows the theme rather than the palette.
|
|
48
|
+
The shadow is cast in the component's own intent, so a success button throws a green shadow and a destructive card a red one. With no intent, both the outline and the shadow use the ink, which follows the theme rather than the palette. Fields and toggles are the exception: they draw the theme's control border, as they do with no aesthetic, because the ink is the primary colour in both themes and a resting checkbox drawn in it reads as loudly as a primary one. The same holds under pixel, cyber, and sketch.
|
|
46
49
|
|
|
47
50
|
`--neo-offset` is the knob: the shadow offset and the distance the press travels are the same number, so scaling the look scales both at once.
|
|
48
51
|
|
|
@@ -57,6 +60,7 @@ The shadow is cast in the component's own intent, so a success button throws a g
|
|
|
57
60
|
- Content chips are left alone. A `.kbd`, `.code`, or `.pre` is content rather than structure, and an ink edge on one reads as a defect: a key cap keeps the quiet border color and a code chip keeps no border at all.
|
|
58
61
|
- Only `.btn` and an opted-in `.card` respond to hover and press. A card opts in with `.interactive`, or with one of its halves — `.hoverable` for the hover response alone, `.pressable` for the press alone; a plain card, an alert, or a panel is a container and stays put.
|
|
59
62
|
- An alert rests on the slab under this aesthetic and nowhere else. Here the slab is a second ink line rather than depth, and an alert is the only container the package rests flat, so without it a neobrutalist alert is the one box on the page that reads as unfinished. It is a resting default, so `.flat` still takes it off and `.floating` still doubles it.
|
|
63
|
+
- The tooltip trigger takes the zero corner like everything else and draws square; `.radio` keeps its circle.
|
|
60
64
|
|
|
61
65
|
## Glass
|
|
62
66
|
|
|
@@ -72,8 +76,36 @@ The shadow is cast in the component's own intent, so a success button throws a g
|
|
|
72
76
|
|
|
73
77
|
**Exceptions:**
|
|
74
78
|
|
|
75
|
-
-
|
|
79
|
+
- Every surface in a glass region is glass, a neutral `.card.soft`, `.panel`, and `.alert` included.
|
|
80
|
+
- The glass is the ground, not the fill. A presentation keeps its whole fill, so a `.solid` button, a checked toggle, and a `.solid` card or table are opaque; the default, `.soft`, and `.ghost` panes are the frosted ones.
|
|
81
|
+
- The blur applies to `.card`, `.panel`, `.alert`, the tooltip bubble, and a default or `.soft` `.data-table` only. Controls stay solid and sit on the glass: a blur under every control of a dense cluster costs a composited layer apiece and reads as noise. Controls still take the aesthetic's radius, border, and shadow.
|
|
76
82
|
- Under `prefers-reduced-transparency: reduce`, glass surfaces drop the blur and become opaque.
|
|
83
|
+
- Buttons and an opted-in `.card` press with the plain `scale(0.97)`; reduced motion turns it off.
|
|
84
|
+
- Text controls and toggles draw their line in the page's ink at 55% rather than the white hairline, which would erase an unchecked checkbox on a light page. It is `--ui-control-ink`; set it on the region to choose another.
|
|
85
|
+
- A table's frame and rules draw the page's ink at 20%, because the hairline vanishes on the table's plate. It is `--ui-rule-ink`.
|
|
86
|
+
- A table with a `<caption>` blurs behind the caption as well as its rows in Chromium and Safari, whose table box includes the caption, and under `.glass-liquid` the rim and sheen frame the caption too. Firefox keeps the caption off the pane. Label the table from a heading outside it with `aria-labelledby` where that matters.
|
|
87
|
+
|
|
88
|
+
### Liquid glass
|
|
89
|
+
|
|
90
|
+
`.glass-liquid` is a modifier of glass, after Apple's Liquid Glass: continuous corners, a bright rim where light catches the pane, a lighter blur, a clearer ground, and a lens that bends what is behind a surface at its edges. Put it beside `.glass` on the region, or on one surface inside a glass region.
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<section class="glass glass-liquid">
|
|
94
|
+
<div class="card">A pane that bends the page behind it</div>
|
|
95
|
+
</section>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The lens is drawn by an SVG filter in `backdrop-filter`, which Chromium renders and Firefox and Safari do not yet. Elsewhere the pane keeps everything but the lens: the rim, the blur, the ground, and the corners, round rather than continuous where `corner-shape` is not drawn. Nothing needs to be in your markup: the filter ships inside the stylesheet.
|
|
99
|
+
|
|
100
|
+
**Exceptions:**
|
|
101
|
+
|
|
102
|
+
- It reaches `.card`, `.panel`, `.alert`, the tooltip bubble, and a default or `.soft` `.data-table`. Controls stay solid, as they do under glass.
|
|
103
|
+
- It draws its blur and lens on each surface's `::before` and `::after`, so a surface inside a liquid region cannot carry a `::before` or `::after` of your own, and each surface becomes a positioned stacking context -- a surface you position yourself keeps your placement.
|
|
104
|
+
- The lens is 8px of erosion blurred over 10px at every size, and its strength is fixed. A filter cannot read a custom property, so neither is a knob. The corners are, through `--glass-radius` and `--glass-radius-surface`, with larger defaults: a continuous corner reads smaller than a round one of the same radius.
|
|
105
|
+
- A region of another aesthetic nested inside a liquid region, or of plain `.glass`, keeps its own material and takes no layers.
|
|
106
|
+
- Without `.glass` in scope it changes the corners and nothing else.
|
|
107
|
+
- Under `prefers-reduced-transparency: reduce` the blur and the lens go and the surface is opaque, as under glass; in forced colours the layers draw nothing.
|
|
108
|
+
- Text sits over a clearer pane than under glass. Over busy content, check that your text still reads -- the ground is 30% of the page colour, where glass's is 45%.
|
|
77
109
|
|
|
78
110
|
## Pixel
|
|
79
111
|
|
|
@@ -87,9 +119,9 @@ The shadow is cast in the component's own intent, so a success button throws a g
|
|
|
87
119
|
|
|
88
120
|
**Exceptions:**
|
|
89
121
|
|
|
90
|
-
- Corners are one unit or nothing. Chips square instead of stepping — badges, key caps, code, checkboxes, and switches all read `--ui-clip-tight`, which this aesthetic sets to none, because one unit off each corner of a 24px badge is a bite rather than a corner. Tables, progress bars, and skeletons square too, each for its own reason: a table
|
|
122
|
+
- Corners are one unit or nothing. Chips square instead of stepping — badges, key caps, code, checkboxes, and switches all read `--ui-clip-tight`, which this aesthetic sets to none, because one unit off each corner of a 24px badge is a bite rather than a corner. Tables, progress bars, and skeletons square too, each for its own reason: a table takes no clip, because in Chromium and WebKit its box includes its caption and the clip would cut the caption rather than the rows, and progress and skeleton never read a clip at all — a squaring aesthetic reaches them through `border-radius` alone. `.pre` is the one exception that steps: it carries no clip override, so it inherits the same polygon a button or a card gets, and with no border by default the cut shows with no ring around it.
|
|
91
123
|
- The outline is an inset ring, because a clip removes a real border — and the focus ring, for the same reason, is a second inset layer rather than an outline. Both are the element's own edge rather than a shadow, so the border answers `.edged` and `.edgeless` the way a border does: a `.edgeless` badge and a `.solid` button draw none, a `.edged` card draws one, and a field keeps one whatever a container asks for.
|
|
92
|
-
- The tooltip trigger and `.radio` are hardcoded past the clip rather than reached by it. `.tooltip-icon`
|
|
124
|
+
- The tooltip trigger and `.radio` are hardcoded past the clip rather than reached by it. `.tooltip-icon` and `.radio` force `clip-path: none`: the circle is the only thing telling a radio from a checkbox at a glance, and a stepped polygon would bite a 20px trigger rather than shape it. The tooltip trigger still takes pixel's zero corner and draws square; the radio keeps its circle.
|
|
93
125
|
- `--font-pixel` is yours to supply. The package ships no font binary, so the aesthetic has no network side effect and falls back to the monospace stack.
|
|
94
126
|
- Numeral legibility depends on the face you pick. At UI sizes -- pagination, counters, small badges -- some pixel/bitmap faces render lookalike digits such as `2`/`8` or `3`/`9` closely enough to misread at a glance; this is a property of the font, not something the aesthetic's CSS can correct. Prefer a face with clearly distinct digit shapes wherever small numeric text matters.
|
|
95
127
|
|
|
@@ -116,10 +148,11 @@ The bar is a darker shade of the element's own colour rather than a shadow under
|
|
|
116
148
|
```
|
|
117
149
|
|
|
118
150
|
- `--font-rounded` is yours to supply. A heavy rounded grotesque is most of this look and the package ships no font binary, so with nothing supplied the page's own stack is used.
|
|
119
|
-
-
|
|
151
|
+
- Labels are drawn heavier and slightly tracked, through `--ui-label-weight` and `--ui-label-tracking`, so your own `font-*` or `tracking-*` utility still wins. It reaches `.btn` and `.badge`, and a bare `<button>` only where `/native` styles it. Casing is left alone: how a label is worded is the application's decision, so if you want uppercase buttons, write that rule in your own stylesheet.
|
|
120
152
|
- `.card.interactive` presses like a `.btn`, so a chunky answer tile drops onto its bar on click; `.card.pressable` gets the same press on its own. A plain `.card` stays put.
|
|
121
153
|
- The shipped `.primary` is a near-black-or-near-white monochrome depending on theme, and the bar mixes toward a fixed black regardless of theme. In light theme this leaves a primary button's bar almost invisible against its own near-black plate (measured `1.04:1`, 10 units of sRGB distance); in dark theme the near-white plate against the same black-anchored bar reads fine (`2.48:1`, 154 units). Give `.primary` a hue of its own if it is the call to action and needs the depth cue in both themes.
|
|
122
154
|
- Depth in this aesthetic is the bar, never a blurred drop shadow. Anything the registry rests flat sits flush on the page.
|
|
155
|
+
- Controls draw a heavier grey than the tiles around them -- `neutral-600` in light, `neutral-400` in dark -- through `--ui-control-ink`, so a field reads as a field inside a tile.
|
|
123
156
|
|
|
124
157
|
## Cyber
|
|
125
158
|
|
|
@@ -127,7 +160,7 @@ Bevelled corners, a 1px edge, and a glow in the component's own colour: a succes
|
|
|
127
160
|
|
|
128
161
|
Controls and surfaces take the cut on opposite diagonals, so a button and the card around it read as the same material and as different things: buttons and fields cut top-left and bottom-right, cards, panels, and alerts top-right and bottom-left. Anything fully round cuts to points -- a radio, a switch knob, and the tooltip icon become diamonds, a pill button or a badge a pointed hexagon -- and chips square, so the checkbox reads as a plain square beside the diamond radio.
|
|
129
162
|
|
|
130
|
-
`--cyber-cut` is the
|
|
163
|
+
`--cyber-cut` is the cut at the default size, `0.625rem`. Controls scale it with their size step, so a `.p-xs` icon button takes half of it and keeps its corners, and it stays a true 45 degrees. `--cyber-shape` and `--cyber-shape-surface` replace the default placement with any `border-radius` value, used as written. `--cyber-glow` is the glow's blur, `8px`. `--cyber-ink` is the neutral line and glow colour, which follows the theme by default -- near-black on light, near-white on dark -- and is where a neon neutral goes if you want one.
|
|
131
164
|
|
|
132
165
|
```html
|
|
133
166
|
<section class="cyber" style="--cyber-ink: rgb(0 229 255); --cyber-cut: 0.75rem">
|
|
@@ -135,7 +168,7 @@ Controls and surfaces take the cut on opposite diagonals, so a button and the ca
|
|
|
135
168
|
</section>
|
|
136
169
|
```
|
|
137
170
|
|
|
138
|
-
Other shapes are a value away. Set them on the `.cyber` element or any ancestor
|
|
171
|
+
Other shapes are a value away. Set them on the `.cyber` element or any ancestor. `--ui-radius` set on an element reaches that element and every component inside it that does not set its own. A shape you set is used as written and does not scale, so for a scaled one on a single control use `.cut-diagonal-reverse` instead.
|
|
139
172
|
|
|
140
173
|
| Shape | Value |
|
|
141
174
|
| ---------------------- | --------------------- |
|
|
@@ -156,23 +189,60 @@ A parallelogram slants its sides into the content, so give a surface that takes
|
|
|
156
189
|
**Exceptions:**
|
|
157
190
|
|
|
158
191
|
- The bevel is Chromium-only today. Firefox and Safari do not draw `corner-shape` yet, and there the aesthetic squares its cut corners instead of rounding them, and what is fully round stays round, so the look degrades to square, lined, and glowing. It picks up the bevel with no change once an engine ships it.
|
|
159
|
-
- The glow is depth, so it
|
|
192
|
+
- The glow is a halo, not depth, so every component takes it -- fields, badges, and alerts included -- and `.flat` does not take it off. `.raised` and `.floating` add no shadow under this aesthetic.
|
|
160
193
|
- In the light theme the glow of a neutral or `.primary` component is its near-black ink, which reads as a soft shadow rather than as light. The look is at its strongest on a dark page, or with a hued `--cyber-ink`.
|
|
161
194
|
- A plain `.btn.icon` is a square control, so it takes the control diagonal; a `.btn.icon.pill` is round, so it becomes a diamond.
|
|
162
195
|
- `--font-cyber` is yours to supply. The package ships no font binary, so the aesthetic falls back to the monospace stack.
|
|
163
196
|
- Casing is left alone, for the reason [Chunky tile](#chunky-tile) gives.
|
|
164
197
|
|
|
198
|
+
## Sketch
|
|
199
|
+
|
|
200
|
+
Hand-drawn outlines: controls take long, uneven elliptical corners, and cards, panels, alerts, and tables take sharper ones that stay clear of their padding. Siblings rotate through four outlines by position, and a field's control takes its field's position, so a row of buttons or a stacked form does not repeat one shape. The rotation is stable for a given DOM order, not random on each render. Every outline is a complete `border-radius`, used as written rather than scaled by the size step or placed by `.cut-diagonal`.
|
|
201
|
+
|
|
202
|
+
The 1px ink line is solid; checkboxes, dividers, and table rules are dashed. `--ui-line-style: dashed` dashes any other component, and `--ui-rule-style: solid` puts a divider or table back to solid. The 2px hard shadow is a small neutral depth cue.
|
|
203
|
+
|
|
204
|
+
`--sketch-radius`, `--sketch-radius-surface`, and `--sketch-radius-pill` replace the control, surface, and pill-button outlines. Set one and every position takes that one outline. To shape a single component instead, set `--ui-radius` (`--ui-radius-surface` on a surface) on it.
|
|
205
|
+
|
|
206
|
+
```html
|
|
207
|
+
<section class="sketch" style='--font-sketch: "Comic Sans MS", cursive'>
|
|
208
|
+
<button class="btn primary">Send note</button>
|
|
209
|
+
<button class="btn ghost edged" style="--ui-line-style: dashed">Draft note</button>
|
|
210
|
+
</section>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The dashed button is `ghost edged` because a filled button has no separate line to dash.
|
|
214
|
+
|
|
215
|
+
`.sketch-rounded` trades the long corners for short, rounded ones, bounded so a wide element keeps straight top and bottom edges. Put it beside `.sketch` on the region, or on one component inside it. `--sketch-radius-rounded` and `--sketch-radius-surface-rounded` are its knobs.
|
|
216
|
+
|
|
217
|
+
```html
|
|
218
|
+
<section class="sketch sketch-rounded">
|
|
219
|
+
<div class="card">
|
|
220
|
+
<button class="btn primary">Rounded action</button>
|
|
221
|
+
</div>
|
|
222
|
+
</section>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Exceptions:**
|
|
226
|
+
|
|
227
|
+
- Sketch names components to rotate their outlines, so its outlines reach only this package's components; a region of another aesthetic nested inside a sketch region keeps that aesthetic's corners.
|
|
228
|
+
- Chips -- checkboxes, key caps, code, badges, switches, and progress bars -- rotate through small uneven outlines through `--ui-radius-tight`. Set that token on a chip to choose its shape.
|
|
229
|
+
- A `.btn.pill` takes a rounded pill bounded to its own height, so a wide one does not become an oval. Badges, progress bars, and switches take their chip outline. Radios and the tooltip icon stay circles, slightly uneven, so a radio is never mistaken for a checkbox. An explicit `--ui-radius-pill` on an element still wins.
|
|
230
|
+
- `--font-sketch` is yours to supply. The package ships no handwriting font and falls back to the platform `cursive` family.
|
|
231
|
+
- Buttons press with the plain `scale(0.97)`; reduced motion turns it off.
|
|
232
|
+
- Forced-colours mode draws the dashed accents solid, like every other material line.
|
|
233
|
+
|
|
165
234
|
## Solo classes
|
|
166
235
|
|
|
167
236
|
An aesthetic class sets material tokens and nothing paints until a component reads them, so `.glass` on an element this package does not style -- a toast from another library, a dialog, a plain `<div>` on a page without the base stylesheet -- changes nothing. Each aesthetic also ships a solo class that paints its look directly onto the one element carrying it:
|
|
168
237
|
|
|
169
|
-
| Aesthetic | Solo class | Paints
|
|
170
|
-
| --------------- | -------------------- |
|
|
171
|
-
| `.glass` | `.glass-solo` | Translucent ground, hairline edge, blur, the tucked two-layer shadow, the surface corner. |
|
|
172
|
-
| `.neobrutalism` | `.neobrutalism-solo` | 2px ink edge, square corners, the hard offset slab.
|
|
173
|
-
| `.pixel` | `.pixel-solo` | The stepped silhouette, the inset ring in place of a border, the pixel font.
|
|
174
|
-
| `.chunky-tile` | `.chunky-tile-solo` | The tile corner, 2px edge, the bar under it, the rounded font.
|
|
175
|
-
| `.cyber` | `.cyber-solo` | The surface diagonal (the control one on an action), 1px edge, the glow, the font.
|
|
238
|
+
| Aesthetic | Solo class | Paints |
|
|
239
|
+
| --------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
240
|
+
| `.glass` | `.glass-solo` | Translucent ground, hairline edge, blur, the tucked two-layer shadow, the surface corner. With `.glass-liquid`, the liquid pane on its `::before` and `::after`. |
|
|
241
|
+
| `.neobrutalism` | `.neobrutalism-solo` | 2px ink edge, square corners, the hard offset slab. |
|
|
242
|
+
| `.pixel` | `.pixel-solo` | The stepped silhouette, the inset ring in place of a border, the pixel font. |
|
|
243
|
+
| `.chunky-tile` | `.chunky-tile-solo` | The tile corner, 2px edge, the bar under it, the rounded font. |
|
|
244
|
+
| `.cyber` | `.cyber-solo` | The surface diagonal (the control one on an action), 1px edge, the glow, the font. |
|
|
245
|
+
| `.sketch` | `.sketch-solo` | Uneven elliptical corners (sharp surface outline on a pane, expressive control outline on an action; subtle rounded contours when paired with `.sketch-rounded`), a 1px solid ink line, the 2px offset shadow, the handwriting face. |
|
|
176
246
|
|
|
177
247
|
```css
|
|
178
248
|
/* The only stylesheet from this package on the page. */
|
|
@@ -186,7 +256,7 @@ An aesthetic class sets material tokens and nothing paints until a component rea
|
|
|
186
256
|
A solo class ships in the same entrypoint as its aesthetic, and needs nothing else loaded:
|
|
187
257
|
|
|
188
258
|
- **It paints material, not colour.** Edge, corner, depth, silhouette, backdrop, font, and press. No intent, no fill amount, no hover tint -- the element has no presentation to compose. Glass's translucent ground is the one fill, because it is glass's material.
|
|
189
|
-
- **It reads its aesthetic's knobs and the theme's tokens, with the shipped values as fallbacks.** `--glass-radius-surface`, `--neo-offset`, `--pixel-unit`, `--tile-lift`, `--tile-radius`, `--cyber-cut`, `--cyber-shape`, `--cyber-shape-surface`, `--cyber-glow`, `--cyber-ink`, and the font knobs all work, set on the element or any ancestor. With the theme loaded it follows it; without it, it renders the shipped look.
|
|
259
|
+
- **It reads its aesthetic's knobs and the theme's tokens, with the shipped values as fallbacks.** `--glass-radius-surface`, `--neo-offset`, `--pixel-unit`, `--tile-lift`, `--tile-radius`, `--cyber-cut`, `--cyber-shape`, `--cyber-shape-surface`, `--cyber-glow`, `--cyber-ink`, `--sketch-radius`, `--sketch-radius-surface`, `--sketch-radius-rounded`, `--sketch-radius-surface-rounded`, and the font knobs (including `--font-sketch`) all work, set on the element or any ancestor. With the theme loaded it follows it; without it, it renders the shipped look.
|
|
190
260
|
- **It ignores the aesthetic around it.** It reads no `--ui-*` or `--elevation-color`, so a `.glass-solo` inside a `.pixel` region keeps its corners. The elevation modifiers do not reach it either.
|
|
191
261
|
- **It beats a foreign component's own styles.** The rules are unlayered and one class deep, so they win over a component's zero-specificity or layered rules wherever the two load. The flip side is that a Tailwind utility on the same element (`rounded-none`) loses to it: tune a solo class through its knobs.
|
|
192
262
|
- **It presses only an action.** Neobrutalism, chunky tile, and cyber press a `button`, `a[href]`, `[role="button"]`, `summary`, or button-type `input` that is not disabled; a container stays put, so a toast does not sink when clicked. Reduced motion drops the movement. Chunky tile's heavier label follows the same rule.
|
package/docs/usage/buttons.md
CHANGED
|
@@ -12,15 +12,15 @@ Intent classes map color tokens into button tone slots. [Presentation](./composi
|
|
|
12
12
|
|
|
13
13
|
Intent classes:
|
|
14
14
|
|
|
15
|
-
| Class
|
|
16
|
-
|
|
|
17
|
-
| `.neutral` _(default)_
|
|
18
|
-
| `.primary`
|
|
19
|
-
| `.secondary`
|
|
20
|
-
| `.success`
|
|
21
|
-
| `.warning`
|
|
22
|
-
| `.destructive
|
|
23
|
-
| `.info`
|
|
15
|
+
| Class | Meaning |
|
|
16
|
+
| ---------------------- | ------------------------------ |
|
|
17
|
+
| `.neutral` _(default)_ | No specific intent. |
|
|
18
|
+
| `.primary` | Primary action. |
|
|
19
|
+
| `.secondary` | Secondary/accent action. |
|
|
20
|
+
| `.success` | Successful or positive action. |
|
|
21
|
+
| `.warning` | Warning/caution action. |
|
|
22
|
+
| `.destructive` | Destructive or error action. |
|
|
23
|
+
| `.info` | Informational action. |
|
|
24
24
|
|
|
25
25
|
Every component that supports intent accepts the same list and reads the same [intent tokens](./theming.md#intent-tokens), so a custom intent class works everywhere without touching a component.
|
|
26
26
|
|
|
@@ -30,13 +30,13 @@ Size and shape classes:
|
|
|
30
30
|
|
|
31
31
|
| Class | Purpose |
|
|
32
32
|
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
33
|
-
| `.pill` | Fully rounded button corners
|
|
33
|
+
| `.pill` | Fully rounded button corners by default; under sketch it takes organic hand-drawn pill contours avoiding egg-shaped distortion. |
|
|
34
34
|
| `.sm` | Smaller button. |
|
|
35
35
|
| `.lg` | Larger button. |
|
|
36
|
-
| `.p-xs
|
|
37
|
-
| `.p-sm
|
|
38
|
-
| `.p-lg
|
|
39
|
-
| `.icon` | Square icon button,
|
|
36
|
+
| `.p-xs` | Tightest padding modifier (`px-2 py-0.5`; icon `p-0.5`). Also drops the `--control-height` minimum so a chip-sized button fits a table cell or a dense toolbar; every other size and padding class keeps that floor for a labeled button. |
|
|
37
|
+
| `.p-sm` | Compact padding modifier (`px-2.5 py-1`; icon `p-1`). |
|
|
38
|
+
| `.p-lg` | Spacious padding modifier (`px-6 py-3`; icon `p-3`). |
|
|
39
|
+
| `.icon` | Square icon button, at least `--control-height` on each side, or 2rem with `.sm` and 3rem with `.lg`. With `.p-xs`, `.p-sm`, or `.p-lg` it drops that floor and sizes to its own padding. Use an accessible name in HTML. |
|
|
40
40
|
| `.disabled`, `[disabled]`, `[aria-disabled="true"]`, `[data-disabled]` | Disabled styling. |
|
|
41
41
|
|
|
42
42
|
Examples:
|
package/docs/usage/composing.md
CHANGED
|
@@ -57,7 +57,7 @@ The combinations mean exactly what they spell:
|
|
|
57
57
|
<!-- A field sunk into the page -->
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
A fill class never decides an edge and an edge class never decides a fill. Use `.solid.edgeless` for a filled box with no line
|
|
60
|
+
A fill class never decides an edge and an edge class never decides a fill. Use `.solid.edgeless` for a filled box with no line; `.solid.edged` renders the same box, because the line fades out as the fill fills in.
|
|
61
61
|
|
|
62
62
|
The edge is the silhouette and nothing else. Rules _inside_ a component that has an inside are a separate switch — see [Content and layout → Table rules](./content-and-layout.md#table-rules) — because tying them to this axis made them arrive by implication rather than by request.
|
|
63
63
|
|
|
@@ -92,7 +92,7 @@ The same split governs the edge: a cascaded `.edgeless` is floored and the eleme
|
|
|
92
92
|
|
|
93
93
|
A tooltip bubble is filled, over a tinted ground. An intent fills it with that intent's own color: `.tooltip-bubble.primary` is the primary color, black on a light page and white on a dark one, and `.tooltip-bubble.destructive` is a red bubble.
|
|
94
94
|
|
|
95
|
-
With no intent the bubble is `--color-tooltip`, the one plate in the package chosen per theme rather than derived from an intent
|
|
95
|
+
With no intent the bubble is `--color-tooltip`, the one plate in the package chosen per theme rather than derived from an intent: near-white over a light page, a mid grey over a dark one. `--color-tooltip-contrast` is its ink.
|
|
96
96
|
|
|
97
97
|
Near-white is only 1.04:1 against a light page, so the bubble draws a hairline as well, and floors it: a container's `.solid` or `.edgeless` cannot take the boundary away from a bubble nobody classed, while `.tooltip-bubble.edgeless` still can. The ground keeps the bubble opaque at every fill, so a cascaded presentation leaves it readable over whatever it floats above. It reads the material tokens too, so an [aesthetic](./aesthetics.md) in scope shapes the bubble like any other component. See [Tooltips](./tooltips.md) for the full tooltip reference.
|
|
98
98
|
|
|
@@ -125,26 +125,26 @@ Presentation is two independent axes, so they get a column each. A `Yes` means t
|
|
|
125
125
|
|
|
126
126
|
Every other text control floors a _cascaded_ `.edgeless` and honours its own: a `.edgeless` toolbar will not erase the line of a field nobody classed, while `.ipt.edgeless` is a consumer describing what they want and gets it.
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
State and modifier classes such as `.interactive`, `.hoverable`, `.pressable`, `.invalid`, `.p-sm`, and `.vertical` sit above this map and are documented with their component.
|
|
129
129
|
|
|
130
130
|
## Elevation
|
|
131
131
|
|
|
132
132
|
Depth is a modifier, not an axis. Nothing is raised until an [aesthetic](./aesthetics.md) draws depth or one of these classes asks for it.
|
|
133
133
|
|
|
134
|
-
| Class
|
|
135
|
-
|
|
|
136
|
-
| `.
|
|
137
|
-
| `.
|
|
138
|
-
| `.
|
|
134
|
+
| Class | Depth |
|
|
135
|
+
| ----------- | ------------------------------------------------------------------------ |
|
|
136
|
+
| `.flat` | Removes part-based elevation; glass surfaces keep their complete shadow. |
|
|
137
|
+
| `.raised` | One unit of the depth in scope. Cards, tiles, popovers that sit close. |
|
|
138
|
+
| `.floating` | Twice it, for menus and popovers. |
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
These are a different thing from the raw `--elevation-*` shadow tokens in [Theming](./theming.md#foundation-tokens), which are fixed shadows for elements you style yourself.
|
|
141
141
|
|
|
142
142
|
Each is one unitless multiplier over whatever shadow geometry is in scope, so the same class reads as a soft blur on a plain page and as a hard offset slab under `.neobrutalism` — the aesthetic decides what depth looks like, the class decides how much of it this element takes.
|
|
143
143
|
|
|
144
144
|
```html
|
|
145
|
-
<article class="card
|
|
146
|
-
<div class="
|
|
147
|
-
<article class="card
|
|
145
|
+
<article class="card raised">Lifted</article>
|
|
146
|
+
<div class="floating panel">A menu surface</div>
|
|
147
|
+
<article class="card flat">Flat, whatever the page or container says</article>
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
The multiplier does not inherit: an elevation class lifts or flattens the element it is written on only, and an unclassed element inside it takes no depth of its own. Give each element that needs depth its own elevation class. Spread is deliberately left out of the multiplication, because an aesthetic that draws its edge as an inset ring spends spread on it and scaling that would erase the edge.
|
|
@@ -14,14 +14,11 @@ Layout helpers use the shared `--layout-gap` token. `.tight` sets it to `0.5rem`
|
|
|
14
14
|
- `.stack` is a vertical flex stack.
|
|
15
15
|
- `.cluster` is a wrapping horizontal flex row; `.between` adds `space-between` alignment.
|
|
16
16
|
- `.auto-grid` is a responsive auto-fit grid using `--layout-grid-min`.
|
|
17
|
-
- `.tight` and `.loose` set the shared gap to `0.5rem` or `1.5rem` on views, stacks, clusters, and auto-grids.
|
|
18
17
|
- `.section` adds responsive block padding and an inline gutter.
|
|
19
18
|
- `.section-content` centers content at `--container-max`; `.narrow` and `.wide` select the corresponding container tokens.
|
|
20
19
|
- `.divider` is horizontal; `.vertical` makes it self-stretch vertically. It takes intent, but presentation classes do not affect it.
|
|
21
20
|
- `.visually-hidden` hides content visually while keeping it in the accessibility tree, using the standard clip-based recipe. Not named `.sr-only`: on a `/tw` entry the consumer's own Tailwind build already ships a real `.sr-only`, and a same-named utility of this package's own would silently collide with it in the cascade — the same reason `.data-table` is not named `.table`.
|
|
22
21
|
|
|
23
|
-
The removed `--layout-stack-gap` and `--layout-cluster-gap` tokens have no compatibility aliases.
|
|
24
|
-
|
|
25
22
|
## Content
|
|
26
23
|
|
|
27
24
|
| Class | Purpose | Intent affects |
|
|
@@ -48,24 +45,24 @@ A table draws three kinds of line, and `.ruled` and `.ruleless` move all of them
|
|
|
48
45
|
|
|
49
46
|
```html
|
|
50
47
|
<table class="data-table">
|
|
51
|
-
Head and foot boundaries only
|
|
48
|
+
<!-- Head and foot boundaries only -->
|
|
52
49
|
</table>
|
|
53
50
|
<table class="data-table ruled">
|
|
54
|
-
Every row separated
|
|
51
|
+
<!-- Every row separated -->
|
|
55
52
|
</table>
|
|
56
53
|
<table class="data-table ruleless">
|
|
57
|
-
No lines inside the table at all
|
|
54
|
+
<!-- No lines inside the table at all -->
|
|
58
55
|
</table>
|
|
59
56
|
```
|
|
60
57
|
|
|
61
|
-
The boundaries under a head and above a foot separate the parts of a table from each other, so they are drawn by default where the row rules are not. Rules between body rows
|
|
58
|
+
The boundaries under a head and above a foot separate the parts of a table from each other, so they are drawn by default where the row rules are not. Rules between body rows are asked for by `.ruled` or `--ui-rule`, never by the edge axis, so whether you get them depends on your markup and not on a default you cannot see.
|
|
62
59
|
|
|
63
60
|
`--ui-rule` is the token behind both classes, so a container can set the answer for a whole region without classing each table:
|
|
64
61
|
|
|
65
62
|
```html
|
|
66
63
|
<section style="--ui-rule: 100%">
|
|
67
64
|
<table class="data-table">
|
|
68
|
-
Ruled by the region
|
|
65
|
+
<!-- Ruled by the region -->
|
|
69
66
|
</table>
|
|
70
67
|
</section>
|
|
71
68
|
```
|
|
@@ -93,10 +90,10 @@ This is the one place intent cascades, because a table's rows are parts of the t
|
|
|
93
90
|
|
|
94
91
|
```html
|
|
95
92
|
<table class="data-table success soft edged">
|
|
96
|
-
...
|
|
93
|
+
<!-- ... -->
|
|
97
94
|
</table>
|
|
98
|
-
<table class="data-table">
|
|
99
|
-
A ghost table: rules and type, no header plate
|
|
95
|
+
<table class="data-table ghost">
|
|
96
|
+
<!-- A ghost table: rules and type, no header plate -->
|
|
100
97
|
</table>
|
|
101
98
|
<kbd class="kbd primary solid">Ctrl</kbd>
|
|
102
99
|
<kbd class="kbd primary soft edged">Shift</kbd>
|
|
@@ -131,21 +128,25 @@ Use `.table-wrap` around `.data-table` when table width may exceed its container
|
|
|
131
128
|
</div>
|
|
132
129
|
```
|
|
133
130
|
|
|
131
|
+
A table takes the surface corner, like a card beside it. Nothing clips it: the four corner cells take the corners, so a `<caption>` sits above the table untouched in every engine. A cell that spans rows down into a bottom corner leaves that corner square.
|
|
132
|
+
|
|
133
|
+
`.table-wrap` scrolls, and a scroll container clips whatever paints outside it. Under an aesthetic that draws a halo -- cyber's glow -- the wrapper pads itself by the halo's reach and pulls itself out by the same amount, so the glow fits inside it and the table stays where it would be. The wrapper then reaches that far past its parent, which only shows when the parent is flush with the viewport. Depth shadows, such as a `.raised` table's, are not given room and are still cut. The wrapper can only make room for a halo it is inside, so put the aesthetic class on `.table-wrap` or an ancestor rather than on a wrapped table alone: `<table class="data-table cyber">` inside a plain wrapper glows, and the wrapper cuts the glow. Leave the wrapper off a table that can never outgrow its container; keep it wherever one can, or a wide table widens the whole page.
|
|
134
|
+
|
|
134
135
|
## Surfaces
|
|
135
136
|
|
|
136
|
-
| Class
|
|
137
|
-
|
|
|
138
|
-
| `.card`
|
|
139
|
-
| `.panel`
|
|
140
|
-
| `.interactive`
|
|
141
|
-
| `.hoverable`
|
|
142
|
-
| `.pressable`
|
|
143
|
-
| `.p-xs
|
|
144
|
-
| `.p-sm
|
|
145
|
-
| `.p-lg
|
|
146
|
-
| `.flush`
|
|
147
|
-
|
|
148
|
-
Both read intent, [presentation](./composing.md#presentation), and [material tokens](./customizing.md#material-tokens). A plain `.card` is a neutral bordered container; only an explicit presentation tints it. Resting at elevation `1` is not a visible shadow by itself — nothing draws depth until an [aesthetic](./aesthetics.md) supplies shadow geometry or `.
|
|
137
|
+
| Class | Purpose |
|
|
138
|
+
| -------------- | ------------------------------------------------------------------------------------- |
|
|
139
|
+
| `.card` | Bordered container, surface radius, padded. Rests at elevation `1`. |
|
|
140
|
+
| `.panel` | Flush container for sidebars, toolbars, and wells. No elevation. |
|
|
141
|
+
| `.interactive` | On `.card`. Adds pointer cursor, hover and press response, and a focus ring. |
|
|
142
|
+
| `.hoverable` | On `.card`. The hover half of `.interactive`: hover response only, no pointer cursor. |
|
|
143
|
+
| `.pressable` | On `.card`. The press half of `.interactive`: press response and pointer cursor. |
|
|
144
|
+
| `.p-xs` | On `.card` or `.panel`. Reduces padding further than `.p-sm`. |
|
|
145
|
+
| `.p-sm` | On `.card` or `.panel`. Reduces padding. |
|
|
146
|
+
| `.p-lg` | On `.card` or `.panel`. Increases padding. |
|
|
147
|
+
| `.flush` | On `.card` or `.panel`. Removes padding, for edge-to-edge content. |
|
|
148
|
+
|
|
149
|
+
Both read intent, [presentation](./composing.md#presentation), and [material tokens](./customizing.md#material-tokens). A plain `.card` is a neutral bordered container; only an explicit presentation tints it. Resting at elevation `1` is not a visible shadow by itself — nothing draws depth until an [aesthetic](./aesthetics.md) supplies shadow geometry or `.raised`/`.floating` asks for it; see [Composing → Elevation](./composing.md#elevation).
|
|
149
150
|
|
|
150
151
|
`.card.soft` with no named intent is untinted at rest — a plain `--color-foreground` plate, no ink mixed in, marking a different container without drawing attention to it. The intent tint and a `--color-surface` ground only appear together, on `:hover`, and only on `.card.interactive`/`.card.hoverable`: a plain `.card.soft` with neither has no hover state to reveal into and stays at the quiet rest. A named intent (`.card.soft.success`, `.card.soft.destructive`, and so on) keeps its ordinary tint at rest instead, and deepens further on hover the same way any other filled surface does — only the no-intent case is untinted, since removing an intent's own color would silence it rather than quiet it. `.solid` and `.ghost` are unaffected either way.
|
|
151
152
|
|