@jasonsdevspace/design-kit 0.1.0-next.1 → 0.1.0-next.3

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.
@@ -0,0 +1,688 @@
1
+ /*
2
+ * The kit's components, in the kit's components layer, so they sit over the base and under a
3
+ * page's own rules. Each is styled by its class and the markup the package README gives for it,
4
+ * which the React components draw and a page without React writes by hand. A selector beyond a
5
+ * single class sits inside one :where(), followed at most by a focus pseudo-class, so only the
6
+ * classes and the focus rule carry weight. The page chrome comes first, then the buttons, fields
7
+ * and callouts, then the explainer page and the panel, table and code block it holds.
8
+ *
9
+ * Load it after tokens.css, whose first statement declares the order of the kit's layers.
10
+ */
11
+
12
+ @layer dk.components {
13
+ /*
14
+ * Skip to content, out of sight until it takes focus, and then over the strip at the column's
15
+ * inset, where the strip's links start. It waits in its own place as the visually hidden
16
+ * class does, one pixel clipped to nothing, rather than moved above it, so one inside a
17
+ * positioned box of the page's own draws nothing, takes no click and covers nothing a screen
18
+ * reader's touch finds wherever the box starts, and shows at the top of that box once a
19
+ * keyboard reaches it.
20
+ */
21
+ .dk-skip {
22
+ position: absolute;
23
+ left: calc(max(0px, (100% - var(--dk-column)) / 2) + var(--dk-space-4));
24
+ top: var(--dk-space-4);
25
+ width: 1px;
26
+ height: 1px;
27
+ padding: 0;
28
+ overflow: hidden;
29
+ clip-path: inset(50%);
30
+ white-space: nowrap;
31
+ border-radius: var(--dk-radius);
32
+ background: var(--dk-accent);
33
+ color: var(--dk-on-accent);
34
+ z-index: 10;
35
+ }
36
+
37
+ :where(.dk-skip):focus-visible {
38
+ width: auto;
39
+ height: auto;
40
+ padding: var(--dk-space-2) var(--dk-space-4);
41
+ overflow: visible;
42
+ clip-path: none;
43
+ }
44
+
45
+ /*
46
+ * The strip and the footer run their rules the width of the page and line their content up
47
+ * with the column below, so the page reads as one column from the strip to the footer. An
48
+ * explainer and the header above it start their text at the same inset.
49
+ */
50
+ :where(.dk-strip, .dk-footer, .dk-explainer-header, .dk-explainer) {
51
+ padding-inline: calc(max(0px, (100% - var(--dk-column)) / 2) + var(--dk-space-4));
52
+ }
53
+
54
+ /*
55
+ * Whose demo this is, one row over its rule on a wide screen: the links together on the left,
56
+ * and the demo's own switches, when it has some, on the right.
57
+ */
58
+ .dk-strip {
59
+ display: flex;
60
+ flex-wrap: wrap;
61
+ align-items: center;
62
+ justify-content: space-between;
63
+ gap: 0 var(--dk-space-5);
64
+ border-bottom: 1px solid var(--dk-line);
65
+ font-size: var(--dk-text-small);
66
+ }
67
+
68
+ .dk-strip-links {
69
+ display: flex;
70
+ flex-wrap: wrap;
71
+ align-items: center;
72
+ gap: 0 var(--dk-space-5);
73
+ }
74
+
75
+ /* The whole row's height is the target, not the one line of small text. */
76
+ :where(.dk-strip-links a) {
77
+ display: inline-flex;
78
+ align-items: center;
79
+ min-height: var(--dk-strip);
80
+ }
81
+
82
+ /*
83
+ * The switches wrap where larger text leaves no room, and stand at least as tall as the links'
84
+ * row.
85
+ */
86
+ .dk-strip-tools {
87
+ display: flex;
88
+ flex-wrap: wrap;
89
+ align-items: center;
90
+ gap: var(--dk-space-3);
91
+ min-height: var(--dk-strip);
92
+ }
93
+
94
+ /* The exit after a long scroll, its rule the width of the page and its text in the column. */
95
+ .dk-footer {
96
+ margin-top: var(--dk-space-6);
97
+ padding-block: var(--dk-space-4);
98
+ border-top: 1px solid var(--dk-line);
99
+ color: var(--dk-muted);
100
+ font-size: var(--dk-text-small);
101
+ }
102
+
103
+ :where(.dk-footer p) {
104
+ margin: 0;
105
+ }
106
+
107
+ /*
108
+ * The chrome's links step back in the muted text, and come forward to the page's text when
109
+ * pointed at or focused, as the link to the current page always is. Every one keeps its
110
+ * underline, which in the footer's sentence is what tells a link from the text around it.
111
+ */
112
+ :where(.dk-strip-links a, .dk-footer a) {
113
+ color: var(--dk-muted);
114
+ }
115
+
116
+ :where(
117
+ .dk-strip-links a:hover,
118
+ .dk-strip-links a:focus-visible,
119
+ .dk-strip-links a[aria-current='page'],
120
+ .dk-footer a:hover,
121
+ .dk-footer a:focus-visible,
122
+ .dk-footer a[aria-current='page']
123
+ ) {
124
+ color: var(--dk-fg);
125
+ }
126
+
127
+ /*
128
+ * The link to the page a reader is on stands in the page's text, as above, and at the heading's
129
+ * weight, so it is told from the links around it by more than its color, which forced colors
130
+ * replace. It keeps its underline, so it still reads as a link.
131
+ */
132
+ :where(.dk-strip-links a[aria-current='page'], .dk-footer a[aria-current='page']) {
133
+ font-weight: var(--dk-weight-strong);
134
+ }
135
+
136
+ /*
137
+ * On a phone the links are smaller and closer, and wrap to rows of their own where they must,
138
+ * with the switches on a row below them.
139
+ */
140
+ @media (max-width: 48rem) {
141
+ .dk-strip {
142
+ font-size: var(--dk-text-caption);
143
+ }
144
+
145
+ .dk-strip-links {
146
+ gap: 0 var(--dk-space-4);
147
+ }
148
+
149
+ .dk-strip-tools {
150
+ flex-basis: 100%;
151
+ padding-block: 0 var(--dk-space-2);
152
+ }
153
+
154
+ /*
155
+ * The room of switches on their way stands as tall as one of the kit's controls at the
156
+ * target, which is taller than the strip's row, so their row keeps the height the switches
157
+ * give it. On a wide screen the strip's row is taller than a control, and holds alone.
158
+ */
159
+ .dk-strip-room {
160
+ min-height: var(--dk-target);
161
+ }
162
+ }
163
+
164
+ /*
165
+ * Every rule for a button, a field or a callout sits in one :where(), the resting look
166
+ * included. Each weighs nothing, so a state written after the resting look, such as pressed or
167
+ * off, wins over it by coming later, and a page's own rule outside a layer wins over them all.
168
+ * A button's states come in the order they win, at rest, pointed at, the accent, pressed and
169
+ * off, and a control's at rest, invalid and off, so off is last for each.
170
+ */
171
+
172
+ /*
173
+ * A button stands as tall as a field, so the two sit level in a row, and is never narrower
174
+ * than it is tall. It has no ground of its own, so it takes the ground of whatever it sits on,
175
+ * a callout or a panel included. A link that wears the class looks the same.
176
+ */
177
+ :where(.dk-button) {
178
+ display: inline-flex;
179
+ align-items: center;
180
+ justify-content: center;
181
+ gap: var(--dk-space-2);
182
+ min-height: var(--dk-field-height);
183
+ min-width: var(--dk-field-height);
184
+ padding: 0 var(--dk-space-3);
185
+ border: 1px solid var(--dk-control);
186
+ border-radius: var(--dk-radius);
187
+ background: transparent;
188
+ color: var(--dk-fg);
189
+ font-size: var(--dk-text-small);
190
+ line-height: var(--dk-leading-tight);
191
+ text-decoration: none;
192
+ cursor: pointer;
193
+ transition:
194
+ border-color var(--dk-duration-short),
195
+ background-color var(--dk-duration-short);
196
+ }
197
+
198
+ /*
199
+ * Pointed at, the edge turns to the accent. Only where a pointer can rest over a button, since
200
+ * on a phone the look would stay after a tap, and a toggle tapped off would look pressed.
201
+ */
202
+ @media (hover: hover) {
203
+ :where(.dk-button:hover) {
204
+ border-color: var(--dk-accent);
205
+ }
206
+ }
207
+
208
+ /*
209
+ * The one action a view leads with, filled in the accent. Its edge is already the accent, so
210
+ * a pointer over it underlines the words instead.
211
+ */
212
+ :where(.dk-button-accent) {
213
+ border-color: var(--dk-accent);
214
+ background: var(--dk-accent);
215
+ color: var(--dk-on-accent);
216
+ font-weight: var(--dk-weight-strong);
217
+ }
218
+
219
+ @media (hover: hover) {
220
+ :where(.dk-button-accent:hover) {
221
+ text-decoration: underline;
222
+ }
223
+ }
224
+
225
+ /*
226
+ * A toggle that is on, and a button whose panel is open, on the highlight with an edge twice
227
+ * as thick in the accent and its words in the page's text, the accent button's included. The
228
+ * highlight alone is close to the page's own ground, so the thicker edge is what tells the
229
+ * state at a glance.
230
+ */
231
+ :where(.dk-button[aria-pressed='true'], .dk-button[aria-expanded='true']) {
232
+ border-color: var(--dk-accent);
233
+ background: var(--dk-highlight);
234
+ box-shadow: inset 0 0 0 1px var(--dk-accent);
235
+ color: var(--dk-fg);
236
+ }
237
+
238
+ /*
239
+ * Off, drawn the same whether the button is disabled or marked aria-disabled, which keeps it
240
+ * in the tab order. The accent is dropped too, so the muted words never sit on the accent.
241
+ * Off has colors of its own rather than a fade, so its words keep a ratio that is measured.
242
+ */
243
+ :where(.dk-button:disabled, .dk-button[aria-disabled='true']) {
244
+ border-color: var(--dk-line);
245
+ background: transparent;
246
+ box-shadow: none;
247
+ color: var(--dk-muted);
248
+ font-weight: var(--dk-weight-normal);
249
+ text-decoration: none;
250
+ cursor: default;
251
+ }
252
+
253
+ /* An off toggle that is on keeps its thicker edge, in the line's color, so it still tells. */
254
+ :where(
255
+ .dk-button[aria-pressed='true']:disabled,
256
+ .dk-button[aria-pressed='true'][aria-disabled='true']
257
+ ) {
258
+ box-shadow: inset 0 0 0 1px var(--dk-line);
259
+ }
260
+
261
+ /*
262
+ * A field: its label, a hint when it has one, an error when it has one, and then the control.
263
+ * The error sits above the control, so a phone's keyboard or an open list never covers it, and
264
+ * the hint stays while the error shows, since it often says how to put the error right.
265
+ */
266
+ :where(.dk-field) {
267
+ display: grid;
268
+ gap: var(--dk-space-1);
269
+ }
270
+
271
+ :where(.dk-field > *) {
272
+ margin: 0;
273
+ }
274
+
275
+ :where(.dk-field-label) {
276
+ font-size: var(--dk-text-small);
277
+ font-weight: var(--dk-weight-medium);
278
+ }
279
+
280
+ :where(.dk-field-hint, .dk-field-error) {
281
+ font-size: var(--dk-text-caption);
282
+ }
283
+
284
+ :where(.dk-field-hint) {
285
+ color: var(--dk-muted);
286
+ }
287
+
288
+ :where(.dk-field-error) {
289
+ color: var(--dk-danger);
290
+ font-weight: var(--dk-weight-medium);
291
+ }
292
+
293
+ /*
294
+ * A control a visitor types into or picks from, on the page's own ground, so it reads as a
295
+ * well on a card or a panel. Its text is never under 16px, in px since it is the size
296
+ * at which a phone stops zooming the page when the field is tapped.
297
+ */
298
+ :where(.dk-input, .dk-select) {
299
+ min-width: 0;
300
+ max-width: 100%;
301
+ min-height: var(--dk-field-height);
302
+ padding: var(--dk-space-1) var(--dk-field-inline);
303
+ border: 1px solid var(--dk-control);
304
+ border-radius: var(--dk-radius);
305
+ background-color: var(--dk-bg);
306
+ color: var(--dk-fg);
307
+ font-size: max(var(--dk-text-body), 16px);
308
+ }
309
+
310
+ /*
311
+ * The browser's own list opens, but the closed select is drawn here, so its caret is in the
312
+ * muted text and sits as far from the right edge as the text does from the left. The padding
313
+ * keeps a long value short of the caret, cut off with an ellipsis where the browser draws one.
314
+ * A select that shows its options as a list, with multiple or a size, is left as the browser
315
+ * draws it.
316
+ */
317
+ :where(.dk-select:not([multiple], [size])) {
318
+ appearance: none;
319
+ padding-inline-end: calc(var(--dk-field-inline) * 2 + var(--dk-space-3));
320
+ text-overflow: ellipsis;
321
+ background-image:
322
+ linear-gradient(45deg, transparent 50%, var(--dk-muted) 50%),
323
+ linear-gradient(135deg, var(--dk-muted) 50%, transparent 50%);
324
+ background-repeat: no-repeat;
325
+ background-position:
326
+ right calc(var(--dk-field-inline) + var(--dk-space-3) / 2) center,
327
+ right var(--dk-field-inline) center;
328
+ background-size: calc(var(--dk-space-3) / 2) calc(var(--dk-space-3) / 2);
329
+ cursor: pointer;
330
+ }
331
+
332
+ /* A control with an error shown, its edge in the danger color, beside the error's words. */
333
+ :where(.dk-input[aria-invalid='true'], .dk-select[aria-invalid='true']) {
334
+ border-color: var(--dk-danger);
335
+ }
336
+
337
+ :where(.dk-input:disabled, .dk-select:disabled) {
338
+ border-color: var(--dk-line);
339
+ background-color: var(--dk-surface);
340
+ color: var(--dk-muted);
341
+ cursor: default;
342
+ }
343
+
344
+ /*
345
+ * A message set apart from the page, on the highlight for news, or on a ground of its own for
346
+ * something that went right or wrong. Its words stay in the page's own color in every tone,
347
+ * and say the tone themselves, so color is never the only sign of it. The edge draws nothing
348
+ * until forced colors drop the ground, and then it marks where the callout starts and ends.
349
+ */
350
+ :where(.dk-callout) {
351
+ display: grid;
352
+ gap: var(--dk-space-2);
353
+ padding: var(--dk-space-2) var(--dk-space-3);
354
+ border: 1px solid transparent;
355
+ border-radius: var(--dk-radius);
356
+ background: var(--dk-highlight);
357
+ color: var(--dk-fg);
358
+ font-size: var(--dk-text-small);
359
+ }
360
+
361
+ :where(.dk-callout-success) {
362
+ background: var(--dk-success-bg);
363
+ }
364
+
365
+ :where(.dk-callout-danger) {
366
+ background: var(--dk-danger-bg);
367
+ }
368
+
369
+ /*
370
+ * A callout whose message holds nothing, not even a space, and that has no actions draws
371
+ * nothing, no ground, padding or edge. That is a live callout a page mounts before it has
372
+ * words, and it stays in the page so a screen reader reads what fills it. It comes after the
373
+ * tones, so it wins over each of them by its order.
374
+ */
375
+ :where(.dk-callout:has(> .dk-callout-body:empty):not(:has(> .dk-callout-actions))) {
376
+ padding: 0;
377
+ border-width: 0;
378
+ background: none;
379
+ }
380
+
381
+ :where(.dk-callout-title) {
382
+ margin: 0;
383
+ font-size: inherit;
384
+ font-weight: var(--dk-weight-strong);
385
+ }
386
+
387
+ :where(.dk-callout-body) {
388
+ display: grid;
389
+ gap: var(--dk-space-2);
390
+ }
391
+
392
+ :where(.dk-callout-body > *) {
393
+ margin: 0;
394
+ }
395
+
396
+ :where(.dk-callout-actions) {
397
+ display: flex;
398
+ flex-wrap: wrap;
399
+ gap: var(--dk-space-2);
400
+ }
401
+
402
+ /* On a phone a button and a field grow to the target a thumb presses, and stay level. */
403
+ @media (max-width: 48rem) {
404
+ :where(.dk-button, .dk-input, .dk-select) {
405
+ min-height: var(--dk-target);
406
+ }
407
+
408
+ :where(.dk-button) {
409
+ min-width: var(--dk-target);
410
+ }
411
+ }
412
+
413
+ /*
414
+ * In forced colors the page's own grounds and shadows are gone, so a pressed toggle takes the
415
+ * system's highlight, an off button the system's gray on the page's ground as a disabled one
416
+ * does, an off toggle that is on an edge in the highlight, and the select the browser's own
417
+ * arrow, since the drawn caret is a background.
418
+ */
419
+ @media (forced-colors: active) {
420
+ :where(.dk-button[aria-pressed='true'], .dk-button[aria-expanded='true']) {
421
+ background: Highlight;
422
+ color: HighlightText;
423
+ }
424
+
425
+ :where(.dk-button:disabled, .dk-button[aria-disabled='true']) {
426
+ border-color: GrayText;
427
+ background: Canvas;
428
+ color: GrayText;
429
+ }
430
+
431
+ :where(
432
+ .dk-button[aria-pressed='true']:disabled,
433
+ .dk-button[aria-pressed='true'][aria-disabled='true']
434
+ ) {
435
+ border-color: Highlight;
436
+ }
437
+
438
+ :where(.dk-select) {
439
+ appearance: auto;
440
+ padding-inline-end: var(--dk-field-inline);
441
+ background-image: none;
442
+ }
443
+ }
444
+
445
+ /*
446
+ * An explainer: the page that says how a demo works, in sections a reader can jump between.
447
+ * Its text starts at the column's inset, where the strip's links start, and every part of it
448
+ * holds to the measure. Each part is spaced from the one before it, so lists, tables, panels
449
+ * and code blocks space alike. A section opens on a rule, then its number, its heading and its
450
+ * text, and a section is a plain one, never named, so the page's landmarks stay the strip's
451
+ * links and switches, the header, the main content, the footer and the frames that scroll.
452
+ */
453
+ :where(.dk-explainer-header) {
454
+ padding-block: var(--dk-space-4) 0;
455
+ font-size: var(--dk-text-small);
456
+ }
457
+
458
+ :where(.dk-explainer) {
459
+ padding-block-start: var(--dk-space-6);
460
+ }
461
+
462
+ :where(.dk-explainer > *, .dk-explainer > section > *) {
463
+ max-width: var(--dk-measure);
464
+ margin-block: 0;
465
+ }
466
+
467
+ :where(.dk-explainer > * + *, .dk-explainer > section > * + *) {
468
+ margin-block-start: var(--dk-space-4);
469
+ }
470
+
471
+ :where(.dk-explainer > h1) {
472
+ font-size: var(--dk-text-display);
473
+ }
474
+
475
+ :where(.dk-explainer > h1 + *) {
476
+ margin-block-start: var(--dk-space-2);
477
+ }
478
+
479
+ /* What the demo does, in a sentence or two, the second thing a reader reads after the title. */
480
+ :where(.dk-explainer-lead) {
481
+ font-size: var(--dk-text-lead);
482
+ }
483
+
484
+ :where(.dk-explainer > section) {
485
+ margin-block-start: var(--dk-space-6);
486
+ padding-block-start: var(--dk-space-6);
487
+ border-top: 1px solid var(--dk-line);
488
+ }
489
+
490
+ /* The section's number, for the eye alone, since its heading says what it is. */
491
+ :where(.dk-explainer-number) {
492
+ color: var(--dk-muted);
493
+ font-size: var(--dk-text-caption);
494
+ }
495
+
496
+ /*
497
+ * A jump to a section's heading stops short of it by the number's line, the space over it and a
498
+ * short step more, so the number and the section's rule stay in sight above it.
499
+ */
500
+ :where(.dk-explainer > section > h2) {
501
+ font-size: var(--dk-text-title);
502
+ scroll-margin-top: calc(
503
+ var(--dk-text-caption) * var(--dk-leading-body) + var(--dk-space-1) +
504
+ var(--dk-space-6) + var(--dk-space-2)
505
+ );
506
+ }
507
+
508
+ :where(.dk-explainer-number + h2) {
509
+ margin-block-start: var(--dk-space-1);
510
+ }
511
+
512
+ :where(.dk-explainer > section > h2 + *) {
513
+ margin-block-start: var(--dk-space-3);
514
+ }
515
+
516
+ :where(.dk-explainer > section > h3) {
517
+ margin-block-start: var(--dk-space-5);
518
+ font-size: var(--dk-text-body);
519
+ }
520
+
521
+ :where(.dk-explainer > section > h3 + *) {
522
+ margin-block-start: var(--dk-space-1);
523
+ }
524
+
525
+ /*
526
+ * Steps a demo takes one after another, each in a box of its own with an arrow above it from
527
+ * the step before. The arrow is a span hidden from a screen reader, since a selector in this
528
+ * sheet takes nothing after its :where() but a focus pseudo-class, and a pseudo-element cannot
529
+ * sit inside one. The list keeps role="list" in its markup, since a browser can drop a list's
530
+ * meaning when its markers are gone.
531
+ */
532
+ :where(.dk-steps) {
533
+ display: grid;
534
+ gap: var(--dk-space-5);
535
+ padding: 0;
536
+ list-style: none;
537
+ }
538
+
539
+ :where(.dk-steps > li) {
540
+ position: relative;
541
+ padding: var(--dk-space-3) var(--dk-space-4);
542
+ border: 1px solid var(--dk-line);
543
+ border-radius: var(--dk-radius-large);
544
+ font-size: var(--dk-text-small);
545
+ }
546
+
547
+ :where(.dk-steps-arrow) {
548
+ position: absolute;
549
+ inset-inline: 0;
550
+ bottom: 100%;
551
+ line-height: var(--dk-space-5);
552
+ text-align: center;
553
+ color: var(--dk-muted);
554
+ }
555
+
556
+ :where(.dk-steps-title) {
557
+ display: block;
558
+ font-weight: var(--dk-weight-medium);
559
+ }
560
+
561
+ :where(.dk-steps-note) {
562
+ display: block;
563
+ margin-block-start: var(--dk-space-1);
564
+ color: var(--dk-muted);
565
+ }
566
+
567
+ /*
568
+ * A panel, a region of a page set apart on the card's ground, at the body's size, with no
569
+ * tone and no role. Its edge in the line's color is what draws it, since the card's ground is
570
+ * close to the page's, and it stays in forced colors. Its title steps down to the body's size
571
+ * inside an explainer, under the section's heading.
572
+ */
573
+ :where(.dk-panel) {
574
+ padding: var(--dk-space-5);
575
+ border: 1px solid var(--dk-line);
576
+ border-radius: var(--dk-radius-large);
577
+ background: var(--dk-surface);
578
+ color: var(--dk-fg);
579
+ }
580
+
581
+ :where(.dk-panel > *) {
582
+ margin-block: 0;
583
+ }
584
+
585
+ :where(.dk-panel > * + *) {
586
+ margin-block-start: var(--dk-space-3);
587
+ }
588
+
589
+ :where(.dk-panel-title) {
590
+ font-size: var(--dk-text-title);
591
+ font-weight: var(--dk-weight-strong);
592
+ line-height: var(--dk-leading-tight);
593
+ }
594
+
595
+ :where(.dk-explainer .dk-panel-title) {
596
+ font-size: var(--dk-text-body);
597
+ }
598
+
599
+ /*
600
+ * A table scrolls inside its frame when it is wider than the measure, so the page never does.
601
+ * The frame is a named region with a tabindex of 0, so a keyboard can reach it and scroll it.
602
+ * Its rows are ruled, its headers step back in the muted text, and its outer cells keep no
603
+ * padding, so its text lines up with the prose around it. Figures sit to the right, never
604
+ * wrapping, while the text in a row wraps and keeps each cell's first line level.
605
+ */
606
+ :where(.dk-table-scroll) {
607
+ max-width: 100%;
608
+ overflow-x: auto;
609
+ }
610
+
611
+ :where(.dk-table) {
612
+ width: 100%;
613
+ font-size: var(--dk-text-small);
614
+ }
615
+
616
+ :where(.dk-table th, .dk-table td) {
617
+ padding: var(--dk-space-2) var(--dk-space-3);
618
+ border-bottom: 1px solid var(--dk-line);
619
+ text-align: start;
620
+ vertical-align: baseline;
621
+ }
622
+
623
+ :where(.dk-table th:first-child, .dk-table td:first-child) {
624
+ padding-inline-start: 0;
625
+ }
626
+
627
+ :where(.dk-table th:last-child, .dk-table td:last-child) {
628
+ padding-inline-end: 0;
629
+ }
630
+
631
+ :where(.dk-table thead th) {
632
+ color: var(--dk-muted);
633
+ font-weight: var(--dk-weight-medium);
634
+ }
635
+
636
+ :where(.dk-table tbody th) {
637
+ font-weight: var(--dk-weight-medium);
638
+ }
639
+
640
+ :where(.dk-table .dk-table-number) {
641
+ text-align: end;
642
+ white-space: nowrap;
643
+ }
644
+
645
+ /* Code in a cell keeps its name whole, so the frame scrolls rather than the name breaking. */
646
+ :where(.dk-table code) {
647
+ overflow-wrap: normal;
648
+ }
649
+
650
+ /*
651
+ * A block of code keeps its lines as written and scrolls inside itself, a named region the
652
+ * keyboard reaches, as a table's frame is. It sits on the card's ground, or on the page's
653
+ * inside a panel, so it reads as set into what holds it, and its edge shows in forced colors.
654
+ */
655
+ :where(.dk-code) {
656
+ padding: var(--dk-space-3) var(--dk-space-4);
657
+ border: 1px solid transparent;
658
+ border-radius: var(--dk-radius);
659
+ background: var(--dk-surface);
660
+ font-size: var(--dk-text-code);
661
+ line-height: var(--dk-leading-body);
662
+ }
663
+
664
+ :where(.dk-panel .dk-code) {
665
+ background: var(--dk-bg);
666
+ }
667
+
668
+ /*
669
+ * The title of a table or a code block, outside the frame that scrolls, which names the frame
670
+ * and the table. A caption would take the table's width and scroll off a phone with it. It
671
+ * comes after the frames' own rules, so its step wins over the code block's margin.
672
+ */
673
+ :where(.dk-table-title, .dk-code-title) {
674
+ margin-block-end: 0;
675
+ font-size: var(--dk-text-small);
676
+ font-weight: var(--dk-weight-strong);
677
+ }
678
+
679
+ :where(.dk-table-title + *, .dk-code-title + *) {
680
+ margin-block-start: var(--dk-space-2);
681
+ }
682
+
683
+ @media (max-width: 48rem) {
684
+ :where(.dk-panel) {
685
+ padding: var(--dk-space-4);
686
+ }
687
+ }
688
+ }