@ptbdynamic/plinth 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +258 -2
- package/package.json +99 -4
- package/packages/css/dist/avatar.css +122 -0
- package/packages/css/dist/badge.css +76 -0
- package/packages/css/dist/button.css +273 -0
- package/packages/css/dist/callout.css +143 -0
- package/packages/css/dist/code-block.css +283 -0
- package/packages/css/dist/confirm-dialog.css +183 -0
- package/packages/css/dist/data-table.css +470 -0
- package/packages/css/dist/dialog.css +113 -0
- package/packages/css/dist/drawer.css +156 -0
- package/packages/css/dist/fonts/geist/LICENSE +93 -0
- package/packages/css/dist/fonts/geist/geist-cyrillic-ext-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/geist/geist-cyrillic-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/geist/geist-latin-ext-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/geist/geist-latin-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/geist/geist-vietnamese-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/geist-mono/LICENSE +93 -0
- package/packages/css/dist/fonts/geist-mono/geist-mono-cyrillic-ext-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/geist-mono/geist-mono-cyrillic-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/geist-mono/geist-mono-latin-ext-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/geist-mono/geist-mono-latin-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/geist-mono/geist-mono-symbols2-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/geist-mono/geist-mono-vietnamese-wght-normal.woff2 +0 -0
- package/packages/css/dist/fonts/index.css +109 -0
- package/packages/css/dist/header.css +110 -0
- package/packages/css/dist/icon.css +51 -0
- package/packages/css/dist/list-card.css +76 -0
- package/packages/css/dist/list-row.css +164 -0
- package/packages/css/dist/menu-sheet.css +84 -0
- package/packages/css/dist/modal.css +367 -0
- package/packages/css/dist/pill-row.css +197 -0
- package/packages/css/dist/plinth.css +3773 -0
- package/packages/css/dist/section-menu.css +225 -0
- package/packages/css/dist/sheet.css +239 -0
- package/packages/css/dist/tokens.css +405 -0
- package/packages/react/dist/PlinthAvatar.d.ts +17 -0
- package/packages/react/dist/PlinthBadge.d.ts +7 -0
- package/packages/react/dist/PlinthButton.d.ts +29 -0
- package/packages/react/dist/PlinthCallout.d.ts +16 -0
- package/packages/react/dist/PlinthCodeBlock.d.ts +24 -0
- package/packages/react/dist/PlinthConfirmDialog.d.ts +38 -0
- package/packages/react/dist/PlinthDataTable.d.ts +11 -0
- package/packages/react/dist/PlinthDataTableCell.d.ts +15 -0
- package/packages/react/dist/PlinthDataTableColumn.d.ts +13 -0
- package/packages/react/dist/PlinthDataTableEmpty.d.ts +9 -0
- package/packages/react/dist/PlinthDataTableRow.d.ts +9 -0
- package/packages/react/dist/PlinthDataTableSort.d.ts +4 -0
- package/packages/react/dist/PlinthDialog.d.ts +26 -0
- package/packages/react/dist/PlinthDrawer.d.ts +29 -0
- package/packages/react/dist/PlinthHeader.d.ts +12 -0
- package/packages/react/dist/PlinthIcon.d.ts +10 -0
- package/packages/react/dist/PlinthIconButton.d.ts +26 -0
- package/packages/react/dist/PlinthListCard.d.ts +14 -0
- package/packages/react/dist/PlinthListRow.d.ts +29 -0
- package/packages/react/dist/PlinthMenuSheet.d.ts +24 -0
- package/packages/react/dist/PlinthPill.d.ts +17 -0
- package/packages/react/dist/PlinthPillRow.d.ts +13 -0
- package/packages/react/dist/PlinthSectionMenu.d.ts +11 -0
- package/packages/react/dist/PlinthSectionMenuItem.d.ts +20 -0
- package/packages/react/dist/PlinthSheet.d.ts +26 -0
- package/packages/react/dist/avatar.d.ts +12 -0
- package/packages/react/dist/button.d.ts +21 -0
- package/packages/react/dist/callout.d.ts +19 -0
- package/packages/react/dist/code-block.d.ts +16 -0
- package/packages/react/dist/confirm-dialog.d.ts +23 -0
- package/packages/react/dist/data-table.d.ts +15 -0
- package/packages/react/dist/dialog.d.ts +10 -0
- package/packages/react/dist/drawer.d.ts +20 -0
- package/packages/react/dist/heading.d.ts +5 -0
- package/packages/react/dist/icon.d.ts +5 -0
- package/packages/react/dist/index.d.ts +40 -0
- package/packages/react/dist/index.js +1127 -0
- package/packages/react/dist/list-row.d.ts +5 -0
- package/packages/react/dist/markup.d.ts +9 -0
- package/packages/react/dist/sheet.d.ts +12 -0
- package/packages/react/dist/size.d.ts +13 -0
- package/packages/react/dist/swipe.d.ts +15 -0
- package/packages/react/dist/tones.d.ts +5 -0
- package/packages/tokens/dist/index.d.ts +218 -0
- package/packages/tokens/dist/index.js +3966 -0
- package/packages/tokens/dist/tailwind-theme.css +80 -0
- package/packages/tokens/dist/tokens.css +405 -0
- package/packages/tokens/dist/tokens.json +3762 -0
- package/packages/vue/dist/PlinthAvatar.vue.d.ts +24 -0
- package/packages/vue/dist/PlinthBadge.vue.d.ts +21 -0
- package/packages/vue/dist/PlinthButton.vue.d.ts +42 -0
- package/packages/vue/dist/PlinthCallout.vue.d.ts +31 -0
- package/packages/vue/dist/PlinthCodeBlock.vue.d.ts +49 -0
- package/packages/vue/dist/PlinthConfirmDialog.vue.d.ts +51 -0
- package/packages/vue/dist/PlinthDataTable.vue.d.ts +21 -0
- package/packages/vue/dist/PlinthDataTableCell.vue.d.ts +29 -0
- package/packages/vue/dist/PlinthDataTableColumn.vue.d.ts +26 -0
- package/packages/vue/dist/PlinthDataTableEmpty.vue.d.ts +19 -0
- package/packages/vue/dist/PlinthDataTableRow.vue.d.ts +19 -0
- package/packages/vue/dist/PlinthDataTableSort.vue.d.ts +13 -0
- package/packages/vue/dist/PlinthDialog.vue.d.ts +45 -0
- package/packages/vue/dist/PlinthDrawer.vue.d.ts +48 -0
- package/packages/vue/dist/PlinthHeader.vue.d.ts +19 -0
- package/packages/vue/dist/PlinthIcon.vue.d.ts +23 -0
- package/packages/vue/dist/PlinthIconButton.vue.d.ts +37 -0
- package/packages/vue/dist/PlinthListCard.vue.d.ts +26 -0
- package/packages/vue/dist/PlinthListRow.vue.d.ts +38 -0
- package/packages/vue/dist/PlinthMenuSheet.vue.d.ts +48 -0
- package/packages/vue/dist/PlinthPill.vue.d.ts +28 -0
- package/packages/vue/dist/PlinthPillRow.vue.d.ts +22 -0
- package/packages/vue/dist/PlinthSectionMenu.vue.d.ts +22 -0
- package/packages/vue/dist/PlinthSectionMenuItem.vue.d.ts +28 -0
- package/packages/vue/dist/PlinthSheet.vue.d.ts +45 -0
- package/packages/vue/dist/avatar.d.ts +12 -0
- package/packages/vue/dist/button.d.ts +5 -0
- package/packages/vue/dist/callout.d.ts +19 -0
- package/packages/vue/dist/code-block.d.ts +16 -0
- package/packages/vue/dist/confirm-dialog.d.ts +23 -0
- package/packages/vue/dist/data-table.d.ts +15 -0
- package/packages/vue/dist/dialog.d.ts +10 -0
- package/packages/vue/dist/drawer.d.ts +20 -0
- package/packages/vue/dist/heading.d.ts +5 -0
- package/packages/vue/dist/icon.d.ts +5 -0
- package/packages/vue/dist/index.d.ts +44 -0
- package/packages/vue/dist/index.js +1439 -0
- package/packages/vue/dist/list-row.d.ts +5 -0
- package/packages/vue/dist/sheet.d.ts +12 -0
- package/packages/vue/dist/size.d.ts +13 -0
- package/packages/vue/dist/slots.d.ts +3 -0
- package/packages/vue/dist/swipe.d.ts +12 -0
- package/packages/vue/dist/tones.d.ts +5 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Button: the main action control.
|
|
3
|
+
*
|
|
4
|
+
* <button type="button" class="plinth-button" data-variant="primary" data-size="md">
|
|
5
|
+
* <span class="plinth-icon" data-size="md" aria-hidden="true"><svg>…</svg></span>
|
|
6
|
+
* <span class="plinth-button-label">Save</span>
|
|
7
|
+
* <span class="plinth-icon" data-size="md" aria-hidden="true"><svg>…</svg></span>
|
|
8
|
+
* </button>
|
|
9
|
+
*
|
|
10
|
+
* With an href it is <a class="plinth-button" href="…"> instead; the icons are optional.
|
|
11
|
+
*
|
|
12
|
+
* data-mirror on an icon flips it in right-to-left text, for arrows (mirror-icon and
|
|
13
|
+
* mirror-trailing in Blade, Vue and React; mirror on the icon button).
|
|
14
|
+
*
|
|
15
|
+
* Variants (data-variant): primary (default, also when missing; inverted neutral unless a brand
|
|
16
|
+
* colours it), accent (the brand's colour, for marketing and brand moments), secondary, ghost, danger, and
|
|
17
|
+
* danger-ghost for a low-emphasis destructive action (Remove next to an item).
|
|
18
|
+
* Sizes (data-size): sm 28px, md 32px (default), lg 40px. On a touch screen every size keeps a
|
|
19
|
+
* 40px touch target through an invisible hit area. Icons inside are 16px on sm and 20px otherwise.
|
|
20
|
+
*
|
|
21
|
+
* States:
|
|
22
|
+
* - disabled: `disabled` on a <button>; on a link, no href, role="link" and aria-disabled="true".
|
|
23
|
+
* - busy: aria-busy="true" and aria-disabled="true", with
|
|
24
|
+
* <span class="plinth-button-spinner" aria-hidden="true"></span> in the leading icon's place.
|
|
25
|
+
* It keeps focus; the app ignores activation while busy.
|
|
26
|
+
* - hover only where the device can hover; the focus ring on :focus-visible.
|
|
27
|
+
*
|
|
28
|
+
* Icon button: a button with only an icon, square at the button's height.
|
|
29
|
+
*
|
|
30
|
+
* <button type="button" class="plinth-button plinth-icon-button" data-variant="ghost"
|
|
31
|
+
* data-size="md" aria-label="More actions">
|
|
32
|
+
* <span class="plinth-icon" data-size="md" aria-hidden="true"><svg>…</svg></span>
|
|
33
|
+
* </button>
|
|
34
|
+
*
|
|
35
|
+
* With an href it is a link instead, with the same disabled state as the button's link:
|
|
36
|
+
*
|
|
37
|
+
* <a class="plinth-button plinth-icon-button" href="…" data-variant="secondary"
|
|
38
|
+
* data-size="md" aria-label="Next page">
|
|
39
|
+
* <span class="plinth-icon" data-size="md" data-mirror aria-hidden="true"><svg>…</svg></span>
|
|
40
|
+
* </a>
|
|
41
|
+
*
|
|
42
|
+
* aria-label is required: it is the only name the button has. A toggle has aria-pressed
|
|
43
|
+
* ("true" or "false"), and pressed shows the selection tint (accent-subtle, accent-text) inside
|
|
44
|
+
* a 2px accent edge (border-width.thick), so colour is not its only cue; it still answers hover
|
|
45
|
+
* and press with a step on the tint. In forced colours it takes the Highlight system colour. A
|
|
46
|
+
* link is never a toggle: aria-pressed is never printed on one.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
@layer plinth {
|
|
50
|
+
.plinth-button {
|
|
51
|
+
--plinth-button-surface: var(--plinth-color-primary);
|
|
52
|
+
--plinth-button-surface-hover: var(--plinth-color-primary-hover);
|
|
53
|
+
--plinth-button-surface-active: var(--plinth-color-primary-active);
|
|
54
|
+
--plinth-button-text: var(--plinth-color-on-primary);
|
|
55
|
+
--plinth-button-edge: transparent;
|
|
56
|
+
--plinth-button-inner-edge: inset 0 0 0 1px var(--plinth-color-primary-edge);
|
|
57
|
+
--plinth-button-height: var(--plinth-control-md);
|
|
58
|
+
--plinth-button-padding: var(--plinth-space-4);
|
|
59
|
+
--plinth-button-icon-size: var(--plinth-size-icon-md);
|
|
60
|
+
|
|
61
|
+
position: relative;
|
|
62
|
+
display: inline-flex;
|
|
63
|
+
gap: var(--plinth-space-2);
|
|
64
|
+
align-items: center;
|
|
65
|
+
justify-content: center;
|
|
66
|
+
max-inline-size: 100%;
|
|
67
|
+
min-block-size: var(--plinth-button-height);
|
|
68
|
+
padding-block: 0;
|
|
69
|
+
padding-inline: var(--plinth-button-padding);
|
|
70
|
+
font-family: var(--plinth-font-family-body);
|
|
71
|
+
font-size: var(--plinth-font-size-md);
|
|
72
|
+
font-weight: var(--plinth-font-weight-medium);
|
|
73
|
+
line-height: var(--plinth-font-leading-tight);
|
|
74
|
+
vertical-align: middle;
|
|
75
|
+
color: var(--plinth-button-text);
|
|
76
|
+
white-space: nowrap;
|
|
77
|
+
text-decoration: none;
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
user-select: none;
|
|
80
|
+
background-color: var(--plinth-button-surface);
|
|
81
|
+
border: var(--plinth-border-width-thin) solid var(--plinth-button-edge);
|
|
82
|
+
border-radius: var(--plinth-radius-control);
|
|
83
|
+
box-shadow: var(--plinth-button-inner-edge);
|
|
84
|
+
transition:
|
|
85
|
+
background-color var(--plinth-duration-fast) var(--plinth-easing-standard),
|
|
86
|
+
border-color var(--plinth-duration-fast) var(--plinth-easing-standard),
|
|
87
|
+
box-shadow var(--plinth-duration-fast) var(--plinth-easing-standard);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* The brand's colour, for marketing and brand moments (Upgrade plan): at most one per screen. */
|
|
91
|
+
.plinth-button[data-variant='accent'] {
|
|
92
|
+
--plinth-button-surface: var(--plinth-color-accent);
|
|
93
|
+
--plinth-button-surface-hover: var(--plinth-color-accent-hover);
|
|
94
|
+
--plinth-button-surface-active: var(--plinth-color-accent-active);
|
|
95
|
+
--plinth-button-text: var(--plinth-color-on-accent);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.plinth-button[data-variant='secondary'] {
|
|
99
|
+
--plinth-button-inner-edge: none;
|
|
100
|
+
--plinth-button-surface: var(--plinth-color-surface-raised);
|
|
101
|
+
--plinth-button-surface-hover: var(--plinth-color-surface-hover);
|
|
102
|
+
--plinth-button-surface-active: var(--plinth-color-surface-sunken);
|
|
103
|
+
--plinth-button-text: var(--plinth-color-text);
|
|
104
|
+
--plinth-button-edge: var(--plinth-color-border-strong);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.plinth-button[data-variant='ghost'] {
|
|
108
|
+
--plinth-button-inner-edge: none;
|
|
109
|
+
--plinth-button-surface: transparent;
|
|
110
|
+
--plinth-button-surface-hover: var(--plinth-color-surface-hover);
|
|
111
|
+
--plinth-button-surface-active: var(--plinth-color-surface-sunken);
|
|
112
|
+
--plinth-button-text: var(--plinth-color-text);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.plinth-button[data-variant='danger'] {
|
|
116
|
+
--plinth-button-inner-edge: none;
|
|
117
|
+
--plinth-button-surface: var(--plinth-color-danger-solid);
|
|
118
|
+
--plinth-button-surface-hover: var(--plinth-color-danger-solid-hover);
|
|
119
|
+
--plinth-button-surface-active: var(--plinth-color-danger-solid-active);
|
|
120
|
+
--plinth-button-text: var(--plinth-color-on-danger);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.plinth-button[data-variant='danger-ghost'] {
|
|
124
|
+
--plinth-button-inner-edge: none;
|
|
125
|
+
--plinth-button-surface: transparent;
|
|
126
|
+
--plinth-button-surface-hover: var(--plinth-color-danger-surface);
|
|
127
|
+
--plinth-button-surface-active: var(--plinth-color-danger-surface);
|
|
128
|
+
--plinth-button-text: var(--plinth-color-danger-text);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.plinth-button[data-size='sm'] {
|
|
132
|
+
--plinth-button-height: var(--plinth-control-sm);
|
|
133
|
+
--plinth-button-padding: var(--plinth-space-3);
|
|
134
|
+
--plinth-button-icon-size: var(--plinth-size-icon-sm);
|
|
135
|
+
|
|
136
|
+
font-size: var(--plinth-font-size-sm);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.plinth-button[data-size='lg'] {
|
|
140
|
+
--plinth-button-height: var(--plinth-control-lg);
|
|
141
|
+
--plinth-button-padding: var(--plinth-space-5);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/*
|
|
145
|
+
* On a touch screen, every button keeps a 40px touch target through an invisible hit area,
|
|
146
|
+
* centred on it, without changing its look (ADR 3: controls look small, touch stays at 40px).
|
|
147
|
+
*/
|
|
148
|
+
@media (pointer: coarse) {
|
|
149
|
+
.plinth-button::before {
|
|
150
|
+
position: absolute;
|
|
151
|
+
inset-block-start: 50%;
|
|
152
|
+
inset-inline: 0;
|
|
153
|
+
block-size: max(100%, var(--plinth-touch-target));
|
|
154
|
+
content: '';
|
|
155
|
+
translate: 0 -50%;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* An icon button is narrower than 40px, so its hit area grows sideways too. */
|
|
159
|
+
.plinth-icon-button::before {
|
|
160
|
+
inset-inline: min(0%, 50% - var(--plinth-touch-target) / 2);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@media (hover: hover) {
|
|
165
|
+
.plinth-button:hover {
|
|
166
|
+
background-color: var(--plinth-button-surface-hover);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.plinth-button:active {
|
|
171
|
+
background-color: var(--plinth-button-surface-active);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.plinth-button:disabled,
|
|
175
|
+
.plinth-button[aria-disabled='true'] {
|
|
176
|
+
cursor: not-allowed;
|
|
177
|
+
background-color: var(--plinth-button-surface);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.plinth-button:disabled,
|
|
181
|
+
.plinth-button[aria-disabled='true']:not([aria-busy='true']) {
|
|
182
|
+
opacity: var(--plinth-opacity-disabled);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.plinth-button[aria-busy='true'] {
|
|
186
|
+
cursor: progress;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.plinth-button:focus-visible {
|
|
190
|
+
outline: var(--plinth-focus-ring-width) solid var(--plinth-color-focus-ring);
|
|
191
|
+
outline-offset: var(--plinth-focus-ring-offset-filled);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.plinth-button:is(
|
|
195
|
+
[data-variant='secondary'],
|
|
196
|
+
[data-variant='ghost'],
|
|
197
|
+
[data-variant='danger-ghost']
|
|
198
|
+
):focus-visible {
|
|
199
|
+
outline-offset: var(--plinth-focus-ring-offset);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.plinth-icon-button {
|
|
203
|
+
flex: none;
|
|
204
|
+
inline-size: var(--plinth-button-height);
|
|
205
|
+
padding-inline: 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* The border and an inset ring make the 2px edge, so pressed doesn't move the icon. */
|
|
209
|
+
.plinth-icon-button[aria-pressed='true'] {
|
|
210
|
+
--plinth-button-surface: var(--plinth-color-accent-subtle);
|
|
211
|
+
--plinth-button-surface-hover: var(--plinth-color-accent-subtle-hover);
|
|
212
|
+
--plinth-button-surface-active: var(--plinth-color-accent-subtle-active);
|
|
213
|
+
--plinth-button-text: var(--plinth-color-accent-text);
|
|
214
|
+
--plinth-button-edge: var(--plinth-color-accent);
|
|
215
|
+
--plinth-button-inner-edge: inset 0 0 0
|
|
216
|
+
calc(var(--plinth-border-width-thick) - var(--plinth-border-width-thin))
|
|
217
|
+
var(--plinth-color-accent);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* A gap between the ring and the pressed accent edge, so focus and pressed read apart. */
|
|
221
|
+
.plinth-icon-button[aria-pressed='true']:focus-visible {
|
|
222
|
+
outline-offset: var(--plinth-focus-ring-offset-filled);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.plinth-button-label {
|
|
226
|
+
overflow: hidden;
|
|
227
|
+
text-overflow: ellipsis;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* The same size as the icon it replaces, so the button keeps its width when it goes busy. */
|
|
231
|
+
.plinth-button-spinner {
|
|
232
|
+
flex: none;
|
|
233
|
+
inline-size: var(--plinth-button-icon-size);
|
|
234
|
+
block-size: var(--plinth-button-icon-size);
|
|
235
|
+
border: var(--plinth-border-width-thick) solid currentcolor;
|
|
236
|
+
border-inline-end-color: transparent;
|
|
237
|
+
border-radius: 50%;
|
|
238
|
+
animation: plinth-button-spin calc(var(--plinth-duration-slow) * 3) linear infinite;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@keyframes plinth-button-spin {
|
|
242
|
+
to {
|
|
243
|
+
transform: rotate(1turn);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@media (forced-colors: active) {
|
|
248
|
+
.plinth-button {
|
|
249
|
+
border-color: ButtonText;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.plinth-button:disabled,
|
|
253
|
+
.plinth-button[aria-disabled='true']:not([aria-busy='true']) {
|
|
254
|
+
color: GrayText;
|
|
255
|
+
border-color: GrayText;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* The pressed tint is dropped in forced colours, so pressed takes the selection colours,
|
|
259
|
+
unless it is disabled, which keeps GrayText. */
|
|
260
|
+
.plinth-icon-button[aria-pressed='true']:not(
|
|
261
|
+
:disabled,
|
|
262
|
+
[aria-disabled='true']:not([aria-busy='true'])
|
|
263
|
+
) {
|
|
264
|
+
color: HighlightText;
|
|
265
|
+
background-color: Highlight;
|
|
266
|
+
border-color: Highlight;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.plinth-button-spinner {
|
|
270
|
+
forced-color-adjust: none;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Callout: a note inside a page, with a tone, an icon, an optional title and actions.
|
|
3
|
+
*
|
|
4
|
+
* <div class="plinth-callout" data-tone="warning" role="note">
|
|
5
|
+
* <span class="plinth-icon plinth-callout-icon" data-size="md" aria-hidden="true">
|
|
6
|
+
* <svg viewBox="0 0 24 24">…</svg>
|
|
7
|
+
* </span>
|
|
8
|
+
* <div class="plinth-callout-body">
|
|
9
|
+
* <p class="plinth-callout-title">Invoices are sent at 9:00</p>
|
|
10
|
+
* <div class="plinth-callout-text">Drafts saved after that go out the next morning.</div>
|
|
11
|
+
* <div class="plinth-callout-actions">…buttons or links…</div>
|
|
12
|
+
* </div>
|
|
13
|
+
* </div>
|
|
14
|
+
*
|
|
15
|
+
* Tones (data-tone): neutral (default, also when the attribute is missing), info, success,
|
|
16
|
+
* warning, danger. Each tints the surface, the hairline border and the icon, and has its own icon
|
|
17
|
+
* shape; the title or the text still says what kind of note it is, so the tone is never the only
|
|
18
|
+
* signal. The tints are the component tokens --plinth-callout-<tone>-surface and -border: faint
|
|
19
|
+
* and translucent, quieter than the status surfaces a badge uses.
|
|
20
|
+
*
|
|
21
|
+
* role: note (default) for a note that is part of the page; status for a message the app adds
|
|
22
|
+
* after something happens (announced politely); alert for an urgent one (announced at once). A
|
|
23
|
+
* live region inserted with its content is often not announced, so for a status the app keeps an
|
|
24
|
+
* empty container with role="status" in the page and puts the callout in it.
|
|
25
|
+
*
|
|
26
|
+
* The text may hold paragraphs, links (underlined, in the text's colour) and inline code.
|
|
27
|
+
*
|
|
28
|
+
* The icon is decorative (aria-hidden). The tone's icon comes with the component; a project puts
|
|
29
|
+
* its own SVG in its place. Title, text and actions are each printed only when they have content.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
@layer plinth {
|
|
33
|
+
.plinth-callout {
|
|
34
|
+
--plinth-callout-surface: var(--plinth-callout-neutral-surface);
|
|
35
|
+
--plinth-callout-border: var(--plinth-callout-neutral-border);
|
|
36
|
+
--plinth-callout-icon-color: var(--plinth-color-text-muted);
|
|
37
|
+
|
|
38
|
+
display: flex;
|
|
39
|
+
gap: var(--plinth-space-3);
|
|
40
|
+
align-items: flex-start;
|
|
41
|
+
min-inline-size: 0;
|
|
42
|
+
padding-block: var(--plinth-space-3);
|
|
43
|
+
padding-inline: var(--plinth-space-4);
|
|
44
|
+
font-family: var(--plinth-font-family-body);
|
|
45
|
+
font-size: var(--plinth-font-size-md);
|
|
46
|
+
line-height: var(--plinth-font-leading-normal);
|
|
47
|
+
color: var(--plinth-color-text);
|
|
48
|
+
overflow-wrap: anywhere;
|
|
49
|
+
background-color: var(--plinth-callout-surface);
|
|
50
|
+
border: 1px solid var(--plinth-callout-border);
|
|
51
|
+
border-radius: var(--plinth-radius-container);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.plinth-callout[data-tone='info'] {
|
|
55
|
+
--plinth-callout-surface: var(--plinth-callout-info-surface);
|
|
56
|
+
--plinth-callout-border: var(--plinth-callout-info-border);
|
|
57
|
+
--plinth-callout-icon-color: var(--plinth-color-info-text);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.plinth-callout[data-tone='success'] {
|
|
61
|
+
--plinth-callout-surface: var(--plinth-callout-success-surface);
|
|
62
|
+
--plinth-callout-border: var(--plinth-callout-success-border);
|
|
63
|
+
--plinth-callout-icon-color: var(--plinth-color-success-text);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.plinth-callout[data-tone='warning'] {
|
|
67
|
+
--plinth-callout-surface: var(--plinth-callout-warning-surface);
|
|
68
|
+
--plinth-callout-border: var(--plinth-callout-warning-border);
|
|
69
|
+
--plinth-callout-icon-color: var(--plinth-color-warning-text);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.plinth-callout[data-tone='danger'] {
|
|
73
|
+
--plinth-callout-surface: var(--plinth-callout-danger-surface);
|
|
74
|
+
--plinth-callout-border: var(--plinth-callout-danger-border);
|
|
75
|
+
--plinth-callout-icon-color: var(--plinth-color-danger-text);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Centred on the first line of text, however tall the line is. */
|
|
79
|
+
.plinth-callout-icon {
|
|
80
|
+
margin-block: calc((1lh - var(--plinth-size-icon-md)) / 2);
|
|
81
|
+
color: var(--plinth-callout-icon-color);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.plinth-callout-body {
|
|
85
|
+
display: flex;
|
|
86
|
+
flex: 1;
|
|
87
|
+
flex-direction: column;
|
|
88
|
+
gap: var(--plinth-space-1);
|
|
89
|
+
min-inline-size: 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.plinth-callout-title {
|
|
93
|
+
margin: 0;
|
|
94
|
+
font-weight: var(--plinth-font-weight-semibold);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.plinth-callout-text > * {
|
|
98
|
+
margin-block: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.plinth-callout-text > * + * {
|
|
102
|
+
margin-block-start: var(--plinth-space-2);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.plinth-callout-text a {
|
|
106
|
+
color: inherit;
|
|
107
|
+
text-decoration-line: underline;
|
|
108
|
+
text-decoration-color: var(--plinth-color-text-muted);
|
|
109
|
+
text-underline-offset: 0.2em;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@media (hover: hover) {
|
|
113
|
+
.plinth-callout-text a:hover {
|
|
114
|
+
text-decoration-color: currentcolor;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.plinth-callout-text a:focus-visible {
|
|
119
|
+
outline: var(--plinth-focus-ring-width) solid var(--plinth-color-focus-ring);
|
|
120
|
+
outline-offset: var(--plinth-focus-ring-offset);
|
|
121
|
+
border-radius: var(--plinth-radius-control);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.plinth-callout-text code {
|
|
125
|
+
font-family: var(--plinth-font-family-mono);
|
|
126
|
+
font-size: var(--plinth-font-size-sm);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.plinth-callout-actions {
|
|
130
|
+
display: flex;
|
|
131
|
+
flex-wrap: wrap;
|
|
132
|
+
gap: var(--plinth-space-2);
|
|
133
|
+
align-items: center;
|
|
134
|
+
margin-block-start: var(--plinth-space-2);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Small buttons grow a 40px hit area on a touch screen; wrapped rows keep theirs apart. */
|
|
138
|
+
@media (pointer: coarse) {
|
|
139
|
+
.plinth-callout-actions {
|
|
140
|
+
row-gap: var(--plinth-space-3);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Code block: a block of code with an optional file name or label, a copy button and optional
|
|
3
|
+
* language tabs.
|
|
4
|
+
*
|
|
5
|
+
* <div class="plinth-code-block">
|
|
6
|
+
* <div class="plinth-code-block-header">
|
|
7
|
+
* <span class="plinth-code-block-label">resources/css/brand.css</span>
|
|
8
|
+
* <button type="button" class="plinth-button plinth-code-block-copy" data-variant="ghost"
|
|
9
|
+
* data-size="sm" hidden>
|
|
10
|
+
* <span class="plinth-button-label">Copy</span>
|
|
11
|
+
* </button>
|
|
12
|
+
* <span class="plinth-code-block-status" role="status"></span>
|
|
13
|
+
* </div>
|
|
14
|
+
* <pre class="plinth-code-block-code" dir="ltr" tabindex="0"><code>…</code></pre>
|
|
15
|
+
* </div>
|
|
16
|
+
*
|
|
17
|
+
* With language tabs, the header holds a radio group after the label, and there is one <pre> per
|
|
18
|
+
* tab, in the same order:
|
|
19
|
+
*
|
|
20
|
+
* <div class="plinth-code-block-tabs" role="radiogroup" aria-label="Language">
|
|
21
|
+
* <label class="plinth-code-block-tab">
|
|
22
|
+
* <input type="radio" class="plinth-code-block-tab-input" name="install-language" checked>
|
|
23
|
+
* <span class="plinth-code-block-tab-label">Blade</span>
|
|
24
|
+
* </label>
|
|
25
|
+
* <label class="plinth-code-block-tab">…Vue…</label>
|
|
26
|
+
* </div>
|
|
27
|
+
* …
|
|
28
|
+
* <pre class="plinth-code-block-code" dir="ltr" tabindex="0"><code>…Blade…</code></pre>
|
|
29
|
+
* <pre class="plinth-code-block-code" dir="ltr" tabindex="0"><code>…Vue…</code></pre>
|
|
30
|
+
*
|
|
31
|
+
* The root is the <div>, and takes the app's id. The label is optional, and is text or a little
|
|
32
|
+
* markup (a badge). The tabs are native radio buttons (ADR 2): the browser moves between them with
|
|
33
|
+
* the arrow keys and remembers the checked one, and CSS shows the <pre> in the checked tab's
|
|
34
|
+
* place, with no script. Their name is the root's id with -language (one is generated when the
|
|
35
|
+
* root has no id), and the group's name is tabs-label in Blade, Vue and React ("Language" by
|
|
36
|
+
* default). In plain HTML, give each block on a page its own name, or their tabs become one group.
|
|
37
|
+
* Up to six tabs (the layers drop the rest); the first is checked unless the app picks another
|
|
38
|
+
* (selected), and after that the browser keeps the reader's choice. Inside a <form> the radios
|
|
39
|
+
* are part of it: they are sent with it (name=on), and a reset checks the starting tab again.
|
|
40
|
+
*
|
|
41
|
+
* The code is text, or the markup a highlighter prints (Phiki, Shiki: the spans inside its
|
|
42
|
+
* <code>). Plinth styles the block, not the tokens: their colours are the highlighter's. The
|
|
43
|
+
* <pre> keeps the code's lines and scrolls sideways inside its own box, so it takes tabindex="0"
|
|
44
|
+
* (a scrolling region must be reachable by keyboard), and dir="ltr", as code reads left to right
|
|
45
|
+
* on any page.
|
|
46
|
+
*
|
|
47
|
+
* Copy: the button (button.css) is printed hidden, and the Blade (Alpine), Vue and React layers
|
|
48
|
+
* show it when the clipboard is there. It copies the text of the <pre> that shows, says Copied
|
|
49
|
+
* (copied-label) for two seconds and puts the same word in the status, a polite live region,
|
|
50
|
+
* hidden from sight. The plain HTML works without it, and the header keeps its place for the
|
|
51
|
+
* button either way. copy: false in Blade, Vue and React leaves
|
|
52
|
+
* the button and the status out.
|
|
53
|
+
*
|
|
54
|
+
* States: the checked tab (input:checked) is a raised surface with a strong edge; hover only
|
|
55
|
+
* where the device can hover; the focus ring on :focus-visible, on the tab's input (it covers the
|
|
56
|
+
* tab) and inset on the <pre>. On a touch screen each tab keeps a 40px touch target, as the
|
|
57
|
+
* button does. The header hides itself when it has nothing to show.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
@layer plinth {
|
|
61
|
+
.plinth-code-block {
|
|
62
|
+
box-sizing: border-box;
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
min-inline-size: 0;
|
|
66
|
+
max-inline-size: 100%;
|
|
67
|
+
color: var(--plinth-color-text);
|
|
68
|
+
background-color: var(--plinth-color-surface-sunken);
|
|
69
|
+
border: var(--plinth-border-width-thin) solid var(--plinth-color-border);
|
|
70
|
+
border-radius: var(--plinth-radius-container);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.plinth-code-block-header {
|
|
74
|
+
box-sizing: border-box;
|
|
75
|
+
display: flex;
|
|
76
|
+
flex-wrap: wrap;
|
|
77
|
+
gap: var(--plinth-space-2);
|
|
78
|
+
align-items: center;
|
|
79
|
+
min-block-size: var(--plinth-touch-target);
|
|
80
|
+
padding-block: calc((var(--plinth-touch-target) - var(--plinth-control-sm)) / 2);
|
|
81
|
+
padding-inline: var(--plinth-space-4)
|
|
82
|
+
calc((var(--plinth-touch-target) - var(--plinth-control-sm)) / 2);
|
|
83
|
+
border-block-end: var(--plinth-border-width-thin) solid var(--plinth-color-divider);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Tabs first, with no label: the header's start matches its end. */
|
|
87
|
+
.plinth-code-block-header:not(:has(.plinth-code-block-label)) {
|
|
88
|
+
padding-inline-start: calc((var(--plinth-touch-target) - var(--plinth-control-sm)) / 2);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
* Nothing to show: no label, no tabs and no copy button (copy off). A hidden copy button keeps
|
|
93
|
+
* the header, so the code doesn't move down when the layer shows it.
|
|
94
|
+
*/
|
|
95
|
+
.plinth-code-block-header:not(
|
|
96
|
+
:has(.plinth-code-block-label, .plinth-code-block-tabs, .plinth-code-block-copy)
|
|
97
|
+
) {
|
|
98
|
+
display: none;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.plinth-code-block-label {
|
|
102
|
+
display: inline-flex;
|
|
103
|
+
flex: 0 1 auto;
|
|
104
|
+
gap: var(--plinth-space-2);
|
|
105
|
+
align-items: center;
|
|
106
|
+
min-inline-size: 0;
|
|
107
|
+
overflow: hidden;
|
|
108
|
+
text-overflow: ellipsis;
|
|
109
|
+
font-family: var(--plinth-font-family-mono);
|
|
110
|
+
font-size: var(--plinth-font-size-xs);
|
|
111
|
+
line-height: var(--plinth-font-leading-tight);
|
|
112
|
+
color: var(--plinth-color-text-muted);
|
|
113
|
+
white-space: nowrap;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.plinth-code-block-label:has(+ .plinth-code-block-tabs) {
|
|
117
|
+
margin-inline-end: var(--plinth-space-2);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* The tabs follow the label; the copy button sits at the end. */
|
|
121
|
+
.plinth-code-block-tabs {
|
|
122
|
+
display: flex;
|
|
123
|
+
flex: 0 1 auto;
|
|
124
|
+
flex-wrap: wrap;
|
|
125
|
+
gap: var(--plinth-space-1);
|
|
126
|
+
align-items: center;
|
|
127
|
+
min-inline-size: 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.plinth-code-block-tab {
|
|
131
|
+
position: relative;
|
|
132
|
+
box-sizing: border-box;
|
|
133
|
+
display: inline-flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
justify-content: center;
|
|
136
|
+
min-block-size: var(--plinth-control-sm);
|
|
137
|
+
padding-block: 0;
|
|
138
|
+
padding-inline: var(--plinth-space-3);
|
|
139
|
+
font-family: var(--plinth-font-family-body);
|
|
140
|
+
font-size: var(--plinth-font-size-sm);
|
|
141
|
+
font-weight: var(--plinth-font-weight-medium);
|
|
142
|
+
line-height: var(--plinth-font-leading-tight);
|
|
143
|
+
color: var(--plinth-color-text-muted);
|
|
144
|
+
white-space: nowrap;
|
|
145
|
+
cursor: pointer;
|
|
146
|
+
user-select: none;
|
|
147
|
+
background-color: transparent;
|
|
148
|
+
border: var(--plinth-border-width-thin) solid transparent;
|
|
149
|
+
border-radius: var(--plinth-radius-control);
|
|
150
|
+
transition:
|
|
151
|
+
background-color var(--plinth-duration-fast) var(--plinth-easing-standard),
|
|
152
|
+
border-color var(--plinth-duration-fast) var(--plinth-easing-standard),
|
|
153
|
+
color var(--plinth-duration-fast) var(--plinth-easing-standard);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* The radio covers its tab, so the tab is what is focused, clicked and ringed. */
|
|
157
|
+
.plinth-code-block-tab-input {
|
|
158
|
+
position: absolute;
|
|
159
|
+
inset: calc(-1 * var(--plinth-border-width-thin));
|
|
160
|
+
margin: 0;
|
|
161
|
+
appearance: none;
|
|
162
|
+
cursor: pointer;
|
|
163
|
+
background: none;
|
|
164
|
+
border: 0;
|
|
165
|
+
border-radius: var(--plinth-radius-control);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.plinth-code-block-tab-input:focus-visible {
|
|
169
|
+
outline: var(--plinth-focus-ring-width) solid var(--plinth-color-focus-ring);
|
|
170
|
+
outline-offset: var(--plinth-focus-ring-offset);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.plinth-code-block-tab:has(> .plinth-code-block-tab-input:checked) {
|
|
174
|
+
color: var(--plinth-color-text);
|
|
175
|
+
background-color: var(--plinth-color-surface-raised);
|
|
176
|
+
border-color: var(--plinth-color-border-strong);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@media (hover: hover) {
|
|
180
|
+
.plinth-code-block-tab:not(:has(> .plinth-code-block-tab-input:checked)):hover {
|
|
181
|
+
color: var(--plinth-color-text);
|
|
182
|
+
background-color: var(--plinth-color-surface-hover);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.plinth-code-block-tab:not(:has(> .plinth-code-block-tab-input:checked)):active {
|
|
187
|
+
background-color: var(--plinth-color-surface-sunken);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* A 40px touch target through an invisible hit area, as on the button (ADR 3). */
|
|
191
|
+
@media (pointer: coarse) {
|
|
192
|
+
.plinth-code-block-tab::before {
|
|
193
|
+
position: absolute;
|
|
194
|
+
inset-block-start: 50%;
|
|
195
|
+
inset-inline: min(0%, 50% - var(--plinth-touch-target) / 2);
|
|
196
|
+
block-size: max(100%, var(--plinth-touch-target));
|
|
197
|
+
content: '';
|
|
198
|
+
translate: 0 -50%;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.plinth-code-block-copy {
|
|
203
|
+
margin-inline-start: auto;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* The button's own display would beat the hidden attribute. */
|
|
207
|
+
.plinth-code-block-copy[hidden] {
|
|
208
|
+
display: none;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* Read out, not shown. */
|
|
212
|
+
.plinth-code-block-status {
|
|
213
|
+
position: absolute;
|
|
214
|
+
inline-size: 1px;
|
|
215
|
+
block-size: 1px;
|
|
216
|
+
padding: 0;
|
|
217
|
+
margin: calc(-1 * var(--plinth-border-width-thin));
|
|
218
|
+
overflow: hidden;
|
|
219
|
+
white-space: nowrap;
|
|
220
|
+
border: 0;
|
|
221
|
+
clip-path: inset(50%);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.plinth-code-block-code {
|
|
225
|
+
box-sizing: border-box;
|
|
226
|
+
max-inline-size: 100%;
|
|
227
|
+
padding: var(--plinth-space-4);
|
|
228
|
+
margin: 0;
|
|
229
|
+
overflow-x: auto;
|
|
230
|
+
overscroll-behavior-inline: contain;
|
|
231
|
+
font-family: var(--plinth-font-family-mono);
|
|
232
|
+
font-size: var(--plinth-font-size-sm);
|
|
233
|
+
line-height: var(--plinth-font-leading-normal);
|
|
234
|
+
color: var(--plinth-color-text);
|
|
235
|
+
tab-size: 2;
|
|
236
|
+
white-space: pre;
|
|
237
|
+
border-radius: var(--plinth-radius-container);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.plinth-code-block-code:focus-visible {
|
|
241
|
+
outline: var(--plinth-focus-ring-width) solid var(--plinth-color-focus-ring);
|
|
242
|
+
outline-offset: var(--plinth-focus-ring-offset-inset);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.plinth-code-block-code > code {
|
|
246
|
+
font: inherit;
|
|
247
|
+
color: inherit;
|
|
248
|
+
background: none;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/*
|
|
252
|
+
* With tabs, only the checked tab's <pre> shows: the nth tab shows the nth <pre>. Nothing
|
|
253
|
+
* checked (a reset form) shows the first.
|
|
254
|
+
*/
|
|
255
|
+
.plinth-code-block:has(.plinth-code-block-tabs) > .plinth-code-block-code {
|
|
256
|
+
display: none;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.plinth-code-block:not(:has(.plinth-code-block-tab-input:checked))
|
|
260
|
+
> .plinth-code-block-code:first-of-type,
|
|
261
|
+
.plinth-code-block:has(.plinth-code-block-tab:nth-child(1) > :checked)
|
|
262
|
+
> .plinth-code-block-code:nth-of-type(1),
|
|
263
|
+
.plinth-code-block:has(.plinth-code-block-tab:nth-child(2) > :checked)
|
|
264
|
+
> .plinth-code-block-code:nth-of-type(2),
|
|
265
|
+
.plinth-code-block:has(.plinth-code-block-tab:nth-child(3) > :checked)
|
|
266
|
+
> .plinth-code-block-code:nth-of-type(3),
|
|
267
|
+
.plinth-code-block:has(.plinth-code-block-tab:nth-child(4) > :checked)
|
|
268
|
+
> .plinth-code-block-code:nth-of-type(4),
|
|
269
|
+
.plinth-code-block:has(.plinth-code-block-tab:nth-child(5) > :checked)
|
|
270
|
+
> .plinth-code-block-code:nth-of-type(5),
|
|
271
|
+
.plinth-code-block:has(.plinth-code-block-tab:nth-child(6) > :checked)
|
|
272
|
+
> .plinth-code-block-code:nth-of-type(6) {
|
|
273
|
+
display: block;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
@media (forced-colors: active) {
|
|
277
|
+
.plinth-code-block-tab:has(> .plinth-code-block-tab-input:checked) {
|
|
278
|
+
color: HighlightText;
|
|
279
|
+
background-color: Highlight;
|
|
280
|
+
border-color: Highlight;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|