mote.css 0.5.1 → 0.6.1
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 +105 -1
- package/README.md +14 -0
- package/mote.components.css +83 -7
- package/mote.css +111 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,109 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [0.
|
|
8
|
+
## [0.6.1] - 2026-10-20
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- `.mote-print-only` now actually displays in print (the unconditional
|
|
13
|
+
`display: none` was after the print block at equal specificity —
|
|
14
|
+
scoped to `@media not print` and moved before it).
|
|
15
|
+
- `.mote-stack` no longer stretches `.mote-sr-only` inputs to 100%
|
|
16
|
+
width (hidden file inputs were creating invisible horizontal scroll).
|
|
17
|
+
- `.mote-doc > main` now uses `overflow-x: auto` (was `clip`, which
|
|
18
|
+
made wide tables invisible rather than scrollable).
|
|
19
|
+
- `.mote-theme-switch` shipped in mote.css: disables transitions during
|
|
20
|
+
`data-theme` flips so Chromium doesn't wedge elements at stale colors
|
|
21
|
+
(custom-property changes don't restart CSS transitions). The docs'
|
|
22
|
+
toggle snippet now includes it; the demo uses it.
|
|
23
|
+
- `.mote-doc > aside` gets the same sticky treatment as the nav rail
|
|
24
|
+
(top, max-height, overflow) — TOCs and aside content no longer scroll
|
|
25
|
+
out of view.
|
|
26
|
+
- Nav rail `max-height` accounts for `--mote-rail-top` (was
|
|
27
|
+
`calc(100svh - 2rem)` regardless of header height).
|
|
28
|
+
- Rail heading treatment (small uppercase labels) now applies to
|
|
29
|
+
`.mote-doc > aside` and `nav[aria-label="toc"]` headings too.
|
|
30
|
+
- `legend` gets `font-weight: 600` so the group caption reads stronger
|
|
31
|
+
than the field labels inside it.
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- `tabular-nums` on all `td` — figures align in data tables without
|
|
36
|
+
any page CSS (invisible on non-numeric content).
|
|
37
|
+
- `.mote-table-scroll`: scrollable table wrapper with sticky `thead`,
|
|
38
|
+
no margin jump on scroll start, and no page-level horizontal scroll.
|
|
39
|
+
- `.mote-grid-sparse`: auto-fit variant that collapses empty grid
|
|
40
|
+
tracks (footers, short card rows).
|
|
41
|
+
- `--mote-control-pad` / `--mote-control-pad-inline` and
|
|
42
|
+
`--mote-cell-pad` / `--mote-cell-pad-inline` density tokens.
|
|
43
|
+
- Docs: toggle snippet includes the theme-switch workaround; Chromium
|
|
44
|
+
note references the shipped class.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- Third ten-app evaluation completed against v0.6.0; all round-2 fixes
|
|
49
|
+
verified holding. Round-3 findings addressed in this patch release.
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- Pagination `<span>` current page: the pill box (display, min-width,
|
|
54
|
+
padding) now targets `[aria-current="page"]` as well as `<a>` — the
|
|
55
|
+
docs-recommended span form renders correctly (was a 6.5px sliver).
|
|
56
|
+
- Pagination: `flex-wrap: wrap` on the link row — 10 pills at 390px
|
|
57
|
+
no longer scroll the page horizontally.
|
|
58
|
+
- Anchor ghosts: `.mote-ghost` now carries its own padding, border-radius,
|
|
59
|
+
text-decoration:none and cursor:pointer — `<a class="mote-ghost">`
|
|
60
|
+
renders as a proper pill (was an underlined unpadded rectangle).
|
|
61
|
+
- Badge links: `a.mote-badge` no longer underlines; `user-select: none`
|
|
62
|
+
dropped from badges so version numbers and tags can be copied.
|
|
63
|
+
- `.mote-display` reads `--mote-status` — themed pages (error, warning)
|
|
64
|
+
tint their giant display text automatically.
|
|
65
|
+
- Default `--mote-rail-top` is now 4.75rem when `body > header` exists
|
|
66
|
+
(the sticky rail clears the sticky header without manual overrides).
|
|
67
|
+
- `.mote-doc > main` gets `overflow-x: clip` — wide tables truly scroll
|
|
68
|
+
inside main, never the page.
|
|
69
|
+
- Sticky header: default `padding-block: 0.7rem` — content no longer hugs
|
|
70
|
+
the border.
|
|
71
|
+
- `.mote-row` zeroes heading margins inside the row — version headers
|
|
72
|
+
and card titles no longer balloon the flex context.
|
|
73
|
+
- Checkbox/radio `width: 1em` hardened against page-level
|
|
74
|
+
`width: 100%` rules.
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- `.mote-btn`: solid button recipe on any element (anchors, spans) —
|
|
79
|
+
the full solid chrome including gated status classes; hero CTAs and
|
|
80
|
+
pricing links no longer need page CSS.
|
|
81
|
+
- `.mote-media`: media object (avatar/icon beside body) — flex row,
|
|
82
|
+
last child grows; forum posts, comments, chat.
|
|
83
|
+
- `nav[aria-label="toc"]`: semantic table-of-contents pattern (mirrors
|
|
84
|
+
breadcrumbs and pagination) — right-rail asides, "On this page" nav.
|
|
85
|
+
- `.mote-no-print` / `.mote-print-only`: opt-in print visibility helpers.
|
|
86
|
+
- `aria-invalid="true"` styled alongside `:user-invalid` — programmatic
|
|
87
|
+
validation states (server-side, failed-save) without waiting for user
|
|
88
|
+
interaction.
|
|
89
|
+
- Rail headings: `.mote-doc > nav :is(h2, h3)` at label scale —
|
|
90
|
+
grouped sidebar navigation without page CSS.
|
|
91
|
+
- `.mote-card` reads `--mote-status` for its border — featured/emphasized
|
|
92
|
+
cards from one status class.
|
|
93
|
+
- Docs recipes: card flush-media, numeric table columns with sticky
|
|
94
|
+
headers, sparse grids (auto-fit), canonical search form.
|
|
95
|
+
- `.mote-stack` opt-in class: stretches form fields to 100% while
|
|
96
|
+
keeping checkboxes/radios at native 1em — no page CSS needed.
|
|
97
|
+
- `--mote-container-max` token (default 70rem): narrow the reading
|
|
98
|
+
measure for long-form pages without new classes.
|
|
99
|
+
- Spinner sized in em (1.25em, 0.15em border) — scales with context
|
|
100
|
+
(buttons, table rows, loading text).
|
|
101
|
+
- Docs: display text section with error-code example and status tinting;
|
|
102
|
+
`--mote-avatar` sizing variable documented; `--mote-grid-min` density
|
|
103
|
+
variable documented; `[role="alert"]`/`[role="status"]` semantic
|
|
104
|
+
feedback helpers documented; safe stacked-form recipe and `.mote-stack`;
|
|
105
|
+
Chromium theme-toggle transition workaround.
|
|
106
|
+
|
|
107
|
+
### Changed
|
|
108
|
+
|
|
109
|
+
- Second ten-app evaluation completed against v0.5.1; all round-1 fixes
|
|
110
|
+
verified holding. Round-2 findings addressed in this release.
|
|
9
111
|
|
|
10
112
|
### Fixed
|
|
11
113
|
|
|
@@ -274,6 +376,8 @@ Components:
|
|
|
274
376
|
- Element gallery demo page (`demo.html`).
|
|
275
377
|
|
|
276
378
|
[0.3.0]: https://gitlab.com/abmach/mote/compare/v0.2.1...v0.3.0
|
|
379
|
+
[0.6.1]: https://gitlab.com/abmach/mote/compare/v0.6.0...v0.6.1
|
|
380
|
+
[0.6.0]: https://gitlab.com/abmach/mote/compare/v0.5.1...v0.6.0
|
|
277
381
|
[0.5.1]: https://gitlab.com/abmach/mote/compare/v0.5.0...v0.5.1
|
|
278
382
|
[0.5.0]: https://gitlab.com/abmach/mote/compare/v0.4.0...v0.5.0
|
|
279
383
|
[0.4.0]: https://gitlab.com/abmach/mote/compare/v0.3.0...v0.4.0
|
package/README.md
CHANGED
|
@@ -96,6 +96,12 @@ The consequence: theming is a handful of variable overrides, and an inline tweak
|
|
|
96
96
|
| `--mote-radius` | `10px` | | Default corner softness |
|
|
97
97
|
| `--mote-radius-sm` | `6px` | | Controls, inline code |
|
|
98
98
|
| `--mote-radius-lg` | `16px` | | Dialogs |
|
|
99
|
+
| `--mote-container-max` | `70rem` | | Page wrapper max width (narrow for reading) |
|
|
100
|
+
| `--mote-display` | `clamp(2.75rem, 1.5rem + 4vw, 5rem)` | | Display text scale (opt-in) |
|
|
101
|
+
| `--mote-grid-min` | `16rem` | | Card grid minimum track width |
|
|
102
|
+
| `--mote-avatar` | `2.5rem` | | Avatar size |
|
|
103
|
+
| `--mote-control-pad` | `0.5rem` | | Button/control vertical padding |
|
|
104
|
+
| `--mote-cell-pad` | `0.6rem` | | Table cell vertical padding |
|
|
99
105
|
| `--mote-shadow` / `--mote-shadow-sm` | warm diffuse | | Elevation |
|
|
100
106
|
| `--mote-transition` | `150ms ease` | | Hover/focus timing |
|
|
101
107
|
|
|
@@ -144,11 +150,19 @@ mote is class-optional by design — elements are styled from tags alone; these
|
|
|
144
150
|
| Sticky site header / nav pills | `body > header` — semantic; `.mote-header`/`.mote-nav` only for shells wrapped in a `<div>` |
|
|
145
151
|
| Semantic buttons (gated) | `class="mote-success"` etc. on the button itself — themed sections never recolor actions |
|
|
146
152
|
| Ghost buttons | `.mote-ghost` — transparent fill; status tints from the button's own class (gated like solids) |
|
|
153
|
+
| Solid button on any element | `.mote-btn` — the full solid recipe for anchors, spans; status classes gated |
|
|
154
|
+
| Media objects | `.mote-media` — avatar/icon beside body (flex, last child grows) |
|
|
147
155
|
| Display text | `.mote-display` — opt-in hero/error-code scale via `--mote-display` |
|
|
148
156
|
| Content rows | `.mote-row` + `.mote-push` — flex row, right-align helper |
|
|
157
|
+
| Stacked forms | `.mote-stack` — opt-in full-width fields, checkboxes stay 1em |
|
|
158
|
+
| Scrollable tables | `.mote-table-scroll` — sticky `thead`, no page scroll, no margin jump |
|
|
159
|
+
| Sparse grids | `.mote-grid-sparse` — auto-fit variant, collapses empty tracks |
|
|
149
160
|
| Pagination | `nav[aria-label="pagination"]` — semantic, no class |
|
|
161
|
+
| Table of contents | `nav[aria-label="toc"]` — semantic, no class |
|
|
150
162
|
| Footer baseline | `body > footer` — semantic top-border + padding |
|
|
151
163
|
| Screen-reader helper | `.mote-sr-only` (doubles as a skip link when focused) |
|
|
164
|
+
| Print helpers | `.mote-no-print` / `.mote-print-only` |
|
|
165
|
+
| Theme-switch guard | `.mote-theme-switch` — prevents Chromium stale-color bug on `data-theme` flips |
|
|
152
166
|
| Status inheritance control | `.mote-default` (force accent) · `.mote-reset` (clear inherited status) |
|
|
153
167
|
| Breadcrumbs | `nav[aria-label="breadcrumb"]` — semantic, no class |
|
|
154
168
|
| Card grids | `.mote-grid` — auto-fill columns from the container, no breakpoints |
|
package/mote.components.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* mote.components.css — opt-in components for mote.css.
|
|
3
|
-
* v0.
|
|
3
|
+
* v0.6.1 · MIT
|
|
4
4
|
* https://gitlab.com/abmach/mote · mirror: https://github.com/abmach/mote
|
|
5
5
|
*
|
|
6
6
|
* Requires mote.css loaded first (provides the --mote-* tokens).
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
flex-direction: column;
|
|
20
20
|
padding: 1.25rem 1.5rem;
|
|
21
21
|
border: var(--mote-border-width) solid var(--mote-border);
|
|
22
|
+
border-color: color-mix(in oklab, var(--mote-status, var(--mote-border)), var(--mote-border) 60%);
|
|
22
23
|
border-radius: var(--mote-radius-lg);
|
|
23
24
|
background: color-mix(in oklab, var(--mote-surface) 55%, var(--mote-bg));
|
|
24
25
|
box-shadow: var(--mote-shadow-sm);
|
|
@@ -48,7 +49,11 @@
|
|
|
48
49
|
line-height: 1.4;
|
|
49
50
|
background: var(--mote-status-soft, var(--mote-accent-soft));
|
|
50
51
|
color: var(--mote-status, var(--mote-accent-deep));
|
|
51
|
-
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Badges as links (tag chips, version pills): kill the underline */
|
|
55
|
+
a:where(.mote-badge) {
|
|
56
|
+
text-decoration: none;
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
/* ---------------------------------------------------------------------------
|
|
@@ -95,9 +100,10 @@
|
|
|
95
100
|
.mote-spinner {
|
|
96
101
|
display: inline-block;
|
|
97
102
|
vertical-align: -0.25em;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
103
|
+
/* em sizing: scales with context (buttons, table rows, loading text) */
|
|
104
|
+
width: 1.25em;
|
|
105
|
+
height: 1.25em;
|
|
106
|
+
border: 0.15em solid color-mix(in oklab, var(--mote-status, var(--mote-accent)), transparent 65%);
|
|
101
107
|
border-block-start-color: var(--mote-status, var(--mote-accent));
|
|
102
108
|
border-radius: 999px;
|
|
103
109
|
animation: mote-spin 0.7s linear infinite;
|
|
@@ -124,6 +130,7 @@
|
|
|
124
130
|
background: color-mix(in oklab, var(--mote-bg) 82%, transparent);
|
|
125
131
|
backdrop-filter: blur(10px);
|
|
126
132
|
border-block-end: var(--mote-border-width) solid var(--mote-border);
|
|
133
|
+
padding-block: 0.7rem;
|
|
127
134
|
}
|
|
128
135
|
|
|
129
136
|
:where(body > header nav, .mote-nav) ul {
|
|
@@ -183,13 +190,14 @@ nav[aria-label="breadcrumb"] [aria-current="page"] {
|
|
|
183
190
|
/* Pagination — semantic selector, no class (mirrors breadcrumbs) */
|
|
184
191
|
nav[aria-label="pagination"] ul {
|
|
185
192
|
display: flex;
|
|
193
|
+
flex-wrap: wrap;
|
|
186
194
|
gap: 0.25rem;
|
|
187
195
|
padding: 0;
|
|
188
196
|
margin: 0;
|
|
189
197
|
list-style: none;
|
|
190
198
|
}
|
|
191
199
|
|
|
192
|
-
nav[aria-label="pagination"] a {
|
|
200
|
+
nav[aria-label="pagination"] :is(a, [aria-current="page"]) {
|
|
193
201
|
display: inline-block;
|
|
194
202
|
min-width: 2.2rem;
|
|
195
203
|
padding: 0.35rem 0.6rem;
|
|
@@ -215,6 +223,45 @@ nav[aria-label="pagination"] [aria-current="page"]:hover {
|
|
|
215
223
|
color: var(--mote-on-accent);
|
|
216
224
|
}
|
|
217
225
|
|
|
226
|
+
/* Table of contents — semantic selector (mirrors breadcrumbs/pagination) */
|
|
227
|
+
nav[aria-label="toc"] ul {
|
|
228
|
+
padding-inline-start: 0.8rem;
|
|
229
|
+
margin: 0;
|
|
230
|
+
list-style: none;
|
|
231
|
+
font-size: 0.9em;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
nav[aria-label="toc"] li {
|
|
235
|
+
margin-block: 0.2rem;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
nav[aria-label="toc"] a {
|
|
239
|
+
color: var(--mote-muted);
|
|
240
|
+
text-decoration: none;
|
|
241
|
+
transition: color var(--mote-transition);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
nav[aria-label="toc"] a:hover {
|
|
245
|
+
color: var(--mote-accent-deep);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Scrollable table wrapper: sticky thead, no page scroll, no margin jump */
|
|
249
|
+
.mote-table-scroll {
|
|
250
|
+
overflow-x: auto;
|
|
251
|
+
max-height: 60vh;
|
|
252
|
+
overflow-y: auto;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.mote-table-scroll table {
|
|
256
|
+
margin-block: 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.mote-table-scroll thead th {
|
|
260
|
+
position: sticky;
|
|
261
|
+
top: 0;
|
|
262
|
+
background: var(--mote-bg);
|
|
263
|
+
}
|
|
264
|
+
|
|
218
265
|
/* Page footer: the quiet sibling of the site header */
|
|
219
266
|
:where(body > footer, .mote-footer) {
|
|
220
267
|
margin-block-start: 3rem;
|
|
@@ -461,6 +508,7 @@ details[name] > :not(summary):last-child {
|
|
|
461
508
|
when the header actually exists. */
|
|
462
509
|
html:where(:has(body > header)) {
|
|
463
510
|
scroll-padding-block-start: 5rem;
|
|
511
|
+
--mote-rail-top: 4.75rem;
|
|
464
512
|
}
|
|
465
513
|
|
|
466
514
|
.mote-doc > header { grid-row: 1; grid-column: 1 / -1; }
|
|
@@ -468,6 +516,12 @@ html:where(:has(body > header)) {
|
|
|
468
516
|
|
|
469
517
|
.mote-doc > main { grid-row: 2; grid-column: 1; min-width: 0; }
|
|
470
518
|
|
|
519
|
+
/* Content stays inside the grid track — wide tables scroll here,
|
|
520
|
+
not the page. */
|
|
521
|
+
.mote-doc > main {
|
|
522
|
+
overflow-x: auto;
|
|
523
|
+
}
|
|
524
|
+
|
|
471
525
|
/* nav = left rail */
|
|
472
526
|
.mote-doc > nav {
|
|
473
527
|
grid-row: 2;
|
|
@@ -476,7 +530,7 @@ html:where(:has(body > header)) {
|
|
|
476
530
|
align-self: start;
|
|
477
531
|
position: sticky;
|
|
478
532
|
top: var(--mote-rail-top, 1rem);
|
|
479
|
-
max-height: calc(100svh -
|
|
533
|
+
max-height: calc(100svh - var(--mote-rail-top, 1rem) - 1rem);
|
|
480
534
|
overflow: auto;
|
|
481
535
|
}
|
|
482
536
|
|
|
@@ -512,6 +566,19 @@ html:where(:has(body > header)) {
|
|
|
512
566
|
color: var(--mote-on-accent);
|
|
513
567
|
}
|
|
514
568
|
|
|
569
|
+
/* Rail headings: small label-scale for grouped navigation */
|
|
570
|
+
.mote-doc > nav :is(h2, h3),
|
|
571
|
+
.mote-doc > aside :is(h2, h3),
|
|
572
|
+
nav[aria-label="toc"] :is(h2, h3) {
|
|
573
|
+
margin: 1rem 0 0.3rem;
|
|
574
|
+
padding-inline: 0.75rem;
|
|
575
|
+
font-size: 0.72rem;
|
|
576
|
+
font-weight: 600;
|
|
577
|
+
text-transform: uppercase;
|
|
578
|
+
letter-spacing: 0.05em;
|
|
579
|
+
color: var(--mote-muted);
|
|
580
|
+
}
|
|
581
|
+
|
|
515
582
|
.mote-doc:where(:has(> nav)) {
|
|
516
583
|
grid-template-columns: minmax(12rem, 16rem) minmax(0, 1fr);
|
|
517
584
|
}
|
|
@@ -526,6 +593,10 @@ html:where(:has(body > header)) {
|
|
|
526
593
|
grid-column: 2;
|
|
527
594
|
min-width: 0;
|
|
528
595
|
align-self: start;
|
|
596
|
+
position: sticky;
|
|
597
|
+
top: var(--mote-rail-top, 1rem);
|
|
598
|
+
max-height: calc(100svh - var(--mote-rail-top, 1rem) - 1rem);
|
|
599
|
+
overflow: auto;
|
|
529
600
|
}
|
|
530
601
|
|
|
531
602
|
.mote-doc:where(:has(> nav)) > aside {
|
|
@@ -568,3 +639,8 @@ html:where(:has(body > header)) {
|
|
|
568
639
|
gives 3-wide pricing; 26rem gives 2-column content. */
|
|
569
640
|
grid-template-columns: repeat(auto-fill, minmax(min(var(--mote-grid-min, 16rem), 100%), 1fr));
|
|
570
641
|
}
|
|
642
|
+
|
|
643
|
+
/* Sparse grids: collapse empty tracks (footers, short card rows) */
|
|
644
|
+
.mote-grid-sparse {
|
|
645
|
+
grid-template-columns: repeat(auto-fit, minmax(min(var(--mote-grid-min, 16rem), 100%), 1fr));
|
|
646
|
+
}
|
package/mote.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* mote.css — a mote of styling for plain HTML.
|
|
3
|
-
* v0.
|
|
3
|
+
* v0.6.1 · MIT
|
|
4
4
|
* https://gitlab.com/abmach/mote · mirror: https://github.com/abmach/mote
|
|
5
5
|
*
|
|
6
6
|
* The smallest thing that can carry style:
|
|
@@ -46,6 +46,9 @@
|
|
|
46
46
|
--mote-tracking: -0.011em;
|
|
47
47
|
/* Display scale — opt-in, for heroes and error pages; body scale untouched */
|
|
48
48
|
--mote-display: clamp(2.75rem, 1.5rem + 4vw, 5rem);
|
|
49
|
+
/* Reading measure: the comfortable max width for long-form content.
|
|
50
|
+
Override per-page for narrow or wide layouts. */
|
|
51
|
+
--mote-container-max: 70rem;
|
|
49
52
|
|
|
50
53
|
/* Shape & depth */
|
|
51
54
|
--mote-radius: 10px;
|
|
@@ -216,7 +219,7 @@ a {
|
|
|
216
219
|
transition: color var(--mote-transition), text-decoration-color var(--mote-transition);
|
|
217
220
|
}
|
|
218
221
|
|
|
219
|
-
a:hover {
|
|
222
|
+
a:hover:where(:not(.mote-btn, .mote-ghost)) {
|
|
220
223
|
color: var(--mote-accent-deep);
|
|
221
224
|
text-decoration-color: currentColor;
|
|
222
225
|
}
|
|
@@ -369,7 +372,8 @@ caption {
|
|
|
369
372
|
}
|
|
370
373
|
|
|
371
374
|
th, td {
|
|
372
|
-
|
|
375
|
+
font-variant-numeric: tabular-nums;
|
|
376
|
+
padding: var(--mote-cell-pad, 0.6rem) var(--mote-cell-pad-inline, 0.8rem);
|
|
373
377
|
border-block-end: var(--mote-border-width) solid var(--mote-border);
|
|
374
378
|
text-align: start;
|
|
375
379
|
vertical-align: top;
|
|
@@ -406,7 +410,7 @@ fieldset {
|
|
|
406
410
|
border-radius: var(--mote-radius);
|
|
407
411
|
}
|
|
408
412
|
|
|
409
|
-
legend { padding-inline: 0.4rem; }
|
|
413
|
+
legend { padding-inline: 0.4rem; font-weight: 600; }
|
|
410
414
|
|
|
411
415
|
input, select, textarea {
|
|
412
416
|
font: inherit;
|
|
@@ -451,10 +455,16 @@ select[multiple] {
|
|
|
451
455
|
width: 1em;
|
|
452
456
|
height: 1em;
|
|
453
457
|
padding: 0;
|
|
454
|
-
accent-color: var(--mote-accent);
|
|
458
|
+
accent-color: var(--mote-status, var(--mote-accent));
|
|
455
459
|
vertical-align: baseline;
|
|
456
460
|
}
|
|
457
461
|
|
|
462
|
+
/* Harden checkbox/radio sizing against page-level width: 100% rules
|
|
463
|
+
(the documented stacked-form recipe). :where() keeps it overridable. */
|
|
464
|
+
:is([type="checkbox"], [type="radio"]):where(input) {
|
|
465
|
+
width: 1em;
|
|
466
|
+
}
|
|
467
|
+
|
|
458
468
|
[type="color"] {
|
|
459
469
|
padding: 0.2rem;
|
|
460
470
|
height: 2.4rem;
|
|
@@ -484,7 +494,7 @@ select[multiple] {
|
|
|
484
494
|
cursor: not-allowed;
|
|
485
495
|
}
|
|
486
496
|
|
|
487
|
-
:is(input, select, textarea):user-invalid {
|
|
497
|
+
:is(input, select, textarea):is(:user-invalid, [aria-invalid="true"]) {
|
|
488
498
|
border-color: var(--mote-error);
|
|
489
499
|
}
|
|
490
500
|
|
|
@@ -492,7 +502,7 @@ button, [type="button"], [type="submit"], [type="reset"] {
|
|
|
492
502
|
font: inherit;
|
|
493
503
|
font-weight: 500;
|
|
494
504
|
color: var(--mote-on-accent);
|
|
495
|
-
padding: 0.5rem 1.1rem;
|
|
505
|
+
padding: var(--mote-control-pad, 0.5rem) var(--mote-control-pad-inline, 1.1rem);
|
|
496
506
|
background: var(--mote-accent);
|
|
497
507
|
border: var(--mote-border-width) solid transparent;
|
|
498
508
|
border-radius: var(--mote-radius-sm);
|
|
@@ -523,9 +533,16 @@ button:hover, [type="button"]:hover, [type="submit"]:hover, [type="reset"]:hover
|
|
|
523
533
|
/* Ghost buttons: quiet, transparent fill, accent-tinted. Like solids,
|
|
524
534
|
status colors come from the button's own class, never from context. */
|
|
525
535
|
.mote-ghost {
|
|
536
|
+
display: inline-block;
|
|
537
|
+
font: inherit;
|
|
538
|
+
font-weight: 500;
|
|
526
539
|
background: none;
|
|
527
540
|
border: var(--mote-border-width) solid color-mix(in oklab, var(--mote-accent), transparent 55%);
|
|
528
541
|
color: var(--mote-accent-deep);
|
|
542
|
+
padding: var(--mote-control-pad, 0.5rem) var(--mote-control-pad-inline, 1.1rem);
|
|
543
|
+
border-radius: var(--mote-radius-sm);
|
|
544
|
+
text-decoration: none;
|
|
545
|
+
cursor: pointer;
|
|
529
546
|
}
|
|
530
547
|
|
|
531
548
|
.mote-ghost:hover {
|
|
@@ -631,7 +648,7 @@ progress, meter {
|
|
|
631
648
|
|
|
632
649
|
/* Centered page wrapper: <main class="mote-container"> */
|
|
633
650
|
.mote-container {
|
|
634
|
-
width: min(100% - 3rem,
|
|
651
|
+
width: min(100% - 3rem, var(--mote-container-max));
|
|
635
652
|
margin-inline: auto;
|
|
636
653
|
}
|
|
637
654
|
|
|
@@ -649,6 +666,74 @@ progress, meter {
|
|
|
649
666
|
|
|
650
667
|
.mote-push { margin-inline-start: auto; }
|
|
651
668
|
|
|
669
|
+
/* Stacked forms: stretch fields, keep checkboxes/radios compact.
|
|
670
|
+
An opt-in alternative to the page-global width: 100% recipe. */
|
|
671
|
+
.mote-stack :is(input, select, textarea) {
|
|
672
|
+
width: 100%;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
.mote-stack :is([type="checkbox"], [type="radio"]) {
|
|
676
|
+
width: 1em;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
.mote-stack :is(input, select, textarea):where(.mote-sr-only) {
|
|
680
|
+
width: 1px;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/* Solid button on any element — anchors, spans, divs.
|
|
684
|
+
Same recipe as the element-level button styles; status classes
|
|
685
|
+
gated identically (class on the element itself). */
|
|
686
|
+
.mote-btn {
|
|
687
|
+
display: inline-block;
|
|
688
|
+
font: inherit;
|
|
689
|
+
font-weight: 500;
|
|
690
|
+
color: var(--mote-on-accent);
|
|
691
|
+
padding: 0.5rem 1.1rem;
|
|
692
|
+
background: var(--mote-accent);
|
|
693
|
+
border: var(--mote-border-width) solid transparent;
|
|
694
|
+
border-radius: var(--mote-radius-sm);
|
|
695
|
+
text-decoration: none;
|
|
696
|
+
cursor: pointer;
|
|
697
|
+
transition: background var(--mote-transition), border-color var(--mote-transition),
|
|
698
|
+
transform var(--mote-transition);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.mote-btn:hover {
|
|
702
|
+
background: color-mix(in oklab, var(--mote-accent), var(--mote-fg) 14%);
|
|
703
|
+
box-shadow: var(--mote-shadow-sm);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
.mote-btn:active {
|
|
707
|
+
transform: translateY(1px);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.mote-btn:where(.mote-success, .mote-warning, .mote-error, .mote-info, .mote-muted):where(:not(.mote-ghost)) {
|
|
711
|
+
background: var(--mote-status);
|
|
712
|
+
color: var(--mote-on-status, var(--mote-bg));
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
.mote-btn:where(.mote-success, .mote-warning, .mote-error, .mote-info, .mote-muted):where(:not(.mote-ghost)):hover {
|
|
716
|
+
background: color-mix(in oklab, var(--mote-status), var(--mote-fg) 14%);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/* Media object: avatar/icon beside body (forum posts, comments, chat) */
|
|
720
|
+
.mote-media {
|
|
721
|
+
display: flex;
|
|
722
|
+
align-items: flex-start;
|
|
723
|
+
gap: 1rem;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
.mote-media > :last-child {
|
|
727
|
+
flex: 1;
|
|
728
|
+
min-width: 0;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/* Headings inside rows (version headers, card titles): default heading
|
|
732
|
+
margins balloon the row — zero them inside the flex context. */
|
|
733
|
+
:where(.mote-row) > :is(h1, h2, h3, h4, h5, h6) {
|
|
734
|
+
margin-block: 0;
|
|
735
|
+
}
|
|
736
|
+
|
|
652
737
|
/* Visually hidden, screen-reader available */
|
|
653
738
|
.mote-sr-only {
|
|
654
739
|
position: absolute;
|
|
@@ -740,6 +825,7 @@ progress, meter {
|
|
|
740
825
|
font-size: var(--mote-display);
|
|
741
826
|
line-height: 1.1;
|
|
742
827
|
letter-spacing: var(--mote-tracking);
|
|
828
|
+
color: var(--mote-status, inherit);
|
|
743
829
|
text-wrap: balance;
|
|
744
830
|
}
|
|
745
831
|
|
|
@@ -784,4 +870,21 @@ progress, meter {
|
|
|
784
870
|
a { color: #000; }
|
|
785
871
|
details { border: none; }
|
|
786
872
|
dialog { box-shadow: none; }
|
|
873
|
+
|
|
874
|
+
/* Opt-in print helpers */
|
|
875
|
+
.mote-no-print { display: none !important; }
|
|
876
|
+
.mote-print-only { display: block; }
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
@media not print {
|
|
880
|
+
.mote-print-only { display: none; }
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/* Theme switch: disable transitions during data-theme flips.
|
|
884
|
+
Chromium doesn't restart CSS transitions on custom-property changes,
|
|
885
|
+
so flipping data-theme leaves elements at the old theme's colors.
|
|
886
|
+
Apply this class before the flip, remove after one frame. */
|
|
887
|
+
.mote-theme-switch,
|
|
888
|
+
.mote-theme-switch * {
|
|
889
|
+
transition: none !important;
|
|
787
890
|
}
|