@slotted/styles 0.0.0-stage → 0.1.0-beta.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 +10 -2
- package/package.json +276 -3
- package/src/accordion/accordion.css +96 -0
- package/src/accordion/accordion.tokens.json +14 -0
- package/src/action-bar/action-bar.css +455 -0
- package/src/action-bar/action-bar.tokens.json +50 -0
- package/src/action-sheet/action-sheet.css +462 -0
- package/src/action-sheet/action-sheet.tokens.json +59 -0
- package/src/alert/alert.css +764 -0
- package/src/alert/alert.tokens.json +77 -0
- package/src/app-shell/app-shell.css +1899 -0
- package/src/app-shell/app-shell.tokens.json +88 -0
- package/src/aspect-ratio/aspect-ratio.css +131 -0
- package/src/aspect-ratio/aspect-ratio.tokens.json +1 -0
- package/src/attachment/attachment.css +906 -0
- package/src/attachment/attachment.tokens.json +85 -0
- package/src/avatar/avatar.css +598 -0
- package/src/avatar/avatar.tokens.json +64 -0
- package/src/avatar-group/avatar-group.css +268 -0
- package/src/avatar-group/avatar-group.tokens.json +16 -0
- package/src/badge/badge.css +462 -0
- package/src/badge/badge.tokens.json +58 -0
- package/src/breadcrumb/breadcrumb.css +441 -0
- package/src/breadcrumb/breadcrumb.tokens.json +50 -0
- package/src/button/button.css +754 -0
- package/src/button/button.tokens.json +72 -0
- package/src/button-group/button-group.css +455 -0
- package/src/button-group/button-group.tokens.json +11 -0
- package/src/calendar/calendar.css +846 -0
- package/src/calendar/calendar.tokens.json +67 -0
- package/src/card/card.css +602 -0
- package/src/card/card.tokens.json +68 -0
- package/src/carousel/carousel.css +860 -0
- package/src/carousel/carousel.tokens.json +62 -0
- package/src/cascader/cascader.css +1320 -0
- package/src/cascader/cascader.tokens.json +103 -0
- package/src/chart/chart.css +1473 -0
- package/src/chart/chart.tokens.json +107 -0
- package/src/checkbox/checkbox.css +1011 -0
- package/src/checkbox/checkbox.tokens.json +102 -0
- package/src/checkbox-group/checkbox-group.css +70 -0
- package/src/checkbox-group/checkbox-group.tokens.json +6 -0
- package/src/code-block/code-block.css +555 -0
- package/src/code-block/code-block.tokens.json +69 -0
- package/src/collapsible/collapsible.css +546 -0
- package/src/collapsible/collapsible.tokens.json +55 -0
- package/src/color-picker/color-picker.css +607 -0
- package/src/color-picker/color-picker.tokens.json +58 -0
- package/src/column-manager/column-manager.css +452 -0
- package/src/column-manager/column-manager.tokens.json +43 -0
- package/src/combobox/combobox.css +1048 -0
- package/src/combobox/combobox.tokens.json +112 -0
- package/src/command-palette/command-palette.css +1000 -0
- package/src/command-palette/command-palette.tokens.json +75 -0
- package/src/container/container.css +198 -0
- package/src/container/container.tokens.json +18 -0
- package/src/context-menu/context-menu.css +104 -0
- package/src/context-menu/context-menu.tokens.json +11 -0
- package/src/currency-field/currency-field.css +787 -0
- package/src/currency-field/currency-field.tokens.json +80 -0
- package/src/dashboard-grid/dashboard-grid.css +748 -0
- package/src/dashboard-grid/dashboard-grid.tokens.json +67 -0
- package/src/data-grid/data-grid.css +2484 -0
- package/src/data-grid/data-grid.tokens.json +100 -0
- package/src/data-list/data-list.css +455 -0
- package/src/data-list/data-list.tokens.json +35 -0
- package/src/date-field/date-field.css +560 -0
- package/src/date-field/date-field.tokens.json +80 -0
- package/src/date-picker/date-picker.css +420 -0
- package/src/date-picker/date-picker.tokens.json +49 -0
- package/src/date-range-picker/date-range-picker.css +983 -0
- package/src/date-range-picker/date-range-picker.tokens.json +109 -0
- package/src/datetime-field/datetime-field.css +850 -0
- package/src/datetime-field/datetime-field.tokens.json +91 -0
- package/src/datetime-picker/datetime-picker.css +843 -0
- package/src/datetime-picker/datetime-picker.tokens.json +78 -0
- package/src/datetime-range-picker/datetime-range-picker.css +1375 -0
- package/src/datetime-range-picker/datetime-range-picker.tokens.json +135 -0
- package/src/description-list/description-list.css +675 -0
- package/src/description-list/description-list.tokens.json +66 -0
- package/src/detail-panel/detail-panel.css +329 -0
- package/src/detail-panel/detail-panel.tokens.json +33 -0
- package/src/dialog/dialog.css +968 -0
- package/src/dialog/dialog.tokens.json +66 -0
- package/src/divider/divider.css +131 -0
- package/src/divider/divider.tokens.json +18 -0
- package/src/drawer/drawer.css +1303 -0
- package/src/drawer/drawer.tokens.json +75 -0
- package/src/entity-picker/entity-picker.css +1367 -0
- package/src/entity-picker/entity-picker.tokens.json +118 -0
- package/src/event-calendar/event-calendar.css +2148 -0
- package/src/event-calendar/event-calendar.tokens.json +87 -0
- package/src/field/field.css +707 -0
- package/src/field/field.tokens.json +58 -0
- package/src/field-group/field-group.css +226 -0
- package/src/field-group/field-group.tokens.json +33 -0
- package/src/filter-bar/filter-bar.css +1306 -0
- package/src/filter-bar/filter-bar.tokens.json +78 -0
- package/src/form/form.css +218 -0
- package/src/form/form.tokens.json +32 -0
- package/src/fullscreen/fullscreen.css +376 -0
- package/src/fullscreen/fullscreen.tokens.json +50 -0
- package/src/grid/grid.css +173 -0
- package/src/grid/grid.tokens.json +20 -0
- package/src/highlight/highlight.css +135 -0
- package/src/highlight/highlight.tokens.json +16 -0
- package/src/hover-card/hover-card.css +93 -0
- package/src/hover-card/hover-card.tokens.json +17 -0
- package/src/icon/icon.css +136 -0
- package/src/icon/icon.tokens.json +14 -0
- package/src/image/image.css +449 -0
- package/src/image/image.tokens.json +27 -0
- package/src/import-export-center/import-export-center.css +1175 -0
- package/src/import-export-center/import-export-center.tokens.json +84 -0
- package/src/inline/inline.css +149 -0
- package/src/inline/inline.tokens.json +14 -0
- package/src/inline-message/inline-message.css +396 -0
- package/src/inline-message/inline-message.tokens.json +19 -0
- package/src/kbd/kbd.css +490 -0
- package/src/kbd/kbd.tokens.json +40 -0
- package/src/link/link.css +237 -0
- package/src/link/link.tokens.json +25 -0
- package/src/list/list.css +240 -0
- package/src/list/list.tokens.json +42 -0
- package/src/list-item/list-item.css +937 -0
- package/src/list-item/list-item.tokens.json +114 -0
- package/src/listbox/listbox.css +674 -0
- package/src/listbox/listbox.tokens.json +72 -0
- package/src/loading-overlay/loading-overlay.css +730 -0
- package/src/loading-overlay/loading-overlay.tokens.json +48 -0
- package/src/markdown/markdown.css +168 -0
- package/src/markdown/markdown.tokens.json +18 -0
- package/src/menu/menu.css +817 -0
- package/src/menu/menu.tokens.json +78 -0
- package/src/menubar/menubar.css +170 -0
- package/src/menubar/menubar.tokens.json +32 -0
- package/src/message/message.css +1453 -0
- package/src/message/message.tokens.json +85 -0
- package/src/message-scroller/message-scroller.css +371 -0
- package/src/message-scroller/message-scroller.tokens.json +47 -0
- package/src/multi-select/multi-select.css +1427 -0
- package/src/multi-select/multi-select.tokens.json +114 -0
- package/src/navigation-menu/navigation-menu.css +1029 -0
- package/src/navigation-menu/navigation-menu.tokens.json +70 -0
- package/src/notification-center/notification-center.css +856 -0
- package/src/notification-center/notification-center.tokens.json +84 -0
- package/src/number-field/number-field.css +794 -0
- package/src/number-field/number-field.tokens.json +80 -0
- package/src/otp-input/otp-input.css +525 -0
- package/src/otp-input/otp-input.tokens.json +69 -0
- package/src/page/page.css +179 -0
- package/src/page/page.tokens.json +20 -0
- package/src/page-header/page-header.css +1181 -0
- package/src/page-header/page-header.tokens.json +71 -0
- package/src/pagination/pagination.css +500 -0
- package/src/pagination/pagination.tokens.json +56 -0
- package/src/popover/popover.css +526 -0
- package/src/popover/popover.tokens.json +60 -0
- package/src/progress-indicator/progress-indicator.css +1584 -0
- package/src/progress-indicator/progress-indicator.tokens.json +50 -0
- package/src/prompt-composer/prompt-composer.css +680 -0
- package/src/prompt-composer/prompt-composer.tokens.json +99 -0
- package/src/prose/prose.css +733 -0
- package/src/prose/prose.tokens.json +79 -0
- package/src/radio-group/radio-group.css +778 -0
- package/src/radio-group/radio-group.tokens.json +103 -0
- package/src/rating/rating.css +1071 -0
- package/src/rating/rating.tokens.json +88 -0
- package/src/result-state/result-state.css +980 -0
- package/src/result-state/result-state.tokens.json +63 -0
- package/src/runtime-properties.mjs +321 -0
- package/src/saved-views/saved-views.css +394 -0
- package/src/saved-views/saved-views.tokens.json +41 -0
- package/src/scroll-area/scroll-area.css +481 -0
- package/src/scroll-area/scroll-area.tokens.json +15 -0
- package/src/section/section.css +177 -0
- package/src/section/section.tokens.json +39 -0
- package/src/segmented-control/segmented-control.css +564 -0
- package/src/segmented-control/segmented-control.tokens.json +67 -0
- package/src/select/select.css +1593 -0
- package/src/select/select.tokens.json +110 -0
- package/src/side-navigation/side-navigation.css +1096 -0
- package/src/side-navigation/side-navigation.tokens.json +87 -0
- package/src/skeleton/skeleton.css +431 -0
- package/src/skeleton/skeleton.tokens.json +29 -0
- package/src/slider/slider.css +792 -0
- package/src/slider/slider.tokens.json +75 -0
- package/src/sparkline/sparkline.css +282 -0
- package/src/sparkline/sparkline.tokens.json +45 -0
- package/src/spinner/spinner.css +224 -0
- package/src/spinner/spinner.tokens.json +8 -0
- package/src/split-button/split-button.css +253 -0
- package/src/split-button/split-button.tokens.json +12 -0
- package/src/splitter/splitter.css +336 -0
- package/src/splitter/splitter.tokens.json +24 -0
- package/src/stack/stack.css +128 -0
- package/src/stack/stack.tokens.json +14 -0
- package/src/stat-card/stat-card.css +641 -0
- package/src/stat-card/stat-card.tokens.json +95 -0
- package/src/status-indicator/status-indicator.css +481 -0
- package/src/status-indicator/status-indicator.tokens.json +38 -0
- package/src/stepper/stepper.css +629 -0
- package/src/stepper/stepper.tokens.json +72 -0
- package/src/switch/switch.css +703 -0
- package/src/switch/switch.tokens.json +75 -0
- package/src/table/table.css +1482 -0
- package/src/table/table.tokens.json +69 -0
- package/src/table-of-contents/table-of-contents.css +533 -0
- package/src/table-of-contents/table-of-contents.tokens.json +53 -0
- package/src/tabs/tabs.css +998 -0
- package/src/tabs/tabs.tokens.json +82 -0
- package/src/tag/tag.css +768 -0
- package/src/tag/tag.tokens.json +85 -0
- package/src/tags-input/tags-input.css +757 -0
- package/src/tags-input/tags-input.tokens.json +84 -0
- package/src/text-field/text-field.css +900 -0
- package/src/text-field/text-field.tokens.json +87 -0
- package/src/textarea/textarea.css +365 -0
- package/src/textarea/textarea.tokens.json +59 -0
- package/src/time-field/time-field.css +719 -0
- package/src/time-field/time-field.tokens.json +86 -0
- package/src/time-picker/time-picker.css +665 -0
- package/src/time-picker/time-picker.tokens.json +66 -0
- package/src/time-range-picker/time-range-picker.css +1287 -0
- package/src/time-range-picker/time-range-picker.tokens.json +134 -0
- package/src/timeline/timeline.css +1596 -0
- package/src/timeline/timeline.tokens.json +96 -0
- package/src/toast/toast.css +943 -0
- package/src/toast/toast.tokens.json +90 -0
- package/src/toggle/toggle.css +290 -0
- package/src/toggle/toggle.tokens.json +54 -0
- package/src/toggle-group/toggle-group.css +463 -0
- package/src/toggle-group/toggle-group.tokens.json +54 -0
- package/src/toolbar/toolbar.css +434 -0
- package/src/toolbar/toolbar.tokens.json +49 -0
- package/src/tooltip/tooltip.css +368 -0
- package/src/tooltip/tooltip.tokens.json +39 -0
- package/src/top-navigation/top-navigation.css +1287 -0
- package/src/top-navigation/top-navigation.tokens.json +91 -0
- package/src/tour/tour.css +680 -0
- package/src/tour/tour.tokens.json +67 -0
- package/src/transfer/transfer.css +571 -0
- package/src/transfer/transfer.tokens.json +49 -0
- package/src/tree/tree.css +1000 -0
- package/src/tree/tree.tokens.json +80 -0
- package/src/typography/typography.css +211 -0
- package/src/typography/typography.tokens.json +31 -0
- package/src/upload/upload.css +1706 -0
- package/src/upload/upload.tokens.json +123 -0
- package/src/visually-hidden/visually-hidden.css +52 -0
- package/src/visually-hidden/visually-hidden.tokens.json +1 -0
- package/src/wizard/wizard.css +740 -0
- package/src/wizard/wizard.tokens.json +63 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
[
|
|
2
|
+
"--slotted-border-subtle",
|
|
3
|
+
"--slotted-border-width-thin",
|
|
4
|
+
"--slotted-calendar-active-background",
|
|
5
|
+
"--slotted-calendar-background",
|
|
6
|
+
"--slotted-calendar-cell-size",
|
|
7
|
+
"--slotted-calendar-color",
|
|
8
|
+
"--slotted-calendar-day-radius",
|
|
9
|
+
"--slotted-calendar-disabled-color",
|
|
10
|
+
"--slotted-calendar-hover-background",
|
|
11
|
+
"--slotted-calendar-in-range-color",
|
|
12
|
+
"--slotted-calendar-invalid-edge-width",
|
|
13
|
+
"--slotted-calendar-invalid-focus-ring-color",
|
|
14
|
+
"--slotted-calendar-outside-color",
|
|
15
|
+
"--slotted-calendar-preview-background",
|
|
16
|
+
"--slotted-calendar-preview-border-color",
|
|
17
|
+
"--slotted-calendar-radius",
|
|
18
|
+
"--slotted-calendar-range-active-background",
|
|
19
|
+
"--slotted-calendar-range-background",
|
|
20
|
+
"--slotted-calendar-range-border-color",
|
|
21
|
+
"--slotted-calendar-range-hover-background",
|
|
22
|
+
"--slotted-calendar-selected-background",
|
|
23
|
+
"--slotted-calendar-selected-color",
|
|
24
|
+
"--slotted-calendar-today-color",
|
|
25
|
+
"--slotted-calendar-trigger-color",
|
|
26
|
+
"--slotted-calendar-unavailable-color",
|
|
27
|
+
"--slotted-calendar-week-number-border-color",
|
|
28
|
+
"--slotted-calendar-week-number-color",
|
|
29
|
+
"--slotted-calendar-weekday-color",
|
|
30
|
+
"--slotted-control-font-family",
|
|
31
|
+
"--slotted-control-font-size-md",
|
|
32
|
+
"--slotted-control-gap-md",
|
|
33
|
+
"--slotted-control-height-md",
|
|
34
|
+
"--slotted-control-icon-size-md",
|
|
35
|
+
"--slotted-control-invalid-edge-width",
|
|
36
|
+
"--slotted-control-radius",
|
|
37
|
+
"--slotted-control-transition-duration",
|
|
38
|
+
"--slotted-control-transition-easing",
|
|
39
|
+
"--slotted-disabled-background",
|
|
40
|
+
"--slotted-disabled-foreground",
|
|
41
|
+
"--slotted-focus-ring-color",
|
|
42
|
+
"--slotted-focus-ring-color-invalid",
|
|
43
|
+
"--slotted-focus-ring-offset",
|
|
44
|
+
"--slotted-focus-ring-width",
|
|
45
|
+
"--slotted-font-size-xs",
|
|
46
|
+
"--slotted-font-weight-medium",
|
|
47
|
+
"--slotted-font-weight-regular",
|
|
48
|
+
"--slotted-font-weight-semibold",
|
|
49
|
+
"--slotted-highlight-tint-opacity",
|
|
50
|
+
"--slotted-radius-full",
|
|
51
|
+
"--slotted-radius-sm",
|
|
52
|
+
"--slotted-space-1",
|
|
53
|
+
"--slotted-space-2",
|
|
54
|
+
"--slotted-space-4",
|
|
55
|
+
"--slotted-space-6",
|
|
56
|
+
"--slotted-target-min",
|
|
57
|
+
"--slotted-text",
|
|
58
|
+
"--slotted-text-muted",
|
|
59
|
+
"--slotted-tone-accent-border",
|
|
60
|
+
"--slotted-tone-accent-on-solid",
|
|
61
|
+
"--slotted-tone-accent-solid",
|
|
62
|
+
"--slotted-tone-accent-subtle-active",
|
|
63
|
+
"--slotted-tone-accent-subtle-hover",
|
|
64
|
+
"--slotted-tone-accent-text",
|
|
65
|
+
"--slotted-tone-secondary-subtle-active",
|
|
66
|
+
"--slotted-tone-secondary-subtle-hover"
|
|
67
|
+
]
|
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
@layer slotted.components {
|
|
2
|
+
/**
|
|
3
|
+
* The surface wave 0 named. A card reads `--slotted-surface-raised` instead
|
|
4
|
+
* of painting a neutral of its own.
|
|
5
|
+
*
|
|
6
|
+
* Resting and state values are declared as custom properties, per fill, and
|
|
7
|
+
* one gated rule per state swaps them. That is what lets each fill answer a
|
|
8
|
+
* state in the property that fill is made of — an elevated card raises its
|
|
9
|
+
* shadow where an outlined card darkens its edge — instead of all three
|
|
10
|
+
* sharing one grey. It is Fluent 2's model, and the review found the library
|
|
11
|
+
* had the axis without the answers.
|
|
12
|
+
*
|
|
13
|
+
* The root does not clip. Media rounds the corners it touches and clips
|
|
14
|
+
* itself, so an overlay opened inside a card is not cut off by the card.
|
|
15
|
+
*/
|
|
16
|
+
[data-ui='card'] {
|
|
17
|
+
--_card-edge-width: var(--slotted-card-border-width, var(--slotted-border-width-thin, 1px));
|
|
18
|
+
--_card-radius: var(--slotted-card-radius, var(--slotted-radius-lg, 8px));
|
|
19
|
+
--_card-inset-block: var(--slotted-card-padding-block, var(--slotted-space-6, 1rem));
|
|
20
|
+
--_card-inset-inline: var(--slotted-card-padding-inline, var(--slotted-space-6, 1rem));
|
|
21
|
+
/* One step below the inset, never equal to it. At every size the region
|
|
22
|
+
gap used to resolve to exactly the outer inset, so the header, the body
|
|
23
|
+
and the footer sat as far from each other as from the card's own edge and
|
|
24
|
+
nothing grouped. */
|
|
25
|
+
--_card-region-gap: var(--slotted-card-region-gap, var(--slotted-space-3, 0.375rem));
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Resting, state, and current — three names, in that order, and a state
|
|
29
|
+
* value may only ever reference a resting one.
|
|
30
|
+
*
|
|
31
|
+
* Writing `--_card-edge-hover: var(--_card-edge)` to mean "hold the edge
|
|
32
|
+
* still" is a cycle: the hover rule sets `--_card-edge` from
|
|
33
|
+
* `--_card-edge-hover`. CSS resolves a cycle to the guaranteed-invalid
|
|
34
|
+
* value, the `border` shorthand becomes invalid at computed-value time, and
|
|
35
|
+
* the edge does not hold still — it disappears. Every fill that held its
|
|
36
|
+
* edge on hover lost it instead, and so did every selected card.
|
|
37
|
+
*/
|
|
38
|
+
--_card-surface-rest: var(--slotted-card-background, var(--slotted-surface-raised, Canvas));
|
|
39
|
+
--_card-edge-rest: var(--slotted-card-border-color, var(--slotted-border-subtle, ButtonBorder));
|
|
40
|
+
--_card-shadow-rest: var(--slotted-card-shadow, none);
|
|
41
|
+
|
|
42
|
+
/* What this fill answers with. Read by the gated state rules below. */
|
|
43
|
+
--_card-surface-hover: var(--_card-surface-rest);
|
|
44
|
+
--_card-edge-hover: var(
|
|
45
|
+
--slotted-card-border-color-hover,
|
|
46
|
+
var(--slotted-border-strong, ButtonBorder)
|
|
47
|
+
);
|
|
48
|
+
--_card-shadow-hover: var(--slotted-card-shadow-hover, var(--slotted-shadow-xs));
|
|
49
|
+
/* Press fills, where hover does not. Hover holding the surface still is
|
|
50
|
+
what keeps it from reading as disabled; a press is momentary and arrives
|
|
51
|
+
with the pointer already down, so the fill is unambiguous — and it is the
|
|
52
|
+
one state all three fills answer the same way, which is what makes a
|
|
53
|
+
press feel like the same gesture across a page. Fluent and Material 3
|
|
54
|
+
both darken the ground on press for every appearance they ship. */
|
|
55
|
+
--_card-surface-active: var(--slotted-tone-secondary-subtle-active);
|
|
56
|
+
--_card-edge-active: var(--_card-edge-hover);
|
|
57
|
+
--_card-shadow-active: none;
|
|
58
|
+
|
|
59
|
+
/* Current. The gated state rules below move these and nothing else. */
|
|
60
|
+
--_card-surface: var(--_card-surface-rest);
|
|
61
|
+
--_card-edge: var(--_card-edge-rest);
|
|
62
|
+
--_card-shadow: var(--_card-shadow-rest);
|
|
63
|
+
/* Disabled recedes from the raised surface. The control's disabled ground
|
|
64
|
+
is a heavier grey than a card can carry: at card area it drew more
|
|
65
|
+
attention than the operable cards around it, which is the same error as
|
|
66
|
+
filling a card with a tone surface calibrated on a badge. */
|
|
67
|
+
--_card-surface-disabled: var(
|
|
68
|
+
--slotted-card-background-disabled,
|
|
69
|
+
var(--slotted-surface-sunken, Canvas)
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
background-color: var(--_card-surface);
|
|
73
|
+
/* The ground a family inside states its own ground from — a table's rows,
|
|
74
|
+
a grid's cells — so they stand on the card and not on the page. */
|
|
75
|
+
--slotted-ground: var(--_card-surface);
|
|
76
|
+
/* The edge is drawn by `::before` over the border box, never in flow, so a
|
|
77
|
+
hairline becoming a selected 2px edge moves no text. A real border would
|
|
78
|
+
have to reserve its own width, and reserving the resting width is what
|
|
79
|
+
makes the jump shift every region by a pixel. Five of the six surveyed
|
|
80
|
+
systems that solve this solve it on a pseudo-element, three of them with
|
|
81
|
+
a comment naming the reason. */
|
|
82
|
+
border: none;
|
|
83
|
+
border-radius: var(--_card-radius);
|
|
84
|
+
box-shadow: var(--_card-shadow);
|
|
85
|
+
box-sizing: border-box;
|
|
86
|
+
color: var(--slotted-card-color, var(--slotted-text, CanvasText));
|
|
87
|
+
display: flex;
|
|
88
|
+
flex-direction: column;
|
|
89
|
+
min-inline-size: 0;
|
|
90
|
+
/* The containing block for the edge and for the stretched hit area. */
|
|
91
|
+
position: relative;
|
|
92
|
+
transition:
|
|
93
|
+
background-color var(--slotted-duration-short) var(--slotted-easing-standard),
|
|
94
|
+
box-shadow var(--slotted-duration-short) var(--slotted-easing-standard);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The edge, at every state. It is a border rather than a box-shadow so that
|
|
99
|
+
* it survives `forced-colors`, where a shadow is removed outright, and it
|
|
100
|
+
* changes width without moving a pixel of content because it is out of flow.
|
|
101
|
+
*/
|
|
102
|
+
[data-ui='card']::before {
|
|
103
|
+
border: var(--_card-edge-width) solid var(--_card-edge);
|
|
104
|
+
border-radius: inherit;
|
|
105
|
+
content: '';
|
|
106
|
+
inset: 0;
|
|
107
|
+
pointer-events: none;
|
|
108
|
+
position: absolute;
|
|
109
|
+
transition: border-color var(--slotted-duration-short) var(--slotted-easing-standard);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Density is the application's choice and governs control geometry; `size`
|
|
113
|
+
is this card's own inset, so a summary card and a card in a dense list can
|
|
114
|
+
stand on the same page. */
|
|
115
|
+
[data-ui='card'][data-size='sm'] {
|
|
116
|
+
--_card-inset-block: var(--slotted-card-padding-block-sm, var(--slotted-space-5, 0.75rem));
|
|
117
|
+
--_card-inset-inline: var(--slotted-card-padding-inline-sm, var(--slotted-space-5, 0.75rem));
|
|
118
|
+
--_card-region-gap: var(--slotted-card-region-gap-sm, var(--slotted-space-2, 0.25rem));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
[data-ui='card'][data-size='lg'] {
|
|
122
|
+
--_card-inset-block: var(--slotted-card-padding-block-lg, var(--slotted-space-8, 1.5rem));
|
|
123
|
+
--_card-inset-inline: var(--slotted-card-padding-inline-lg, var(--slotted-space-8, 1.5rem));
|
|
124
|
+
--_card-region-gap: var(--slotted-card-region-gap-lg, var(--slotted-space-4, 0.5rem));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Three ways to bound a surface, and a page uses more than one: a grid of
|
|
129
|
+
* outlined list cards, a summary that lifts off the page, and a filled block
|
|
130
|
+
* that recedes into it.
|
|
131
|
+
*
|
|
132
|
+
* `elevated` rests at the medium step. The small step under a hairline does
|
|
133
|
+
* not separate on a white page, and `0 1px 3px rgb(0 0 0 / 0.5)` on a
|
|
134
|
+
* near-black one is invisible, so `elevated` and `outline` were one picture
|
|
135
|
+
* in both schemes. It keeps its hairline, because a shadow is removed under
|
|
136
|
+
* forced colours and an edge is not.
|
|
137
|
+
*/
|
|
138
|
+
[data-ui='card'][data-fill='elevated'] {
|
|
139
|
+
--_card-shadow-rest: var(--slotted-card-shadow, var(--slotted-shadow-md));
|
|
140
|
+
/* The shadow moves and the edge holds still: elevation is what this fill
|
|
141
|
+
is made of. */
|
|
142
|
+
--_card-edge-hover: var(--_card-edge-rest);
|
|
143
|
+
--_card-shadow-hover: var(--slotted-card-shadow-hover, var(--slotted-shadow-lg));
|
|
144
|
+
--_card-edge-active: var(--_card-edge-rest);
|
|
145
|
+
/* The elevation falls back under the finger rather than to nothing: an
|
|
146
|
+
elevated card that flattens completely reads as removed, not pressed. */
|
|
147
|
+
--_card-shadow-active: var(--slotted-shadow-sm);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* `subtle` is a fill, and it keeps the same hairline the outlined card has.
|
|
152
|
+
*
|
|
153
|
+
* Dropping the edge was tried, on Fluent's rule for the same appearance —
|
|
154
|
+
* "similar to filled-alternative, but no border is applied" — and reverted.
|
|
155
|
+
* Fluent's subtle background differs from its page; the high-contrast scheme
|
|
156
|
+
* here paints `--slotted-surface-sunken` and `--slotted-surface` the same
|
|
157
|
+
* white, so an edgeless subtle card had neither fill nor edge and stopped
|
|
158
|
+
* being a card at all. A hairline that reads as slightly redundant in two
|
|
159
|
+
* schemes fails more loudly than a card that disappears in the third.
|
|
160
|
+
*/
|
|
161
|
+
[data-ui='card'][data-fill='subtle'] {
|
|
162
|
+
--_card-surface-rest: var(
|
|
163
|
+
--slotted-card-background-subtle,
|
|
164
|
+
var(--slotted-surface-sunken, Canvas)
|
|
165
|
+
);
|
|
166
|
+
/* The fill is what this variant is made of, so the fill is what moves —
|
|
167
|
+
toward the raised surface, which is a card coming forward rather than a
|
|
168
|
+
card greying out. The edge holds still. */
|
|
169
|
+
--_card-surface-hover: var(--slotted-surface-raised, Canvas);
|
|
170
|
+
--_card-edge-hover: var(--_card-edge-rest);
|
|
171
|
+
--_card-shadow-hover: none;
|
|
172
|
+
--_card-surface-active: var(--slotted-tone-secondary-subtle-active);
|
|
173
|
+
--_card-edge-active: var(--_card-edge-rest);
|
|
174
|
+
/* This fill already rests on the sunken surface, so receding onto it would
|
|
175
|
+
leave a disabled card and an operable one the same picture. It is the one
|
|
176
|
+
fill that takes the control's disabled ground. */
|
|
177
|
+
--_card-surface-disabled: var(
|
|
178
|
+
--slotted-card-background-disabled,
|
|
179
|
+
var(--slotted-disabled-background, Canvas)
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* A card is interactive when it holds a destination or a choice. Every state
|
|
185
|
+
* below was previously gated on `[data-part='link']` alone, so the chooser —
|
|
186
|
+
* a `<label>` around a native input, which is the whole-card selection this
|
|
187
|
+
* family documents — answered no hover, no press and no ring.
|
|
188
|
+
*
|
|
189
|
+
* The two guards are the state precedence: a disabled card does not answer
|
|
190
|
+
* the pointer, and neither does a card whose only control is disabled.
|
|
191
|
+
*/
|
|
192
|
+
[data-ui='card']:not([data-disabled]):has(
|
|
193
|
+
:is([data-part='link'], [data-part='selection'] :is(input, button)):not(:disabled)
|
|
194
|
+
):hover {
|
|
195
|
+
--_card-surface: var(--_card-surface-hover);
|
|
196
|
+
--_card-edge: var(--_card-edge-hover);
|
|
197
|
+
--_card-shadow: var(--_card-shadow-hover);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* A card that resolves somewhere or holds a choice is a target, and the
|
|
202
|
+
* pointer says so over the whole surface. The link's own hit area already
|
|
203
|
+
* carried the pointer, so only the chooser was left with the default arrow
|
|
204
|
+
* over a surface that is entirely clickable.
|
|
205
|
+
*
|
|
206
|
+
* Descendants inherit it rather than reverting to a text caret: the surface
|
|
207
|
+
* is one target, and a caret over it offers a selection the `<label>` will
|
|
208
|
+
* not make. Anything a consumer raises above the hit area — `actions`, the
|
|
209
|
+
* `footer` — sets its own cursor, because it is its own target.
|
|
210
|
+
*/
|
|
211
|
+
[data-ui='card']:not([data-disabled]):has(
|
|
212
|
+
:is([data-part='link'], [data-part='selection'] :is(input, button)):not(:disabled)
|
|
213
|
+
) {
|
|
214
|
+
cursor: pointer;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
[data-ui='card']:not([data-disabled]):has(
|
|
218
|
+
[data-part='selection'] :is(input, button):not(:disabled)
|
|
219
|
+
)
|
|
220
|
+
:where(*) {
|
|
221
|
+
cursor: inherit;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
[data-ui='card']:not([data-disabled]):has(
|
|
225
|
+
:is([data-part='link'], [data-part='selection'] :is(input, button)):not(:disabled)
|
|
226
|
+
):active {
|
|
227
|
+
--_card-surface: var(--_card-surface-active);
|
|
228
|
+
--_card-edge: var(--_card-edge-active);
|
|
229
|
+
--_card-shadow: var(--_card-shadow-active);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Vertical rhythm is carried by each region's own block padding rather than
|
|
234
|
+
* by a gap on the root, which is what lets an absent region collapse to
|
|
235
|
+
* nothing instead of leaving its gap behind — the case a three-region layout
|
|
236
|
+
* usually gets wrong.
|
|
237
|
+
*/
|
|
238
|
+
[data-ui='card'] > :is([data-part='header'], [data-part='body'], [data-part='footer']) {
|
|
239
|
+
min-inline-size: 0;
|
|
240
|
+
padding-block: var(--_card-region-gap);
|
|
241
|
+
padding-inline: var(--_card-inset-inline);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* A region at either end absorbs the padding its missing neighbour would
|
|
245
|
+
have carried, so a card of only a body is not visibly tighter than a full
|
|
246
|
+
one. Media bleeds, so the region next to it counts as an end. */
|
|
247
|
+
[data-ui='card']
|
|
248
|
+
> :is([data-part='header'], [data-part='body'], [data-part='footer']):first-child,
|
|
249
|
+
[data-ui='card']
|
|
250
|
+
> [data-part='media']
|
|
251
|
+
+ :is([data-part='header'], [data-part='body'], [data-part='footer']) {
|
|
252
|
+
padding-block-start: var(--_card-inset-block);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
[data-ui='card'] > :is([data-part='header'], [data-part='body'], [data-part='footer']):last-child,
|
|
256
|
+
[data-ui='card']
|
|
257
|
+
> :is([data-part='header'], [data-part='body'], [data-part='footer']):has(
|
|
258
|
+
+ [data-part='media']
|
|
259
|
+
) {
|
|
260
|
+
padding-block-end: var(--_card-inset-block);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* The header stacks a title and the line that supports it in the first
|
|
265
|
+
* column, and keeps a second column for whatever belongs in the corner: a
|
|
266
|
+
* badge, a status, a menu button. Both are Typography and both are the
|
|
267
|
+
* consumer's, so the header decides only the two distances and the corner.
|
|
268
|
+
*/
|
|
269
|
+
[data-ui='card'] > [data-part='header'] {
|
|
270
|
+
align-items: start;
|
|
271
|
+
column-gap: var(--slotted-card-header-column-gap, var(--slotted-space-5, 0.75rem));
|
|
272
|
+
display: grid;
|
|
273
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
274
|
+
row-gap: var(--slotted-card-header-gap, var(--slotted-space-2, 0.25rem));
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
[data-ui='card'] > [data-part='header'] > * {
|
|
278
|
+
grid-column: 1;
|
|
279
|
+
min-inline-size: 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* The corner. It stays on the first row, so a title that wraps to two lines
|
|
283
|
+
does not drag the badge down with it, and it takes the last column whether
|
|
284
|
+
the header has two or three. */
|
|
285
|
+
[data-ui='card'] > [data-part='header'] > [data-part='actions'] {
|
|
286
|
+
align-items: center;
|
|
287
|
+
display: flex;
|
|
288
|
+
flex-wrap: wrap;
|
|
289
|
+
/* Centred on the title's own row rather than on the row's start edge: a
|
|
290
|
+
badge aligned to the line box sits optically high against cap height. */
|
|
291
|
+
align-self: center;
|
|
292
|
+
gap: var(--slotted-card-actions-gap, var(--slotted-space-3, 0.375rem));
|
|
293
|
+
grid-column: -2 / -1;
|
|
294
|
+
grid-row: 1;
|
|
295
|
+
/* Above the stretched hit area, like the footer: a control in the corner
|
|
296
|
+
of a card that resolves elsewhere still has to be operable. */
|
|
297
|
+
position: relative;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* The place a choice card keeps for its control. It is the slot and not the
|
|
302
|
+
* glyph: `checkbox radio-group` owns where a check and a dot are drawn, and a
|
|
303
|
+
* card drawing its own would be the second answer to that question.
|
|
304
|
+
*
|
|
305
|
+
* It leads rather than trails, because `actions` already owns the corner.
|
|
306
|
+
* Spectrum and Mantine put selection at the inline start for the same reason;
|
|
307
|
+
* Carbon, Fluent and Cloudscape trail only because none of them keeps a
|
|
308
|
+
* corner in the header.
|
|
309
|
+
*/
|
|
310
|
+
[data-ui='card'] > [data-part='header']:has([data-part='selection']) {
|
|
311
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
[data-ui='card'] > [data-part='header']:has([data-part='selection']) > * {
|
|
315
|
+
grid-column: 2;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
[data-ui='card'] > [data-part='header'] > [data-part='selection'] {
|
|
319
|
+
/**
|
|
320
|
+
* On the title's first line, not in the middle of its block (C1, the rule
|
|
321
|
+
* R5 gives every mark beside a title): the slot is one line of the title's
|
|
322
|
+
* step tall and centres the control inside it, so a title that wraps to
|
|
323
|
+
* two lines keeps its control beside the first. The step is the large one,
|
|
324
|
+
* which is the title a card header holds; a header set at another step
|
|
325
|
+
* retunes the line with the family token.
|
|
326
|
+
*/
|
|
327
|
+
--_selection-line: var(
|
|
328
|
+
--slotted-card-selection-line,
|
|
329
|
+
calc(var(--slotted-font-size-lg, 1rem) * var(--slotted-line-height-lg, 1.5))
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
align-items: center;
|
|
333
|
+
align-self: start;
|
|
334
|
+
block-size: var(--_selection-line);
|
|
335
|
+
display: flex;
|
|
336
|
+
grid-column: 1;
|
|
337
|
+
grid-row: 1;
|
|
338
|
+
/* Above the stretched hit area: a card holding a choice is not a
|
|
339
|
+
destination, but a consumer may still raise something over the surface. */
|
|
340
|
+
position: relative;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* The control is the selection scale's square, the one `checkbox` and
|
|
345
|
+
* `radio-group` draw in, and it does not follow density: the control glyph
|
|
346
|
+
* scale it read before fell to thirteen pixels at `dense`, and a chooser
|
|
347
|
+
* smaller than the check beside it in the same form was two answers.
|
|
348
|
+
*
|
|
349
|
+
* The card sizes and places the control and paints none of it. Tinting it
|
|
350
|
+
* with `accent-color` was tried and reverted: the accent is a dark blue, so
|
|
351
|
+
* on a dark card the platform had to draw its mark and ring in white against
|
|
352
|
+
* it, and the checked radio came out ringed in white — brighter than the
|
|
353
|
+
* card's own selected edge. Left alone, the control follows `color-scheme`
|
|
354
|
+
* and reads correctly in both. It is the same boundary the part is drawn on:
|
|
355
|
+
* `checkbox radio-group` owns what the control looks like, and a brand-tinted
|
|
356
|
+
* check arrives with the family that owns the geometry.
|
|
357
|
+
*
|
|
358
|
+
* The control's box is below the WCAG minimum target on its own. The target
|
|
359
|
+
* is the card: the surface is the `<label>`, so the hit area is the whole
|
|
360
|
+
* card, which is the correction the token foundation asks a family to make.
|
|
361
|
+
*/
|
|
362
|
+
[data-ui='card'] > [data-part='header'] > [data-part='selection'] > :is(input, button) {
|
|
363
|
+
block-size: var(--slotted-card-selection-size, var(--slotted-selection-size-md, 16px));
|
|
364
|
+
inline-size: var(--slotted-card-selection-size, var(--slotted-selection-size-md, 16px));
|
|
365
|
+
margin: 0;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* Cards stretched to a common height in a grid keep their footers on one
|
|
369
|
+
line, because the body takes the leftover. */
|
|
370
|
+
[data-ui='card'] > [data-part='body'] {
|
|
371
|
+
flex: 1 1 auto;
|
|
372
|
+
min-block-size: 0;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
[data-ui='card'] > [data-part='footer'] {
|
|
376
|
+
align-items: center;
|
|
377
|
+
display: flex;
|
|
378
|
+
flex-wrap: wrap;
|
|
379
|
+
gap: var(--slotted-card-footer-gap, var(--slotted-space-4, 0.5rem));
|
|
380
|
+
/* Above the stretched hit area: a secondary action belongs in the footer
|
|
381
|
+
and has to stay operable while the card resolves to somewhere else. */
|
|
382
|
+
position: relative;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* A rule between two regions is a Divider written between them, not an axis
|
|
387
|
+
* of this family. It runs edge to edge because the region padding is the
|
|
388
|
+
* region's own, and `inset` on the rule lines it up with the text instead.
|
|
389
|
+
* The regions on either side keep the distance they already had.
|
|
390
|
+
*/
|
|
391
|
+
[data-ui='card'] > [data-ui='divider'] {
|
|
392
|
+
flex-shrink: 0;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
[data-ui='card'][data-orientation='horizontal'] > [data-ui='divider'] {
|
|
396
|
+
grid-column: 2;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
[data-ui='card'] > [data-part='media'] {
|
|
400
|
+
display: block;
|
|
401
|
+
min-inline-size: 0;
|
|
402
|
+
overflow: hidden;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
[data-ui='card'] > [data-part='media'] > :is(img, video, canvas, picture, svg) {
|
|
406
|
+
block-size: 100%;
|
|
407
|
+
display: block;
|
|
408
|
+
inline-size: 100%;
|
|
409
|
+
object-fit: cover;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/* The media rounds the corners it touches and no others. The radius is the
|
|
413
|
+
card's own, less the edge it sits inside. */
|
|
414
|
+
[data-ui='card'] > [data-part='media']:first-child {
|
|
415
|
+
border-start-end-radius: var(--_card-radius);
|
|
416
|
+
border-start-start-radius: var(--_card-radius);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
[data-ui='card'] > [data-part='media']:last-child {
|
|
420
|
+
border-end-end-radius: var(--_card-radius);
|
|
421
|
+
border-end-start-radius: var(--_card-radius);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* A horizontal card is a grid of two columns and four rows: the media takes
|
|
426
|
+
* the first column across every row, and the three regions take rows one to
|
|
427
|
+
* three of the second. The fourth row is empty until the card reflows, and
|
|
428
|
+
* an empty row costs nothing because the rhythm is padding, not a gap.
|
|
429
|
+
*/
|
|
430
|
+
[data-ui='card'][data-orientation='horizontal'] {
|
|
431
|
+
container-name: slotted-card;
|
|
432
|
+
container-type: inline-size;
|
|
433
|
+
display: grid;
|
|
434
|
+
/* A card that reflows on its own inline size cannot also be sized by its
|
|
435
|
+
content: `container-type` removes the inline contribution, so a
|
|
436
|
+
horizontal card in a flex row would collapse to one word per line. It
|
|
437
|
+
fills the inline size it is given instead, and shrinks with its row. */
|
|
438
|
+
inline-size: 100%;
|
|
439
|
+
/* A ratio rather than a length: a card decides how much of itself the
|
|
440
|
+
media may take, and a theme that wants a fixed strip sets the token to
|
|
441
|
+
one. Neither is a scale the family invents. */
|
|
442
|
+
grid-template-columns: var(--slotted-card-media-size, minmax(0, 1fr)) minmax(0, 2fr);
|
|
443
|
+
grid-template-rows: repeat(4, auto);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
[data-ui='card'][data-orientation='horizontal'] > [data-part='media'] {
|
|
447
|
+
border-end-end-radius: 0;
|
|
448
|
+
border-end-start-radius: var(--_card-radius);
|
|
449
|
+
border-start-end-radius: 0;
|
|
450
|
+
border-start-start-radius: var(--_card-radius);
|
|
451
|
+
grid-area: 1 / 1 / -1 / 2;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
[data-ui='card'][data-orientation='horizontal'] > [data-part='header'] {
|
|
455
|
+
grid-area: 1 / 2;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
[data-ui='card'][data-orientation='horizontal'] > [data-part='body'] {
|
|
459
|
+
grid-area: 2 / 2;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
[data-ui='card'][data-orientation='horizontal'] > [data-part='footer'] {
|
|
463
|
+
grid-area: 3 / 2;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* The card answers its own inline size, not the viewport's. Below the
|
|
468
|
+
* breakpoint every part spans both columns, which collapses the media
|
|
469
|
+
* column and returns the media to the top of a single column. The value is
|
|
470
|
+
* a literal because CSS forbids a custom property in a container condition.
|
|
471
|
+
*/
|
|
472
|
+
@container slotted-card (max-inline-size: 24rem) {
|
|
473
|
+
[data-ui='card'][data-orientation='horizontal'] > [data-part='media'] {
|
|
474
|
+
border-end-start-radius: 0;
|
|
475
|
+
border-start-end-radius: var(--_card-radius);
|
|
476
|
+
grid-area: 1 / 1 / 2 / -1;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
[data-ui='card'][data-orientation='horizontal'] > [data-part='header'] {
|
|
480
|
+
grid-area: 2 / 1 / 3 / -1;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
[data-ui='card'][data-orientation='horizontal'] > [data-part='body'] {
|
|
484
|
+
grid-area: 3 / 1 / 4 / -1;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
[data-ui='card'][data-orientation='horizontal'] > [data-part='footer'] {
|
|
488
|
+
grid-area: 4 / 1 / 5 / -1;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* A card that resolves to one destination stretches that anchor's hit area
|
|
494
|
+
* across the whole surface. The element stays an `<a href>`, so the name,
|
|
495
|
+
* Enter, the context menu and middle-click are the platform's, and the name
|
|
496
|
+
* is the title rather than every string in the card.
|
|
497
|
+
*/
|
|
498
|
+
[data-ui='card'] [data-part='link']::after {
|
|
499
|
+
content: '';
|
|
500
|
+
inset: 0;
|
|
501
|
+
position: absolute;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Focus keeps the accent and stays outside the card; selection takes the
|
|
506
|
+
* inverse surface and sits on the edge. In this theme
|
|
507
|
+
* `--slotted-focus-ring-color` and `--slotted-tone-accent-border` resolve to
|
|
508
|
+
* the same hex, so a selected card and a focused card were the same image.
|
|
509
|
+
* They now differ in colour, in width and in position.
|
|
510
|
+
*/
|
|
511
|
+
[data-ui='card']:has(
|
|
512
|
+
:is([data-part='link'], [data-part='selection'] :is(input, button)):focus-visible
|
|
513
|
+
) {
|
|
514
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
515
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Written inside `:has()` on purpose: a browser without it drops the whole
|
|
520
|
+
* rule and keeps the native outline, rather than removing the only ring.
|
|
521
|
+
*
|
|
522
|
+
* The control's own ring goes for the same reason the link's does. The card
|
|
523
|
+
* is the label and the click target, so the card is what the ring is about;
|
|
524
|
+
* drawing both left a ring around a 16px radio inside a ring around the whole
|
|
525
|
+
* surface. Carbon and Fluent avoid the pair by hiding the control outright,
|
|
526
|
+
* which is not open here — the control is meant to be seen.
|
|
527
|
+
*/
|
|
528
|
+
[data-ui='card']:has([data-part='link']) [data-part='link']:focus-visible,
|
|
529
|
+
[data-ui='card']:has([data-part='selection'])
|
|
530
|
+
[data-part='selection']
|
|
531
|
+
:is(input, button):focus-visible {
|
|
532
|
+
outline: none;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Selection is the accent surface under a one-pixel accent edge (C1, by R1:
|
|
537
|
+
* `selected` is the `accent-subtle` ground, never a rail or a heavier
|
|
538
|
+
* stroke), the same pair `list-item` paints on a selected row, so a chosen
|
|
539
|
+
* card and a chosen row in one page are one state. The edge keeps the
|
|
540
|
+
* resting width; the ground is what says chosen.
|
|
541
|
+
*
|
|
542
|
+
* The `high-contrast` scheme paints the accent surface white and the accent
|
|
543
|
+
* edge black, like every other border, so there the card itself says
|
|
544
|
+
* nothing — and does not have to: the control inside is checked, and the
|
|
545
|
+
* check is what carries the state, as it does for assistive technology. The
|
|
546
|
+
* inverse-surface edge this replaced survived that scheme by being thicker,
|
|
547
|
+
* and was the rail R1 removes.
|
|
548
|
+
*
|
|
549
|
+
* A selected card still answers the pointer: the ground steps to the
|
|
550
|
+
* accent's hover and active tints, as a selected row's does, and the edge
|
|
551
|
+
* holds, because it is already saying the stronger thing.
|
|
552
|
+
*/
|
|
553
|
+
[data-ui='card'][data-selected] {
|
|
554
|
+
--_card-surface-rest: var(
|
|
555
|
+
--slotted-card-background-selected,
|
|
556
|
+
var(--slotted-tone-accent-surface, Canvas)
|
|
557
|
+
);
|
|
558
|
+
--_card-surface-hover: var(
|
|
559
|
+
--slotted-card-background-selected-hover,
|
|
560
|
+
var(--slotted-tone-accent-subtle-hover, Canvas)
|
|
561
|
+
);
|
|
562
|
+
--_card-surface-active: var(
|
|
563
|
+
--slotted-card-background-selected-active,
|
|
564
|
+
var(--slotted-tone-accent-subtle-active, Canvas)
|
|
565
|
+
);
|
|
566
|
+
--_card-edge-rest: var(
|
|
567
|
+
--slotted-card-edge-color-selected,
|
|
568
|
+
var(--slotted-tone-accent-border, CanvasText)
|
|
569
|
+
);
|
|
570
|
+
--_card-edge: var(--_card-edge-rest);
|
|
571
|
+
--_card-edge-hover: var(--_card-edge-rest);
|
|
572
|
+
--_card-edge-active: var(--_card-edge-rest);
|
|
573
|
+
--_card-edge-width: var(
|
|
574
|
+
--slotted-card-edge-width-selected,
|
|
575
|
+
var(--slotted-border-width-thin, 1px)
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Disabled is answered per fill like every other state: the two that rest on
|
|
581
|
+
* the raised surface recede onto the sunken one, and the fill already resting
|
|
582
|
+
* there takes the control's disabled ground instead. The edge and the text
|
|
583
|
+
* mute in every case, and the elevation drops to nothing — a card that cannot
|
|
584
|
+
* be used does not float above the page.
|
|
585
|
+
*/
|
|
586
|
+
[data-ui='card'][data-disabled] {
|
|
587
|
+
--_card-surface: var(--_card-surface-disabled);
|
|
588
|
+
--_card-edge: var(
|
|
589
|
+
--slotted-card-border-color-disabled,
|
|
590
|
+
var(--slotted-disabled-border, GrayText)
|
|
591
|
+
);
|
|
592
|
+
--_card-shadow: none;
|
|
593
|
+
|
|
594
|
+
color: var(--slotted-card-color-disabled, var(--slotted-disabled-foreground, GrayText));
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/* The card withdraws the hit area it added. Disabling the control itself is
|
|
598
|
+
the consumer's, because only the control can refuse an interaction. */
|
|
599
|
+
[data-ui='card'][data-disabled] [data-part='link']::after {
|
|
600
|
+
display: none;
|
|
601
|
+
}
|
|
602
|
+
}
|