@slotted/styles 0.1.0-beta.2 → 0.1.0-beta.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slotted/styles",
3
- "version": "0.1.0-beta.2",
3
+ "version": "0.1.0-beta.4",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -460,7 +460,18 @@
460
460
  * for fifty pixels stood at whatever the longest destination measured.
461
461
  */
462
462
  min-inline-size: 0;
463
- overflow: hidden;
463
+ /**
464
+ * The inline axis clips, which the width transition between open and rail
465
+ * needs. The block axis scrolls: a region holding one column taller than
466
+ * itself instead of `nav-header`, `nav-body` and `nav-footer` keeps its
467
+ * foot reachable. With the three parts the body scrolls and the region
468
+ * never overflows.
469
+ */
470
+ overflow-x: hidden;
471
+ overflow-y: auto;
472
+ overflow-inline: hidden;
473
+ overflow-block: auto;
474
+ overscroll-behavior: contain;
464
475
  transition:
465
476
  inline-size var(--_duration) var(--_easing),
466
477
  visibility var(--_duration) step-start;
@@ -158,6 +158,19 @@
158
158
  --_edge: var(--_solid-active);
159
159
  }
160
160
 
161
+ /**
162
+ * Ink: the theme's `neutral` tone fills with the inverse surface and labels
163
+ * with the inverse text. A product that keeps the accent for data draws its
164
+ * primary action in it.
165
+ */
166
+ [data-ui='button'][data-tone='neutral'] {
167
+ --_solid: var(--slotted-tone-neutral-solid);
168
+ --_solid-hover: var(--slotted-tone-neutral-solid-hover);
169
+ --_solid-active: var(--slotted-tone-neutral-solid-active);
170
+ --_on-solid: var(--slotted-tone-neutral-on-solid);
171
+ --_text: var(--slotted-tone-neutral-text);
172
+ }
173
+
161
174
  [data-ui='button'][data-tone='success'] {
162
175
  --_solid: var(--slotted-tone-success-solid);
163
176
  --_solid-hover: var(--slotted-tone-success-solid-hover);
@@ -681,6 +694,26 @@
681
694
  inline-size: 100%;
682
695
  }
683
696
 
697
+ /**
698
+ * A field trigger: the label at the start and `end` at the inline end. The
699
+ * label takes the free space, so `start` stays beside it and the end slot is
700
+ * pushed to the edge; flex follows the writing direction, so it mirrors.
701
+ */
702
+ [data-ui='button'][data-justify='between'] {
703
+ justify-content: space-between;
704
+ }
705
+
706
+ [data-ui='button'][data-justify='between'] > [data-part='label'] {
707
+ flex: 1 1 auto;
708
+ text-align: start;
709
+ }
710
+
711
+ /* What a trigger holds at its end — a shortcut, a count — is as wide as it is. */
712
+ [data-ui='button'][data-justify='between'] > [data-part='end'] {
713
+ inline-size: auto;
714
+ min-inline-size: var(--_icon-size);
715
+ }
716
+
684
717
  /**
685
718
  * An icon-only control is square from the control height, so its visual box
686
719
  * and its target are the same box. The two minimums are the WCAG 2.2 floor
@@ -52,6 +52,11 @@
52
52
  "--slotted-tone-danger-solid-active",
53
53
  "--slotted-tone-danger-solid-hover",
54
54
  "--slotted-tone-danger-text",
55
+ "--slotted-tone-neutral-on-solid",
56
+ "--slotted-tone-neutral-solid",
57
+ "--slotted-tone-neutral-solid-active",
58
+ "--slotted-tone-neutral-solid-hover",
59
+ "--slotted-tone-neutral-text",
55
60
  "--slotted-tone-secondary-on-solid",
56
61
  "--slotted-tone-secondary-solid",
57
62
  "--slotted-tone-secondary-solid-active",
@@ -341,6 +341,10 @@
341
341
  --_seam: var(--slotted-tone-secondary-solid-active);
342
342
  }
343
343
 
344
+ [data-ui='button-group'] > [data-tone='neutral'] {
345
+ --_seam: var(--slotted-tone-neutral-solid-active);
346
+ }
347
+
344
348
  [data-ui='button-group'] > [data-tone='success'] {
345
349
  --_seam: var(--slotted-tone-success-solid-active);
346
350
  }
@@ -5,6 +5,7 @@
5
5
  "--slotted-text-muted",
6
6
  "--slotted-tone-accent-solid-active",
7
7
  "--slotted-tone-danger-solid-active",
8
+ "--slotted-tone-neutral-solid-active",
8
9
  "--slotted-tone-secondary-solid-active",
9
10
  "--slotted-tone-success-solid-active",
10
11
  "--slotted-tone-warning-solid-active"
@@ -877,6 +877,13 @@
877
877
  overflow-wrap: anywhere;
878
878
  }
879
879
 
880
+ /* The label of a line on this category, the plot's own words for it. */
881
+ [data-ui='chart'] [data-part='tooltip-note'] {
882
+ color: var(--slotted-text-muted, GrayText);
883
+ grid-column: 1 / -1;
884
+ overflow-wrap: anywhere;
885
+ }
886
+
880
887
  [data-ui='chart'] :is([data-part='tooltip-item'], [data-part='tooltip-total']) {
881
888
  align-items: center;
882
889
  display: grid;
@@ -784,4 +784,128 @@
784
784
  [data-ui='currency-field'][data-part='root'][data-disabled] > [data-part='end'] {
785
785
  color: var(--slotted-disabled-foreground);
786
786
  }
787
+
788
+ /**
789
+ * ── The display step ───────────────────────────────────────────────────
790
+ *
791
+ * The headline amount of an entry sheet: the figure at the 4xl step in
792
+ * tabular figures with the tighter tracking large type takes, and the
793
+ * currency's mark apart from it, muted at the xl step and on the baseline
794
+ * of the digits. Where the platform sizes a field to its content the
795
+ * control is as wide as the amount it holds, so the mark stays beside the
796
+ * digits; elsewhere the control takes the line and `align` places the
797
+ * amount in it.
798
+ */
799
+ [data-ui='currency-field'][data-part='root'][data-appearance='display'] {
800
+ --_font-size: var(
801
+ --slotted-currency-field-display-font-size,
802
+ var(--slotted-font-size-4xl, 2rem)
803
+ );
804
+ --_height: calc(
805
+ var(--_font-size) * var(--slotted-line-height-4xl, 1.2) + 2 * var(--slotted-space-2, 0.25rem)
806
+ );
807
+ --_padding-inline: var(--slotted-control-padding-inline-lg, 16px);
808
+ --_gap: var(--slotted-space-3, 0.375rem);
809
+
810
+ align-items: baseline;
811
+ font-weight: var(--slotted-font-weight-medium, 500);
812
+ letter-spacing: var(--slotted-letter-spacing-tighter, -0.03em);
813
+ line-height: var(--slotted-line-height-4xl, 1.2);
814
+ }
815
+
816
+ [data-ui='currency-field'][data-part='root'][data-appearance='display'] > [data-part='symbol'] {
817
+ color: var(--slotted-currency-field-symbol-color, var(--slotted-text-muted, GrayText));
818
+ flex: none;
819
+ font-size: var(
820
+ --slotted-currency-field-symbol-font-size,
821
+ var(--slotted-font-size-xl, 1.125rem)
822
+ );
823
+ font-weight: var(--slotted-font-weight-regular, 400);
824
+ letter-spacing: 0;
825
+ }
826
+
827
+ [data-ui='currency-field'][data-part='root'][data-appearance='display'] > [data-part='input'] {
828
+ align-self: auto;
829
+ margin-block: 0;
830
+ }
831
+
832
+ @supports (field-sizing: content) {
833
+ [data-ui='currency-field'][data-part='root'][data-appearance='display'] {
834
+ inline-size: fit-content;
835
+ max-inline-size: 100%;
836
+ }
837
+
838
+ [data-ui='currency-field'][data-part='root'][data-appearance='display'] > [data-part='input'] {
839
+ field-sizing: content;
840
+ flex: 0 1 auto;
841
+ min-inline-size: 1ch;
842
+ }
843
+ }
844
+
845
+ /**
846
+ * No box: a rule under the amount. On focus the rule takes the text colour
847
+ * and doubles, which is the focus indicator; invalid, it takes the danger
848
+ * colour. No ground, no corner and no resting lift.
849
+ */
850
+ [data-ui='currency-field'][data-part='root'][data-appearance='display'] {
851
+ background-color: transparent;
852
+ border-color: transparent;
853
+ border-block-end-color: var(
854
+ --slotted-currency-field-underline-color,
855
+ var(--slotted-control-border-color, ButtonBorder)
856
+ );
857
+ border-radius: var(--slotted-radius-none, 0px);
858
+ box-shadow: none;
859
+ padding-inline: 0;
860
+ }
861
+
862
+ [data-ui='currency-field'][data-part='root'][data-appearance='display']:has(
863
+ > [data-part='input']:focus-visible
864
+ ) {
865
+ border-block-end-color: var(--slotted-text, CanvasText);
866
+ box-shadow: inset 0 calc(-1 * var(--slotted-border-width-thin, 1px)) 0
867
+ var(--slotted-text, CanvasText);
868
+ outline: none;
869
+ }
870
+
871
+ [data-ui='currency-field'][data-part='root'][data-appearance='display'][data-invalid] {
872
+ border-block-end-color: var(--slotted-tone-danger-border, CanvasText);
873
+ box-shadow: none;
874
+ }
875
+
876
+ [data-ui='currency-field'][data-part='root'][data-appearance='display'][data-invalid]:has(
877
+ > [data-part='input']:focus-visible
878
+ ) {
879
+ box-shadow: inset 0 calc(-1 * var(--_invalid-edge-width)) 0 var(--_invalid-edge-color);
880
+ }
881
+
882
+ [data-ui='currency-field'][data-part='root'][data-appearance='display']:has(
883
+ > [data-part='input']:disabled
884
+ ) {
885
+ border-block-end-color: var(--slotted-disabled-border, GrayText);
886
+ }
887
+
888
+ @media (forced-colors: active) {
889
+ [data-ui='currency-field'][data-part='root'][data-appearance='display'] {
890
+ border-block-end-color: ButtonBorder;
891
+ }
892
+
893
+ /* A shadow is not painted under forced colours, so the doubled rule of
894
+ focus is a wider border there. */
895
+ [data-ui='currency-field'][data-part='root'][data-appearance='display']:has(
896
+ > [data-part='input']:focus-visible
897
+ ) {
898
+ border-block-end-color: Highlight;
899
+ border-block-end-width: calc(2 * var(--slotted-border-width-thin, 1px));
900
+ }
901
+
902
+ [data-ui='currency-field'][data-part='root'][data-appearance='display'][data-invalid]:has(
903
+ > [data-part='input']:focus-visible
904
+ ) {
905
+ border-block-end-color: Highlight;
906
+ border-block-end-width: calc(
907
+ var(--slotted-border-width-thin, 1px) + var(--_invalid-edge-width)
908
+ );
909
+ }
910
+ }
787
911
  }
@@ -1,5 +1,6 @@
1
1
  [
2
2
  "--slotted-border-subtle",
3
+ "--slotted-border-width-thin",
3
4
  "--slotted-control-border-color",
4
5
  "--slotted-control-border-width",
5
6
  "--slotted-control-font-family",
@@ -36,6 +37,7 @@
36
37
  "--slotted-currency-field-disabled-background",
37
38
  "--slotted-currency-field-disabled-border-color",
38
39
  "--slotted-currency-field-disabled-color",
40
+ "--slotted-currency-field-display-font-size",
39
41
  "--slotted-currency-field-hover-border-color",
40
42
  "--slotted-currency-field-icon-size-min",
41
43
  "--slotted-currency-field-invalid-border-color",
@@ -57,6 +59,9 @@
57
59
  "--slotted-currency-field-subtle-background",
58
60
  "--slotted-currency-field-subtle-border-color",
59
61
  "--slotted-currency-field-subtle-hover-background",
62
+ "--slotted-currency-field-symbol-color",
63
+ "--slotted-currency-field-symbol-font-size",
64
+ "--slotted-currency-field-underline-color",
60
65
  "--slotted-disabled-background",
61
66
  "--slotted-disabled-border",
62
67
  "--slotted-disabled-foreground",
@@ -64,10 +69,17 @@
64
69
  "--slotted-focus-ring-color-invalid",
65
70
  "--slotted-focus-ring-offset",
66
71
  "--slotted-focus-ring-width",
72
+ "--slotted-font-size-4xl",
73
+ "--slotted-font-size-xl",
74
+ "--slotted-font-weight-medium",
75
+ "--slotted-font-weight-regular",
76
+ "--slotted-letter-spacing-tighter",
77
+ "--slotted-line-height-4xl",
67
78
  "--slotted-radius-none",
68
79
  "--slotted-radius-xs",
69
80
  "--slotted-space-1",
70
81
  "--slotted-space-2",
82
+ "--slotted-space-3",
71
83
  "--slotted-surface-sunken",
72
84
  "--slotted-target-comfortable",
73
85
  "--slotted-target-min",
@@ -52,8 +52,12 @@
52
52
  --_measure: var(--slotted-dialog-measure, 32rem);
53
53
  /** The air between the panel and the edge of the layer. */
54
54
  --_layer-padding: var(--slotted-space-8, 1.5rem);
55
- /** The panel's own inset, which every row reads. */
56
- --_padding-inline: var(--slotted-space-8, 1.5rem);
55
+ /**
56
+ * The panel's own inset, which every row reads. The panel draws none of it
57
+ * itself: the header, the body and the footer carry it, and a layout of the
58
+ * consumer's own that skips them reads the same two public tokens.
59
+ */
60
+ --_padding-inline: var(--slotted-dialog-padding-inline, var(--slotted-space-8, 1.5rem));
57
61
  /**
58
62
  * Three insets, not one number used three times, because the three rows
59
63
  * hold three different things.
@@ -72,7 +76,7 @@
72
76
  * paragraph reads as a slab around a button: twenty above and below a
73
77
  * thirty-four pixel control is a seventy-four pixel bar for one line.
74
78
  */
75
- --_padding-block: var(--slotted-space-7, 1.25rem);
79
+ --_padding-block: var(--slotted-dialog-padding-block, var(--slotted-space-7, 1.25rem));
76
80
  --_header-padding-block: var(--slotted-space-6, 1rem);
77
81
  --_footer-padding-block: var(--slotted-space-5, 0.75rem);
78
82
  --_gap: var(--slotted-space-5, 0.75rem);
@@ -182,8 +186,8 @@
182
186
 
183
187
  [data-ui='dialog'][data-size='sm'] {
184
188
  --_measure: var(--slotted-dialog-measure, 24rem);
185
- --_padding-inline: var(--slotted-space-7, 1.25rem);
186
- --_padding-block: var(--slotted-space-6, 1rem);
189
+ --_padding-inline: var(--slotted-dialog-padding-inline-sm, var(--slotted-space-7, 1.25rem));
190
+ --_padding-block: var(--slotted-dialog-padding-block-sm, var(--slotted-space-6, 1rem));
187
191
  --_header-padding-block: var(--slotted-space-5, 0.75rem);
188
192
  --_footer-padding-block: var(--slotted-space-4, 0.5rem);
189
193
  --_title-font-size: var(--slotted-font-size-lg, 1rem);
@@ -281,6 +285,15 @@
281
285
  /* ── The panel ────────────────────────────────────────────────────────── */
282
286
 
283
287
  [data-ui='dialog'] > [data-part='viewport'] > [data-part='content'] {
288
+ /**
289
+ * The inset the rows carry, stated where a layout of the consumer's own can
290
+ * read it: the panel draws no padding, so content written straight inside
291
+ * it reads `--slotted-dialog-inset-inline` for its padding and stands
292
+ * in the column the header, the body and the footer stand in.
293
+ */
294
+ --slotted-dialog-inset-inline: var(--_padding-inline);
295
+ --slotted-dialog-inset-block: var(--_padding-block);
296
+
284
297
  display: grid;
285
298
  grid-template-rows: auto minmax(0, 1fr) auto;
286
299
  inline-size: 100%;
@@ -17,6 +17,10 @@
17
17
  "--slotted-dialog-description-color",
18
18
  "--slotted-dialog-footer-surface",
19
19
  "--slotted-dialog-measure",
20
+ "--slotted-dialog-padding-block",
21
+ "--slotted-dialog-padding-block-sm",
22
+ "--slotted-dialog-padding-inline",
23
+ "--slotted-dialog-padding-inline-sm",
20
24
  "--slotted-dialog-radius",
21
25
  "--slotted-dialog-rule-color",
22
26
  "--slotted-dialog-scrim",
package/src/list/list.css CHANGED
@@ -193,6 +193,33 @@
193
193
  * level is the library's own sticky step, so a heading never rises above an
194
194
  * overlay that is above the page.
195
195
  */
196
+ /* A heading with an end sets the name at the start and the end content on
197
+ the same line, at the end. */
198
+ [data-ui='list'] [data-part='section-label']:has(> [data-part='section-end']) {
199
+ align-items: baseline;
200
+ display: flex;
201
+ gap: var(--slotted-space-4, 0.5rem);
202
+ justify-content: space-between;
203
+ }
204
+
205
+ [data-ui='list'] [data-part='section-end'] {
206
+ flex: none;
207
+ font-variant-numeric: tabular-nums;
208
+ white-space: nowrap;
209
+ }
210
+
211
+ /**
212
+ * `ruled`: the name in the text colour over a rule, with no ground behind it
213
+ * — a day of a phone list with its balance at the end. The sticky ground is
214
+ * still the set's surface, so the rows passing under it are covered.
215
+ */
216
+ [data-ui='list'] [data-part='section-label'][data-variant='ruled'] {
217
+ border-block-end: var(--slotted-border-width-thin, 1px) solid
218
+ var(--slotted-list-section-rule-color, var(--slotted-border-subtle, GrayText));
219
+ color: var(--slotted-list-section-ruled-color, var(--slotted-text, CanvasText));
220
+ font-weight: var(--slotted-font-weight-medium, 500);
221
+ }
222
+
196
223
  [data-ui='list'] [data-part='section-label'][data-sticky] {
197
224
  background-color: var(--_surface);
198
225
  inset-block-start: 0;
@@ -5,6 +5,7 @@
5
5
  "--slotted-control-padding-inline-md",
6
6
  "--slotted-control-padding-inline-sm",
7
7
  "--slotted-font-size-xs",
8
+ "--slotted-font-weight-medium",
8
9
  "--slotted-font-weight-semibold",
9
10
  "--slotted-line-height-sm",
10
11
  "--slotted-list-background",
@@ -28,6 +29,8 @@
28
29
  "--slotted-list-section-padding-block",
29
30
  "--slotted-list-section-padding-block-lg",
30
31
  "--slotted-list-section-padding-block-sm",
32
+ "--slotted-list-section-rule-color",
33
+ "--slotted-list-section-ruled-color",
31
34
  "--slotted-radius-md",
32
35
  "--slotted-space-2",
33
36
  "--slotted-space-3",
@@ -37,6 +40,7 @@
37
40
  "--slotted-space-8",
38
41
  "--slotted-space-9",
39
42
  "--slotted-surface",
43
+ "--slotted-text",
40
44
  "--slotted-text-muted",
41
45
  "--slotted-z-index-sticky"
42
46
  ]
@@ -520,6 +520,86 @@
520
520
  box-shadow: none;
521
521
  }
522
522
 
523
+ /**
524
+ * ── Underline ──────────────────────────────────────────────────────────
525
+ *
526
+ * The same radio group with no track: the words alone, sized to their own
527
+ * width, the chosen one in the text colour and underlined. Every other word
528
+ * is muted and takes the text colour under the pointer. No thumb, no
529
+ * dividers, no ground — the underline is the mark, and it sits under the
530
+ * word rather than on an edge of a box (R1).
531
+ */
532
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline'] {
533
+ --_inner: var(--_height);
534
+
535
+ background: none;
536
+ border: 0;
537
+ border-radius: 0;
538
+ box-shadow: none;
539
+ column-gap: var(--slotted-segmented-control-underline-gap, var(--slotted-space-6, 1rem));
540
+ grid-auto-columns: auto;
541
+ padding: 0;
542
+ }
543
+
544
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline'] [data-part='indicator'],
545
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline']
546
+ [data-part='item']
547
+ + [data-part='item']::before {
548
+ display: none;
549
+ }
550
+
551
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline'] [data-part='item'] {
552
+ color: var(--slotted-segmented-control-underline-color, var(--slotted-text-muted, GrayText));
553
+ font-weight: var(--slotted-font-weight-medium, 500);
554
+ min-inline-size: var(--slotted-target-min, 24px);
555
+ padding-inline: 0;
556
+ }
557
+
558
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline']
559
+ [data-part='item'][data-checked] {
560
+ color: var(
561
+ --slotted-segmented-control-underline-checked-color,
562
+ var(--slotted-text, CanvasText)
563
+ );
564
+ }
565
+
566
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline']
567
+ [data-part='item'][data-checked]
568
+ [data-part='label'] {
569
+ text-decoration-color: currentColor;
570
+ text-decoration-line: underline;
571
+ text-decoration-thickness: var(--slotted-border-width-thick, 2px);
572
+ text-underline-offset: 0.35em;
573
+ }
574
+
575
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline'][data-invalid]
576
+ [data-part='item'][data-checked]
577
+ [data-part='label'] {
578
+ text-decoration-color: var(--slotted-tone-danger-border, CanvasText);
579
+ }
580
+
581
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline']:not([data-readonly])
582
+ [data-part='item']:hover:not([data-disabled]):not([data-checked]):has(
583
+ [data-part='control']:enabled
584
+ ),
585
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline']:not([data-readonly])
586
+ [data-part='item']:active:not([data-disabled]):not([data-checked]):has(
587
+ [data-part='control']:enabled
588
+ ) {
589
+ background: none;
590
+ color: var(--slotted-text, CanvasText);
591
+ }
592
+
593
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline']
594
+ [data-part='item']:has([data-part='control']:focus-visible) {
595
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
596
+ }
597
+
598
+ [data-ui='segmented-control'][data-part='root'][data-variant='underline']
599
+ [data-part='item'][data-disabled] {
600
+ color: var(--slotted-disabled-foreground, GrayText);
601
+ }
602
+
523
603
  /* ── Condensed ────────────────────────────────────────────────────────── */
524
604
 
525
605
  /**
@@ -1,5 +1,6 @@
1
1
  [
2
2
  "--slotted-border-subtle",
3
+ "--slotted-border-width-thick",
3
4
  "--slotted-control-border-color",
4
5
  "--slotted-control-border-width",
5
6
  "--slotted-control-font-family",
@@ -35,7 +36,9 @@
35
36
  "--slotted-easing-standard",
36
37
  "--slotted-focus-ring-color",
37
38
  "--slotted-focus-ring-color-invalid",
39
+ "--slotted-focus-ring-offset",
38
40
  "--slotted-focus-ring-width",
41
+ "--slotted-font-weight-medium",
39
42
  "--slotted-radius-xs",
40
43
  "--slotted-segmented-control-active-background",
41
44
  "--slotted-segmented-control-background",
@@ -55,9 +58,14 @@
55
58
  "--slotted-segmented-control-invalid-focus-ring-color",
56
59
  "--slotted-segmented-control-radius",
57
60
  "--slotted-segmented-control-shadow",
61
+ "--slotted-segmented-control-underline-checked-color",
62
+ "--slotted-segmented-control-underline-color",
63
+ "--slotted-segmented-control-underline-gap",
58
64
  "--slotted-space-1",
65
+ "--slotted-space-6",
59
66
  "--slotted-target-min",
60
67
  "--slotted-text",
68
+ "--slotted-text-muted",
61
69
  "--slotted-tone-accent-border",
62
70
  "--slotted-tone-accent-subtle-active",
63
71
  "--slotted-tone-accent-text",
@@ -446,7 +446,9 @@
446
446
  font-size: var(--_value-size);
447
447
  font-variant-numeric: proportional-nums;
448
448
  font-weight: var(--slotted-font-weight-semibold, 600);
449
- letter-spacing: -0.02em;
449
+ /* The figure is set at the 3xl or 4xl step, where the theme's tighter
450
+ tracking applies. */
451
+ letter-spacing: var(--slotted-letter-spacing-tighter, -0.03em);
450
452
  unicode-bidi: plaintext;
451
453
  line-height: var(--_value-line);
452
454
  margin: 0;
@@ -13,6 +13,7 @@
13
13
  "--slotted-font-size-xs",
14
14
  "--slotted-font-weight-medium",
15
15
  "--slotted-font-weight-semibold",
16
+ "--slotted-letter-spacing-tighter",
16
17
  "--slotted-line-height-2xl",
17
18
  "--slotted-line-height-3xl",
18
19
  "--slotted-line-height-4xl",
@@ -232,7 +232,7 @@
232
232
  color: var(--_muted);
233
233
  font-size: var(--slotted-font-size-xs, 0.75rem);
234
234
  padding-block: var(--_pad-block);
235
- padding-inline: var(--_pad-inline);
235
+ padding-inline: var(--_edge-inset);
236
236
  text-align: start;
237
237
  }
238
238
 
@@ -319,6 +319,57 @@
319
319
  vertical-align: var(--_cell-align);
320
320
  }
321
321
 
322
+ /**
323
+ * ── The outer edges ────────────────────────────────────────────────────
324
+ *
325
+ * The first and the last column take `--_edge-inset` on their outer side:
326
+ * the cell's own inset by default, and under `edges="flush"` the theme's
327
+ * `--slotted-table-edge-inset`, nought when it sets none — so a `plain` or
328
+ * `ruled` table lines its text up with the heading above it. A `framed`
329
+ * table keeps the inset whatever `edges` says: its text stands against a
330
+ * border, and text touching a border is the cramped picture the frame
331
+ * exists to avoid. A pinned column keeps its own offset, which is a
332
+ * position rather than a padding, and the selection cell keeps its own
333
+ * inset because it is not one of the parts named here — a table that leads
334
+ * with a chooser has no text at its edge.
335
+ */
336
+ [data-ui='table'][data-part='root'] {
337
+ --_edge-inset: var(--_pad-inline);
338
+ }
339
+
340
+ [data-ui='table'][data-part='root'][data-edges='flush']:is(
341
+ [data-variant='plain'],
342
+ [data-variant='ruled']
343
+ ) {
344
+ --_edge-inset: var(--slotted-table-edge-inset, 0px);
345
+ }
346
+
347
+ [data-ui='table']
348
+ [data-part='row']
349
+ > :is([data-part='cell'], [data-part='row-header'], [data-part='group-header']):first-child,
350
+ [data-ui='table']
351
+ [data-part='row']
352
+ > [data-part='column-header']:first-child:not(:has(> [data-part='sort'])),
353
+ [data-ui='table']
354
+ [data-part='row']
355
+ > [data-part='column-header']:first-child
356
+ > [data-part='sort'] {
357
+ padding-inline-start: var(--_edge-inset);
358
+ }
359
+
360
+ [data-ui='table']
361
+ [data-part='row']
362
+ > :is([data-part='cell'], [data-part='row-header'], [data-part='group-header']):last-child,
363
+ [data-ui='table']
364
+ [data-part='row']
365
+ > [data-part='column-header']:last-child:not(:has(> [data-part='sort'])),
366
+ [data-ui='table']
367
+ [data-part='row']
368
+ > [data-part='column-header']:last-child
369
+ > [data-part='sort'] {
370
+ padding-inline-end: var(--_edge-inset);
371
+ }
372
+
322
373
  [data-ui='table'] [data-block-align='start'] {
323
374
  vertical-align: top;
324
375
  }
@@ -461,6 +512,84 @@
461
512
  color: var(--slotted-disabled-foreground, GrayText);
462
513
  }
463
514
 
515
+ /**
516
+ * The row the page shows elsewhere — the record open in a detail pane. A
517
+ * neutral ground a step beyond hover, so the pointer passing over it changes
518
+ * nothing, and no edge on the start side (R1). It is opaque, because a
519
+ * pinned cell copies the row's ground and a translucent one shows the
520
+ * scrolled cells through it. Selection is stronger and paints over it.
521
+ */
522
+ [data-ui='table'] [data-part='body'] > [data-part='row'][data-current]:not([data-selected]) {
523
+ background-color: var(
524
+ --slotted-table-row-surface-current,
525
+ var(--slotted-tone-secondary-subtle-active, ButtonFace)
526
+ );
527
+ }
528
+
529
+ /* A row with an action of its own is a thing the pointer presses. */
530
+ [data-ui='table'] [data-part='body'] > [data-part='row'][data-interactive]:not([data-disabled]) {
531
+ cursor: pointer;
532
+ }
533
+
534
+ /**
535
+ * ── The band that opens a group ────────────────────────────────────────
536
+ *
537
+ * One header cell across every column: the group's name at the start and
538
+ * its total at the end, in tabular figures so a column of daily nets lines
539
+ * up. The ground is the stripe's step, opaque for the same reason a pinned
540
+ * cell's is, and the band stays where it is when the pointer passes.
541
+ */
542
+ [data-ui='table'] [data-part='group-header'] {
543
+ background-color: var(--slotted-table-group-surface, var(--_stripe));
544
+ border-block-end: var(--_rule-width) solid var(--_rule);
545
+ color: var(--slotted-table-group-color, var(--_text));
546
+ font-weight: var(--slotted-font-weight-semibold, 600);
547
+ padding-block: var(--_pad-block);
548
+ padding-inline: var(--_pad-inline);
549
+ text-align: start;
550
+ }
551
+
552
+ [data-ui='table'] [data-part='group-content'] {
553
+ align-items: baseline;
554
+ display: flex;
555
+ gap: var(--_gap);
556
+ justify-content: space-between;
557
+ min-inline-size: 0;
558
+ }
559
+
560
+ [data-ui='table'] [data-part='group-end'] {
561
+ font-variant-numeric: tabular-nums;
562
+ text-align: end;
563
+ white-space: nowrap;
564
+ }
565
+
566
+ /**
567
+ * A sticky band stops under the header when the header sticks too. The
568
+ * header's height is one row of the control scale and its rule; a header
569
+ * that wraps sets `--slotted-table-group-sticky-offset` itself.
570
+ */
571
+ [data-ui='table'] [data-part='group-row'][data-sticky] > [data-part='group-header'] {
572
+ inset-block-start: var(--slotted-table-group-sticky-offset, 0);
573
+ position: sticky;
574
+ z-index: var(--slotted-z-index-sticky, 100);
575
+ }
576
+
577
+ [data-ui='table'][data-sticky-header]
578
+ [data-part='group-row'][data-sticky]
579
+ > [data-part='group-header'] {
580
+ inset-block-start: var(
581
+ --slotted-table-group-sticky-offset,
582
+ calc(var(--_row-min-block) + var(--_rule-width))
583
+ );
584
+ }
585
+
586
+ @media (forced-colors: active) {
587
+ [data-ui='table'] [data-part='body'] > [data-part='row'][data-current] {
588
+ outline: var(--_rule-width) solid Highlight;
589
+ outline-offset: calc(var(--_rule-width) * -1);
590
+ }
591
+ }
592
+
464
593
  /**
465
594
  * ── Alignment and numerals ─────────────────────────────────────────────
466
595
  *
@@ -542,20 +671,32 @@
542
671
  * written where the choice is made: a table wider than the page pushes the
543
672
  * page sideways instead of scrolling inside its frame.
544
673
  *
545
- * The offset is where the header stops. An application with a bar of its own
546
- * sets `--slotted-table-sticky-offset` once, and every table under it stops
547
- * below the bar rather than under it.
674
+ * The offset is where the header stops under `page`. An application with a
675
+ * bar of its own sets `--slotted-table-sticky-offset` once, and every table
676
+ * under it stops below the bar rather than under it. Under `scroll` the
677
+ * header stops at the top of the family's own scroller and reads no offset:
678
+ * `page.css` binds the offset to the page's chrome for every table inside
679
+ * the page, and a header reading it stood that far below its own scroller's
680
+ * top, over the first rows. A `page` table inside a scrolling box of the
681
+ * consumer's own sets the offset on that box, `0` for its top edge.
548
682
  */
549
683
  [data-ui='table'][data-sticky-header] [data-part='column-header'],
550
684
  /* The chooser's own header is a `selection` cell and not a `column-header`,
551
685
  and a rule naming only the second left the select-all scrolling away while
552
686
  every column beside it stayed. */
553
687
  [data-ui='table'][data-sticky-header] [data-part='head'] [data-part='selection'] {
554
- inset-block-start: var(--slotted-table-sticky-offset, 0);
688
+ inset-block-start: 0;
555
689
  position: sticky;
556
690
  z-index: calc(var(--slotted-z-index-sticky, 100) + 1);
557
691
  }
558
692
 
693
+ [data-ui='table'][data-sticky-to='page'][data-sticky-header] [data-part='column-header'],
694
+ [data-ui='table'][data-sticky-to='page'][data-sticky-header]
695
+ [data-part='head']
696
+ [data-part='selection'] {
697
+ inset-block-start: var(--slotted-table-sticky-offset, 0);
698
+ }
699
+
559
700
  [data-ui='table'][data-sticky-to='page'] [data-part='scroll'] {
560
701
  overflow: visible;
561
702
  }
@@ -572,11 +713,18 @@
572
713
  * sibling of the scroller and never leaves it in the first place.
573
714
  */
574
715
  [data-ui='table'][data-sticky-footer] [data-part='summary'] > [data-part='row'] > * {
575
- inset-block-end: var(--slotted-table-sticky-offset-end, 0);
716
+ inset-block-end: 0;
576
717
  position: sticky;
577
718
  z-index: calc(var(--slotted-z-index-sticky, 100) + 1);
578
719
  }
579
720
 
721
+ [data-ui='table'][data-sticky-to='page'][data-sticky-footer]
722
+ [data-part='summary']
723
+ > [data-part='row']
724
+ > * {
725
+ inset-block-end: var(--slotted-table-sticky-offset-end, 0);
726
+ }
727
+
580
728
  /* The corner again, at the bottom: a summary cell that is also a pinned
581
729
  column takes both insets and the step above both. */
582
730
  [data-ui='table'][data-sticky-footer] [data-part='summary'] [data-sticky] {
@@ -38,15 +38,20 @@
38
38
  "--slotted-table-color-muted",
39
39
  "--slotted-table-column-actions-size",
40
40
  "--slotted-table-control-radius",
41
+ "--slotted-table-edge-inset",
41
42
  "--slotted-table-font-family",
42
43
  "--slotted-table-font-size",
43
44
  "--slotted-table-gap",
45
+ "--slotted-table-group-color",
46
+ "--slotted-table-group-sticky-offset",
47
+ "--slotted-table-group-surface",
44
48
  "--slotted-table-header-surface",
45
49
  "--slotted-table-header-surface-hover",
46
50
  "--slotted-table-icon-size",
47
51
  "--slotted-table-radius",
48
52
  "--slotted-table-row-color-selected",
49
53
  "--slotted-table-row-min-block-size",
54
+ "--slotted-table-row-surface-current",
50
55
  "--slotted-table-row-surface-hover",
51
56
  "--slotted-table-row-surface-selected",
52
57
  "--slotted-table-row-surface-selected-hover",
@@ -64,6 +69,7 @@
64
69
  "--slotted-tone-accent-subtle-hover",
65
70
  "--slotted-tone-accent-surface",
66
71
  "--slotted-tone-accent-text",
72
+ "--slotted-tone-secondary-subtle-active",
67
73
  "--slotted-tone-secondary-subtle-hover",
68
74
  "--slotted-z-index-sticky"
69
75
  ]
@@ -235,6 +235,47 @@
235
235
  transition-duration: var(--slotted-duration-instant);
236
236
  }
237
237
 
238
+ /**
239
+ * ── Chips ──────────────────────────────────────────────────────────────
240
+ *
241
+ * The same chip `toggle-group` draws: a rounded item with the control edge,
242
+ * pressed in the neutral tone's ink.
243
+ */
244
+ [data-ui='toggle'][data-part='root'][data-variant='chips'] {
245
+ border-color: var(--_border-color);
246
+ border-radius: var(--slotted-toggle-chips-radius, var(--slotted-radius-full, 9999px));
247
+ font-weight: var(--slotted-font-weight-medium, 500);
248
+ }
249
+
250
+ [data-ui='toggle'][data-part='root'][data-variant='chips'][data-pressed]:not(:disabled):not(
251
+ [data-disabled]
252
+ ),
253
+ [data-ui='toggle'][data-part='root'][data-variant='chips'][data-pressed]:active:not(
254
+ :disabled
255
+ ):not([data-disabled]) {
256
+ background: var(
257
+ --slotted-toggle-chips-pressed-background,
258
+ var(--slotted-tone-neutral-solid, CanvasText)
259
+ );
260
+ border-color: var(
261
+ --slotted-toggle-chips-pressed-background,
262
+ var(--slotted-tone-neutral-solid, CanvasText)
263
+ );
264
+ color: var(--slotted-toggle-chips-pressed-color, var(--slotted-tone-neutral-on-solid, Canvas));
265
+ }
266
+
267
+ [data-ui='toggle'][data-part='root'][data-variant='chips'][data-pressed]:hover:not(:disabled):not(
268
+ [data-disabled]
269
+ ) {
270
+ background: var(--slotted-tone-neutral-solid-hover, CanvasText);
271
+ border-color: var(--slotted-tone-neutral-solid-hover, CanvasText);
272
+ }
273
+
274
+ [data-ui='toggle'][data-part='root'][data-variant='chips']:disabled,
275
+ [data-ui='toggle'][data-part='root'][data-variant='chips'][data-disabled] {
276
+ border-color: var(--slotted-disabled-border, GrayText);
277
+ }
278
+
238
279
  /* ── Focus ────────────────────────────────────────────────────────────── */
239
280
 
240
281
  /**
@@ -31,9 +31,14 @@
31
31
  "--slotted-focus-ring-color",
32
32
  "--slotted-focus-ring-offset",
33
33
  "--slotted-focus-ring-width",
34
+ "--slotted-font-weight-medium",
35
+ "--slotted-radius-full",
34
36
  "--slotted-text",
35
37
  "--slotted-toggle-active-background",
36
38
  "--slotted-toggle-border-color",
39
+ "--slotted-toggle-chips-pressed-background",
40
+ "--slotted-toggle-chips-pressed-color",
41
+ "--slotted-toggle-chips-radius",
37
42
  "--slotted-toggle-color",
38
43
  "--slotted-toggle-disabled-border-color",
39
44
  "--slotted-toggle-disabled-color",
@@ -49,6 +54,9 @@
49
54
  "--slotted-tone-accent-subtle-active",
50
55
  "--slotted-tone-accent-subtle-hover",
51
56
  "--slotted-tone-accent-text",
57
+ "--slotted-tone-neutral-on-solid",
58
+ "--slotted-tone-neutral-solid",
59
+ "--slotted-tone-neutral-solid-hover",
52
60
  "--slotted-tone-secondary-subtle-active",
53
61
  "--slotted-tone-secondary-subtle-hover"
54
62
  ]
@@ -392,6 +392,56 @@
392
392
  transition-duration: var(--slotted-duration-instant);
393
393
  }
394
394
 
395
+ /**
396
+ * ── Chips ──────────────────────────────────────────────────────────────
397
+ *
398
+ * A short list of choices as separate rounded items that wrap onto a second
399
+ * line rather than overflow, never joined into a bar. A chip at rest has the
400
+ * control edge; the pressed one is the neutral tone's ink — its solid ground
401
+ * under its own label — which is the one state a chip has to say at a
402
+ * glance. Hover and press move the ground of a chip at rest only.
403
+ */
404
+ [data-ui='toggle-group'][data-part='root'][data-variant='chips'] {
405
+ flex-wrap: wrap;
406
+ gap: var(--slotted-toggle-group-chips-gap, var(--slotted-space-3, 0.375rem));
407
+ }
408
+
409
+ [data-ui='toggle-group'][data-part='root'][data-variant='chips'] [data-part='item'] {
410
+ border-color: var(--_border-color);
411
+ border-radius: var(--slotted-toggle-group-chips-radius, var(--slotted-radius-full, 9999px));
412
+ font-weight: var(--slotted-font-weight-medium, 500);
413
+ }
414
+
415
+ [data-ui='toggle-group'][data-part='root'][data-variant='chips']
416
+ [data-part='item'][data-pressed]:not(:disabled):not([data-disabled]),
417
+ [data-ui='toggle-group'][data-part='root'][data-variant='chips']
418
+ [data-part='item'][data-pressed]:active:not(:disabled):not([data-disabled]) {
419
+ background: var(
420
+ --slotted-toggle-group-chips-pressed-background,
421
+ var(--slotted-tone-neutral-solid, CanvasText)
422
+ );
423
+ border-color: var(
424
+ --slotted-toggle-group-chips-pressed-background,
425
+ var(--slotted-tone-neutral-solid, CanvasText)
426
+ );
427
+ color: var(
428
+ --slotted-toggle-group-chips-pressed-color,
429
+ var(--slotted-tone-neutral-on-solid, Canvas)
430
+ );
431
+ }
432
+
433
+ [data-ui='toggle-group'][data-part='root'][data-variant='chips']
434
+ [data-part='item'][data-pressed]:hover:not(:disabled):not([data-disabled]) {
435
+ background: var(--slotted-tone-neutral-solid-hover, CanvasText);
436
+ border-color: var(--slotted-tone-neutral-solid-hover, CanvasText);
437
+ }
438
+
439
+ [data-ui='toggle-group'][data-part='root'][data-variant='chips'] [data-part='item']:disabled,
440
+ [data-ui='toggle-group'][data-part='root'][data-variant='chips']
441
+ [data-part='item'][data-disabled] {
442
+ border-color: var(--slotted-disabled-border, GrayText);
443
+ }
444
+
395
445
  /* ── Focus ────────────────────────────────────────────────────────────── */
396
446
 
397
447
  /**
@@ -31,9 +31,16 @@
31
31
  "--slotted-focus-ring-color",
32
32
  "--slotted-focus-ring-offset",
33
33
  "--slotted-focus-ring-width",
34
+ "--slotted-font-weight-medium",
35
+ "--slotted-radius-full",
36
+ "--slotted-space-3",
34
37
  "--slotted-text",
35
38
  "--slotted-toggle-group-active-background",
36
39
  "--slotted-toggle-group-border-color",
40
+ "--slotted-toggle-group-chips-gap",
41
+ "--slotted-toggle-group-chips-pressed-background",
42
+ "--slotted-toggle-group-chips-pressed-color",
43
+ "--slotted-toggle-group-chips-radius",
37
44
  "--slotted-toggle-group-color",
38
45
  "--slotted-toggle-group-disabled-border-color",
39
46
  "--slotted-toggle-group-disabled-color",
@@ -49,6 +56,9 @@
49
56
  "--slotted-tone-accent-subtle-active",
50
57
  "--slotted-tone-accent-subtle-hover",
51
58
  "--slotted-tone-accent-text",
59
+ "--slotted-tone-neutral-on-solid",
60
+ "--slotted-tone-neutral-solid",
61
+ "--slotted-tone-neutral-solid-hover",
52
62
  "--slotted-tone-secondary-subtle-active",
53
63
  "--slotted-tone-secondary-subtle-hover"
54
64
  ]