@slotted/styles 0.0.0-stage → 0.1.0-beta.0
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,1596 @@
|
|
|
1
|
+
@layer slotted.components {
|
|
2
|
+
/**
|
|
3
|
+
* An ordered list of events on one line, each with a marker, a machine
|
|
4
|
+
* timestamp and a body — and, in feed mode, the APG Feed pattern drawn the
|
|
5
|
+
* same way.
|
|
6
|
+
*
|
|
7
|
+
* The whole family is drawn from the control glyph size. An empty marker is
|
|
8
|
+
* a dot as large as the glyph a badge holds, so a dot, a spinner and the
|
|
9
|
+
* glyph inside a badge are one size; a marker holding a glyph is a badge the
|
|
10
|
+
* control icon wide plus one step of air on each side, and a marker holding
|
|
11
|
+
* an avatar is the smallest avatar. The rail is a
|
|
12
|
+
* column as wide as the widest marker the timeline holds. The connector is a
|
|
13
|
+
* hairline that runs from the centre of one marker to the centre of the
|
|
14
|
+
* next. Everything else — how far the words stand off the rail, the rhythm
|
|
15
|
+
* between events — is the control gap plus a step, so density moves the
|
|
16
|
+
* whole timeline together.
|
|
17
|
+
*
|
|
18
|
+
* Every width a centre depends on — the dot, its core, the badge, the rail —
|
|
19
|
+
* is the line's own width plus an even number of pixels, rounded up to it.
|
|
20
|
+
* The line then stands a whole number of pixels inside each of them. An
|
|
21
|
+
* eight-pixel dot on a one-pixel line put the line three and a half pixels
|
|
22
|
+
* in, the browser rounded the half to a whole CSS pixel, and the line was
|
|
23
|
+
* drawn one device pixel off the dot's centre at 100%, 150% and 200%.
|
|
24
|
+
*/
|
|
25
|
+
[data-ui='timeline'] {
|
|
26
|
+
--_icon: var(--slotted-control-icon-size-md, 16px);
|
|
27
|
+
--_font-size: var(--slotted-timeline-font-size, var(--slotted-control-font-size-md, 13px));
|
|
28
|
+
/**
|
|
29
|
+
* The actor, the description, the group heading and the two pills: the
|
|
30
|
+
* title's size, told apart from it by weight and ink. A fixed
|
|
31
|
+
* `--slotted-font-size-sm` stood a description of 13 under a title of 12
|
|
32
|
+
* at `sm` and in the tighter densities, and its 19.5-pixel line put every
|
|
33
|
+
* event after the first at half a pixel.
|
|
34
|
+
*/
|
|
35
|
+
--_meta-size: var(--slotted-timeline-meta-font-size, var(--_font-size));
|
|
36
|
+
/* The control gap and one step more: a mark eight pixels from a word reads as touching it. */
|
|
37
|
+
--_gap: var(
|
|
38
|
+
--slotted-timeline-gap,
|
|
39
|
+
calc(var(--slotted-control-gap-md, 8px) + var(--slotted-space-2, 0.25rem))
|
|
40
|
+
);
|
|
41
|
+
/* The glyph a badge holds, and the size of a dot and of a spinner: the glyph less a step of air a side. */
|
|
42
|
+
--_glyph: calc(var(--_icon) - 2 * var(--slotted-space-1, 0.125rem));
|
|
43
|
+
--_dot: calc(var(--_rule) + round(up, var(--_glyph) - var(--_rule), 2px));
|
|
44
|
+
/* The solid centre of a dot, a proportion of it: the literal the contract records. */
|
|
45
|
+
--_core: calc(
|
|
46
|
+
var(--_rule) +
|
|
47
|
+
round(nearest, var(--_dot) * var(--slotted-timeline-core-ratio, 0.4) - var(--_rule), 2px)
|
|
48
|
+
);
|
|
49
|
+
/* The badge around a glyph: the control icon and one step of air on each side, 21 at `md`. */
|
|
50
|
+
--_badge: calc(
|
|
51
|
+
var(--_rule) +
|
|
52
|
+
round(up, var(--_icon) + 2 * var(--slotted-space-1, 0.125rem) - var(--_rule), 2px)
|
|
53
|
+
);
|
|
54
|
+
/**
|
|
55
|
+
* A face in the marker: the smallest avatar, rounded to the line's parity.
|
|
56
|
+
* The badge's 21 put the initials at 8.4 pixels, under
|
|
57
|
+
* `--slotted-avatar-size-xs`, the smallest step `avatar` draws; this is 25
|
|
58
|
+
* at comfortable density and 21 at the two tighter ones, where that step
|
|
59
|
+
* is 20.
|
|
60
|
+
*/
|
|
61
|
+
--_avatar: calc(
|
|
62
|
+
var(--_rule) + round(up, var(--slotted-avatar-size-xs, 24px) - var(--_rule), 2px)
|
|
63
|
+
);
|
|
64
|
+
--_rail: var(--_dot);
|
|
65
|
+
--_rule: var(--slotted-timeline-connector-thickness, var(--slotted-border-width-thin, 1px));
|
|
66
|
+
/* The ring of a hollow dot, and of the halo around the current one. */
|
|
67
|
+
--_edge: var(--slotted-border-width-medium, 1.5px);
|
|
68
|
+
/* How far the current ring stands outside its marker. */
|
|
69
|
+
--_reach: calc(var(--_edge) + var(--slotted-border-width-thick, 2px));
|
|
70
|
+
/* The gap and one step more, so the rhythm between events tightens with density. */
|
|
71
|
+
--_item-gap: var(
|
|
72
|
+
--slotted-timeline-item-gap,
|
|
73
|
+
calc(var(--_gap) + var(--slotted-space-2, 0.25rem))
|
|
74
|
+
);
|
|
75
|
+
/* The air the line leaves around each marker, drawn as a halo of the ground. */
|
|
76
|
+
--_line-gap: var(--slotted-timeline-line-gap, var(--slotted-space-1, 0.125rem));
|
|
77
|
+
--_opposite: var(--slotted-timeline-opposite-size, 8rem);
|
|
78
|
+
--_line-height: var(--slotted-timeline-line-height, var(--slotted-line-height-md, 1.5));
|
|
79
|
+
/**
|
|
80
|
+
* The ratio set in whole pixels: 20 at `md` rather than 19.5. Every event
|
|
81
|
+
* is a stack of these lines, and a one-line event of 19.5 put the next
|
|
82
|
+
* event, its marker and its ring at half a pixel.
|
|
83
|
+
*/
|
|
84
|
+
--_leading: round(up, calc(var(--_font-size) * var(--_line-height)), 1px);
|
|
85
|
+
--_muted: var(--slotted-timeline-color-muted, var(--slotted-text-muted, GrayText));
|
|
86
|
+
--_strong: var(--slotted-timeline-color, var(--slotted-text, CanvasText));
|
|
87
|
+
/**
|
|
88
|
+
* The track is decoration and may be faint; the marker's ring is the
|
|
89
|
+
* frame of the mark itself and holds the 3:1 a non-text element needs —
|
|
90
|
+
* the split `stepper` records for the same two parts.
|
|
91
|
+
*/
|
|
92
|
+
--_line: var(--slotted-timeline-connector-color, var(--slotted-border-subtle, GrayText));
|
|
93
|
+
--_ring: var(
|
|
94
|
+
--slotted-timeline-marker-border,
|
|
95
|
+
var(--slotted-control-border-color, ButtonBorder)
|
|
96
|
+
);
|
|
97
|
+
--_surface: var(--slotted-timeline-marker-surface, var(--slotted-surface, Canvas));
|
|
98
|
+
|
|
99
|
+
color: var(--_strong);
|
|
100
|
+
container-name: slotted-timeline;
|
|
101
|
+
container-type: inline-size;
|
|
102
|
+
display: block;
|
|
103
|
+
font-family: var(--slotted-timeline-font-family, var(--slotted-font-family-sans, inherit));
|
|
104
|
+
font-size: var(--_font-size);
|
|
105
|
+
line-height: var(--_leading);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
[data-ui='timeline'][data-size='sm'] {
|
|
109
|
+
--_icon: var(--slotted-control-icon-size-sm, 14px);
|
|
110
|
+
--_font-size: var(--slotted-timeline-font-size, var(--slotted-control-font-size-sm, 12px));
|
|
111
|
+
--_gap: var(
|
|
112
|
+
--slotted-timeline-gap,
|
|
113
|
+
calc(var(--slotted-control-gap-sm, 6px) + var(--slotted-space-2, 0.25rem))
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
[data-ui='timeline'][data-size='lg'] {
|
|
118
|
+
--_icon: var(--slotted-control-icon-size-lg, 18px);
|
|
119
|
+
--_font-size: var(--slotted-timeline-font-size, var(--slotted-control-font-size-lg, 14px));
|
|
120
|
+
--_gap: var(
|
|
121
|
+
--slotted-timeline-gap,
|
|
122
|
+
calc(var(--slotted-control-gap-lg, 8px) + var(--slotted-space-2, 0.25rem))
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* One badge anywhere widens the rail everywhere, groups included, so the
|
|
128
|
+
* dots of the plain events stay on the same centre as the badge and every
|
|
129
|
+
* title starts at the same indent. A spinner and the check of a finished
|
|
130
|
+
* dot are a dot's size and widen nothing.
|
|
131
|
+
*/
|
|
132
|
+
[data-ui='timeline']:has([data-part='marker'] > :not([data-ui='spinner'], [data-check])) {
|
|
133
|
+
--_rail: var(--_badge);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
[data-ui='timeline']:has([data-part='marker'] > [data-ui='avatar']) {
|
|
137
|
+
--_rail: max(var(--_badge), var(--_avatar));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* ── Tone ───────────────────────────────────────────────────────────────
|
|
141
|
+
*
|
|
142
|
+
* Five tones, each read on the item so one event can be a failure in a list
|
|
143
|
+
* of successes. The root states the tone every item starts from, and an
|
|
144
|
+
* item that names its own wins by being nearer.
|
|
145
|
+
*/
|
|
146
|
+
|
|
147
|
+
[data-ui='timeline'],
|
|
148
|
+
[data-ui='timeline'] [data-tone='secondary'] {
|
|
149
|
+
--_tone-solid: var(--slotted-tone-secondary-solid, ButtonFace);
|
|
150
|
+
--_tone-on-solid: var(--slotted-tone-secondary-on-solid, ButtonText);
|
|
151
|
+
--_tone-surface: var(--slotted-tone-secondary-surface, Canvas);
|
|
152
|
+
--_tone-border: var(--slotted-tone-secondary-border, ButtonBorder);
|
|
153
|
+
--_tone-text: var(--slotted-tone-secondary-text, CanvasText);
|
|
154
|
+
/**
|
|
155
|
+
* The ink of a dot. A tone's border step, which holds 3:1 on the page;
|
|
156
|
+
* for `secondary` the theme's strong border, because the secondary fill
|
|
157
|
+
* is a ground and a grey dot in it vanishes on white.
|
|
158
|
+
*/
|
|
159
|
+
--_tone-mark: var(--slotted-border-strong, GrayText);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
[data-ui='timeline'][data-tone='accent'],
|
|
163
|
+
[data-ui='timeline'] [data-tone='accent'] {
|
|
164
|
+
--_tone-solid: var(--slotted-tone-accent-solid, Highlight);
|
|
165
|
+
--_tone-on-solid: var(--slotted-tone-accent-on-solid, HighlightText);
|
|
166
|
+
--_tone-surface: var(--slotted-tone-accent-surface, Canvas);
|
|
167
|
+
--_tone-border: var(--slotted-tone-accent-border, Highlight);
|
|
168
|
+
--_tone-mark: var(--slotted-tone-accent-border, Highlight);
|
|
169
|
+
--_tone-text: var(--slotted-tone-accent-text, Highlight);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
[data-ui='timeline'][data-tone='success'],
|
|
173
|
+
[data-ui='timeline'] [data-tone='success'] {
|
|
174
|
+
--_tone-solid: var(--slotted-tone-success-solid, ButtonFace);
|
|
175
|
+
--_tone-on-solid: var(--slotted-tone-success-on-solid, ButtonText);
|
|
176
|
+
--_tone-surface: var(--slotted-tone-success-surface, Canvas);
|
|
177
|
+
--_tone-border: var(--slotted-tone-success-border, ButtonBorder);
|
|
178
|
+
--_tone-mark: var(--slotted-tone-success-border, ButtonBorder);
|
|
179
|
+
--_tone-text: var(--slotted-tone-success-text, CanvasText);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
[data-ui='timeline'][data-tone='warning'],
|
|
183
|
+
[data-ui='timeline'] [data-tone='warning'] {
|
|
184
|
+
--_tone-solid: var(--slotted-tone-warning-solid, ButtonFace);
|
|
185
|
+
--_tone-on-solid: var(--slotted-tone-warning-on-solid, ButtonText);
|
|
186
|
+
--_tone-surface: var(--slotted-tone-warning-surface, Canvas);
|
|
187
|
+
--_tone-border: var(--slotted-tone-warning-border, ButtonBorder);
|
|
188
|
+
--_tone-mark: var(--slotted-tone-warning-border, ButtonBorder);
|
|
189
|
+
--_tone-text: var(--slotted-tone-warning-text, CanvasText);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
[data-ui='timeline'][data-tone='danger'],
|
|
193
|
+
[data-ui='timeline'] [data-tone='danger'] {
|
|
194
|
+
--_tone-solid: var(--slotted-tone-danger-solid, Mark);
|
|
195
|
+
--_tone-on-solid: var(--slotted-tone-danger-on-solid, MarkText);
|
|
196
|
+
--_tone-surface: var(--slotted-tone-danger-surface, Canvas);
|
|
197
|
+
--_tone-border: var(--slotted-tone-danger-border, Mark);
|
|
198
|
+
--_tone-mark: var(--slotted-tone-danger-border, Mark);
|
|
199
|
+
--_tone-text: var(--slotted-tone-danger-text, MarkText);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* ── The list ───────────────────────────────────────────────────────────
|
|
203
|
+
*
|
|
204
|
+
* An `ol`, or a `div[role="feed"]`; both are painted the same, because what
|
|
205
|
+
* changes between them is what a reader hears, not what a timeline looks
|
|
206
|
+
* like. A group nests a second list of the same kind.
|
|
207
|
+
*/
|
|
208
|
+
|
|
209
|
+
[data-ui='timeline'] :is([data-part='list'], [data-part='group-list']) {
|
|
210
|
+
display: flex;
|
|
211
|
+
flex-direction: column;
|
|
212
|
+
list-style: none;
|
|
213
|
+
margin: 0;
|
|
214
|
+
padding: 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The opposite column exists when any item in the list projects one. It is
|
|
219
|
+
* read from the list rather than declared, so a consumer who writes the part
|
|
220
|
+
* on one event gets the column on every event and the titles keep lining up.
|
|
221
|
+
*/
|
|
222
|
+
[data-ui='timeline'] [data-part='list']:has([data-part='opposite']) {
|
|
223
|
+
--_opposite-column: var(--_opposite);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/* ── The item ───────────────────────────────────────────────────────────
|
|
227
|
+
*
|
|
228
|
+
* Three columns: the opposite side, the rail, and the body. The rail is
|
|
229
|
+
* stretched to the row so the line can run its whole height; the body and
|
|
230
|
+
* the opposite side share a baseline so a timestamp set smaller than the
|
|
231
|
+
* title still sits on the title's first line.
|
|
232
|
+
*/
|
|
233
|
+
|
|
234
|
+
[data-ui='timeline'] [data-part='item'] {
|
|
235
|
+
align-items: stretch;
|
|
236
|
+
column-gap: var(--_gap);
|
|
237
|
+
display: grid;
|
|
238
|
+
grid-template-columns:
|
|
239
|
+
[opposite] var(--_opposite-column, 0)
|
|
240
|
+
[rail] var(--_rail)
|
|
241
|
+
[content] minmax(0, 1fr);
|
|
242
|
+
position: relative;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
[data-ui='timeline']
|
|
246
|
+
:where([data-part='list']:not(:has([data-part='opposite'])))
|
|
247
|
+
[data-part='item'] {
|
|
248
|
+
grid-template-columns: [rail] var(--_rail) [content] minmax(0, 1fr);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* The space between two events is the item's margin, so a focus ring drawn
|
|
253
|
+
* around an article wraps the event and not the air under it; the connector
|
|
254
|
+
* runs on through the margin to the next marker.
|
|
255
|
+
*/
|
|
256
|
+
[data-ui='timeline'] [data-part='item'] {
|
|
257
|
+
margin-block-end: var(--_item-gap);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
[data-ui='timeline'] [data-part='item']:last-child {
|
|
261
|
+
margin-block-end: 0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
[data-ui='timeline'] [data-part='content'] {
|
|
265
|
+
align-self: baseline;
|
|
266
|
+
grid-column: content;
|
|
267
|
+
/**
|
|
268
|
+
* The row is named on all three cells. Auto-placement puts a cell whose
|
|
269
|
+
* column lies before the cursor on the next row, so with the body before
|
|
270
|
+
* the rail in the columns and after it in the DOM the body dropped a row.
|
|
271
|
+
*/
|
|
272
|
+
grid-row: 1;
|
|
273
|
+
min-inline-size: 0;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
[data-ui='timeline'] [data-part='opposite'] {
|
|
277
|
+
align-self: baseline;
|
|
278
|
+
color: var(--_muted);
|
|
279
|
+
grid-column: opposite;
|
|
280
|
+
grid-row: 1;
|
|
281
|
+
min-inline-size: 0;
|
|
282
|
+
overflow-wrap: anywhere;
|
|
283
|
+
text-align: end;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* ── The rail ───────────────────────────────────────────────────────────
|
|
287
|
+
*
|
|
288
|
+
* The column the marker and the line share, the full height of the row.
|
|
289
|
+
* Its type is the title's, so `1lh` here is the title's first line, and the
|
|
290
|
+
* middle of that line is where every marker centres and where every
|
|
291
|
+
* connector starts and ends — whatever size the marker is.
|
|
292
|
+
*/
|
|
293
|
+
|
|
294
|
+
[data-ui='timeline'] [data-part='rail'] {
|
|
295
|
+
align-items: center;
|
|
296
|
+
display: flex;
|
|
297
|
+
flex-direction: column;
|
|
298
|
+
grid-column: rail;
|
|
299
|
+
grid-row: 1;
|
|
300
|
+
line-height: var(--_leading);
|
|
301
|
+
position: relative;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* A dot when the marker is empty or holds a spinner, a badge when it holds
|
|
306
|
+
* a glyph or an avatar. The marker is pushed from the top of the row by half
|
|
307
|
+
* the difference between one line and itself, the rule `toast` and `alert`
|
|
308
|
+
* draw their marks with, so a dot and a badge in the same list centre on the
|
|
309
|
+
* same line. It stands above the connector and wears a halo of the ground,
|
|
310
|
+
* which is the air the line leaves around it; a halo rather than a shortened
|
|
311
|
+
* line, because the line then runs centre to centre and never has to know
|
|
312
|
+
* how big the next marker is.
|
|
313
|
+
*
|
|
314
|
+
* A dot is drawn in three layers of one box: the box's ground, its border,
|
|
315
|
+
* and a core laid over it at a whole-pixel inset. There is no smaller box
|
|
316
|
+
* centred by arithmetic, so the core lands where the ring does.
|
|
317
|
+
*/
|
|
318
|
+
[data-ui='timeline'] [data-part='marker'] {
|
|
319
|
+
--_marker: var(--_dot);
|
|
320
|
+
/**
|
|
321
|
+
* Rounded to a whole pixel: a line of 19.5 put a 13-pixel dot at a
|
|
322
|
+
* quarter pixel and antialiased its edge on both sides.
|
|
323
|
+
*/
|
|
324
|
+
--_lift: round(nearest, calc((1lh - var(--_marker)) / 2), 1px);
|
|
325
|
+
/* The tone's ink faded into the ground: the soft disc a dot sits in. */
|
|
326
|
+
--_tint: color-mix(in srgb, var(--_tone-mark) 16%, var(--_surface));
|
|
327
|
+
|
|
328
|
+
align-items: center;
|
|
329
|
+
background-color: var(--_tint);
|
|
330
|
+
block-size: var(--_marker);
|
|
331
|
+
border: 0 solid transparent;
|
|
332
|
+
border-radius: var(--slotted-radius-full, 9999px);
|
|
333
|
+
box-shadow: 0 0 0 var(--_line-gap) var(--_surface);
|
|
334
|
+
box-sizing: border-box;
|
|
335
|
+
color: var(--_muted);
|
|
336
|
+
display: inline-flex;
|
|
337
|
+
flex: none;
|
|
338
|
+
inline-size: var(--_marker);
|
|
339
|
+
justify-content: center;
|
|
340
|
+
margin-block-start: var(--_lift);
|
|
341
|
+
/* The halo and the current ring are outside the box; nothing inside may push it wider. */
|
|
342
|
+
overflow: hidden;
|
|
343
|
+
position: relative;
|
|
344
|
+
transition:
|
|
345
|
+
background-color var(--slotted-control-transition-duration)
|
|
346
|
+
var(--slotted-control-transition-easing),
|
|
347
|
+
border-color var(--slotted-control-transition-duration)
|
|
348
|
+
var(--slotted-control-transition-easing),
|
|
349
|
+
color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
|
|
350
|
+
z-index: 1;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* The core, on one box that fills the marker: inset by a whole number of
|
|
355
|
+
* pixels, since the dot and the core differ by an even number. A finished
|
|
356
|
+
* dot holds its check instead, so it is not empty and draws no core.
|
|
357
|
+
*/
|
|
358
|
+
[data-ui='timeline'] [data-part='marker']:empty::after {
|
|
359
|
+
background-color: var(--_tone-mark);
|
|
360
|
+
border-radius: inherit;
|
|
361
|
+
content: '';
|
|
362
|
+
inset: calc((var(--_marker) - var(--_core)) / 2);
|
|
363
|
+
position: absolute;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* A badge. The glyph is the control icon less one step of air on each side,
|
|
368
|
+
* made the badge's parity: 13 in a badge of 21 at `md`, four whole pixels
|
|
369
|
+
* off each edge. The badge is odd so the line runs through its middle; a
|
|
370
|
+
* glyph of 12 stood four and a half pixels in, the browser painted it on
|
|
371
|
+
* the next whole pixel, and its ink sat half a CSS pixel right of and below
|
|
372
|
+
* the disc's centre at every zoom — two device pixels at 400%, measured on
|
|
373
|
+
* the painted capture. The avatar fills its own marker without a ring.
|
|
374
|
+
*
|
|
375
|
+
* The check of a finished dot is the one icon the family puts in a marker
|
|
376
|
+
* itself, marked `data-check` by the binding so it is never read as a badge:
|
|
377
|
+
* the marker stays a dot, and every rule a dot takes names it beside
|
|
378
|
+
* `:empty`.
|
|
379
|
+
*/
|
|
380
|
+
[data-ui='timeline']
|
|
381
|
+
[data-part='marker']:not(:empty, :has(> [data-ui='spinner'], > [data-check])) {
|
|
382
|
+
--_marker: var(--_badge);
|
|
383
|
+
|
|
384
|
+
background-color: var(--_surface);
|
|
385
|
+
border-color: var(--_ring);
|
|
386
|
+
border-width: var(--slotted-border-width-thin, 1px);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
[data-ui='timeline'] [data-part='marker'] > [data-ui='icon'] {
|
|
390
|
+
--slotted-icon-size: calc(
|
|
391
|
+
var(--_badge) - 2 * round(down, (var(--_badge) - var(--_glyph)) / 2, 1px)
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
color: inherit;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/* A spinner is a dot: the same box, and the same size as the glyph in a badge. */
|
|
398
|
+
[data-ui='timeline'] [data-part='marker'] > [data-ui='spinner'] {
|
|
399
|
+
--slotted-spinner-size: var(--_dot);
|
|
400
|
+
|
|
401
|
+
color: inherit;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
[data-ui='timeline'] [data-part='marker'] > [data-ui='avatar'] {
|
|
405
|
+
--slotted-avatar-size: var(--_avatar);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
[data-ui='timeline'] [data-part='marker']:has(> [data-ui='avatar']) {
|
|
409
|
+
--_marker: var(--_avatar);
|
|
410
|
+
|
|
411
|
+
background-color: transparent;
|
|
412
|
+
border-width: 0;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/* ── Variants ───────────────────────────────────────────────────────────
|
|
416
|
+
*
|
|
417
|
+
* Four emphases, read on the item, each drawn twice: once as a dot, once as
|
|
418
|
+
* a badge. `subtle` is the default and the quiet one — a solid core in a
|
|
419
|
+
* soft disc of its own tone, or a badge on the tone's ground with its edge,
|
|
420
|
+
* the pair rule `docs/token-foundation.md` states under semantic colour.
|
|
421
|
+
* `outline` is the hollow ring, `solid` fills, and `plain` drops every frame:
|
|
422
|
+
* the core alone, threaded on the line, or the bare glyph over it.
|
|
423
|
+
*/
|
|
424
|
+
|
|
425
|
+
[data-ui='timeline']
|
|
426
|
+
[data-variant='outline']
|
|
427
|
+
[data-part='marker']:is(:empty, :has(> [data-check])) {
|
|
428
|
+
background-color: var(--_surface);
|
|
429
|
+
border-color: var(--_tone-mark);
|
|
430
|
+
border-width: var(--_edge);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
[data-ui='timeline'] [data-variant='outline'] [data-part='marker']:empty::after,
|
|
434
|
+
[data-ui='timeline'] [data-variant='solid'] [data-part='marker']:empty::after {
|
|
435
|
+
content: none;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
[data-ui='timeline']
|
|
439
|
+
[data-variant='solid']
|
|
440
|
+
[data-part='marker']:is(:empty, :has(> [data-check])) {
|
|
441
|
+
background-color: var(--_tone-mark);
|
|
442
|
+
/* A border as wide as the radius, so forced colours, which drop the ground, keep the disc. */
|
|
443
|
+
border-color: var(--_tone-mark);
|
|
444
|
+
border-width: calc(var(--_marker) / 2);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/* The core alone, on the line: the ground and the halo give way so the line runs into it. */
|
|
448
|
+
[data-ui='timeline']
|
|
449
|
+
[data-variant='plain']
|
|
450
|
+
[data-part='marker']:is(:empty, :has(> [data-check])) {
|
|
451
|
+
background-color: transparent;
|
|
452
|
+
box-shadow: none;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/* The glyph of a hairline or frameless badge is drawn in the dot's own ink. */
|
|
456
|
+
[data-ui='timeline']
|
|
457
|
+
[data-variant='outline']
|
|
458
|
+
[data-part='marker']:not(:empty, :has(> [data-check])) {
|
|
459
|
+
color: var(--_tone-mark);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
[data-ui='timeline']
|
|
463
|
+
[data-variant='outline'][data-tone]:not([data-tone='secondary'])
|
|
464
|
+
[data-part='marker']:not(:empty, :has(> [data-ui='spinner'], > [data-check])) {
|
|
465
|
+
border-color: var(--_tone-border);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
[data-ui='timeline']
|
|
469
|
+
[data-variant='solid']
|
|
470
|
+
[data-part='marker']:not(:empty, :has(> [data-ui='spinner'], > [data-check])) {
|
|
471
|
+
background-color: var(--_tone-solid);
|
|
472
|
+
border-color: var(--_tone-solid);
|
|
473
|
+
color: var(--_tone-on-solid);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
[data-ui='timeline']
|
|
477
|
+
[data-variant='subtle']
|
|
478
|
+
[data-part='marker']:not(:empty, :has(> [data-ui='spinner'], > [data-check])) {
|
|
479
|
+
background-color: var(--_tone-surface);
|
|
480
|
+
border-color: var(--_tone-border);
|
|
481
|
+
color: var(--_tone-text);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
[data-ui='timeline']
|
|
485
|
+
[data-variant='plain']
|
|
486
|
+
[data-part='marker']:not(:empty, :has(> [data-check])) {
|
|
487
|
+
background-color: var(--_surface);
|
|
488
|
+
border-color: transparent;
|
|
489
|
+
color: var(--_tone-mark);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/* ── Statuses ───────────────────────────────────────────────────────────
|
|
493
|
+
*
|
|
494
|
+
* Each one is a shape as well as a colour, because `high-contrast` paints
|
|
495
|
+
* every tone in one ink and forced colours paint every ring in one. Pending
|
|
496
|
+
* is the variant's own mark; complete is a filled disc with the check
|
|
497
|
+
* knocked out of it; current is a filled disc with a ring around it, a
|
|
498
|
+
* target; loading is the shared spinner. The ring is a shadow and not an
|
|
499
|
+
* outline, because an outline in this library is the focus ring and a ring
|
|
500
|
+
* in the tone's ink around a marker would read as focus; forced colours drop
|
|
501
|
+
* the shadow, and the block at the end draws it there as an outline in the
|
|
502
|
+
* system's ink, where no colour can be mistaken.
|
|
503
|
+
*/
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* A finished dot fills with its ground, not with a border as wide as its
|
|
507
|
+
* radius: that border would leave the check no box to stand in. Forced
|
|
508
|
+
* colours keep the ground through the block at the end.
|
|
509
|
+
*/
|
|
510
|
+
[data-ui='timeline']
|
|
511
|
+
[data-complete]:not([data-current])
|
|
512
|
+
[data-part='marker']:has(> [data-check]) {
|
|
513
|
+
background-color: var(--_tone-mark);
|
|
514
|
+
border-width: 0;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
[data-ui='timeline'] [data-current] [data-part='marker']:empty {
|
|
518
|
+
background-color: var(--_tone-mark);
|
|
519
|
+
border-color: var(--_tone-mark);
|
|
520
|
+
border-width: calc(var(--_marker) / 2);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
[data-ui='timeline'] [data-current] [data-part='marker']:empty::after {
|
|
524
|
+
content: none;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* The check is knocked out of the disc in the ground's own colour, so it
|
|
529
|
+
* reads in every tone and scheme without a token of its own; it is the
|
|
530
|
+
* dot less a step a side, the same air a badge gives its glyph.
|
|
531
|
+
*/
|
|
532
|
+
[data-ui='timeline'] [data-part='marker'] > [data-ui='icon'][data-check] {
|
|
533
|
+
--slotted-icon-size: calc(var(--_marker) - 2 * var(--slotted-space-1, 0.125rem));
|
|
534
|
+
|
|
535
|
+
color: var(--_surface);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
[data-ui='timeline'] [data-current] [data-part='marker'] {
|
|
539
|
+
box-shadow:
|
|
540
|
+
0 0 0 var(--slotted-border-width-thick, 2px) var(--_surface),
|
|
541
|
+
0 0 0 var(--_reach) var(--_tone-mark),
|
|
542
|
+
0 0 0 calc(var(--_reach) + var(--_line-gap)) var(--_surface);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
[data-ui='timeline']
|
|
546
|
+
[data-complete]:not([data-current])
|
|
547
|
+
[data-part='marker']:not(:empty, :has(> [data-ui='spinner'], > [data-check])),
|
|
548
|
+
[data-ui='timeline']
|
|
549
|
+
[data-current]
|
|
550
|
+
[data-part='marker']:not(:empty, :has(> [data-ui='spinner'], > [data-check])) {
|
|
551
|
+
background-color: var(--_tone-solid);
|
|
552
|
+
border-color: var(--_tone-solid);
|
|
553
|
+
color: var(--_tone-on-solid);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* An event still arriving. The ring is `spinner`'s — one arc, drawn once,
|
|
558
|
+
* for every family that waits — standing bare on the ground, the size of a
|
|
559
|
+
* dot, in the tone's ink.
|
|
560
|
+
*/
|
|
561
|
+
[data-ui='timeline'] [data-loading][data-variant] [data-part='marker'] {
|
|
562
|
+
background-color: var(--_surface);
|
|
563
|
+
border-color: transparent;
|
|
564
|
+
box-shadow: 0 0 0 var(--_line-gap) var(--_surface);
|
|
565
|
+
color: var(--_tone-mark);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
[data-ui='timeline'] [data-loading] > [data-part='content'] {
|
|
569
|
+
color: var(--_muted);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/* ── The connector ──────────────────────────────────────────────────────
|
|
573
|
+
*
|
|
574
|
+
* A hairline from the middle of this row's first line to the middle of the
|
|
575
|
+
* next row's, which are the two markers' centres; the markers stand above
|
|
576
|
+
* it and their halo opens the gap. It is a border rather than a painted
|
|
577
|
+
* background, so `dashed` is a word rather than a gradient and the line
|
|
578
|
+
* keeps its colour under forced colours. The last item of a list draws
|
|
579
|
+
* none, because there is nothing after it.
|
|
580
|
+
*/
|
|
581
|
+
|
|
582
|
+
[data-ui='timeline'] [data-part='connector'] {
|
|
583
|
+
/* Both edges named, so the dashed style below reaches only the one drawn. */
|
|
584
|
+
border-block-start: 0 solid var(--_line);
|
|
585
|
+
border-inline-start: var(--_rule) solid var(--_line);
|
|
586
|
+
display: block;
|
|
587
|
+
inline-size: 0;
|
|
588
|
+
inset-block-end: calc(-0.5lh - var(--_item-gap));
|
|
589
|
+
inset-block-start: 0.5lh;
|
|
590
|
+
inset-inline-start: calc(50% - var(--_rule) / 2);
|
|
591
|
+
position: absolute;
|
|
592
|
+
transition: border-color var(--slotted-control-transition-duration)
|
|
593
|
+
var(--slotted-control-transition-easing);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
[data-ui='timeline'] [data-connector='dashed'] [data-part='connector'] {
|
|
597
|
+
border-block-start-style: dashed;
|
|
598
|
+
border-inline-start-style: dashed;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
[data-ui='timeline'] [data-connector='none'] [data-part='connector'],
|
|
602
|
+
[data-ui='timeline'] [data-part='item']:last-child [data-part='connector'] {
|
|
603
|
+
display: none;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* The line after a finished event is painted in its tone, so a tracking
|
|
608
|
+
* timeline reads as a filled track up to where the reader is.
|
|
609
|
+
*/
|
|
610
|
+
[data-ui='timeline'] [data-complete] [data-part='connector'] {
|
|
611
|
+
border-color: var(--_tone-mark);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/* ── The body ───────────────────────────────────────────────────────────
|
|
615
|
+
*
|
|
616
|
+
* Title and timestamp on the first line, the actor under them, then the
|
|
617
|
+
* description, whatever the consumer wrote, and the actions. The timestamp
|
|
618
|
+
* keeps to the end of the line while there is room and drops under the
|
|
619
|
+
* title when there is not.
|
|
620
|
+
*
|
|
621
|
+
* Two columns and no named areas: the title takes the first cell and the
|
|
622
|
+
* time the second, and everything else spans both and follows the DOM. A
|
|
623
|
+
* body laid out by named areas put a consumer's own child in the first
|
|
624
|
+
* empty cell — the actor's row — above the description it was written
|
|
625
|
+
* under.
|
|
626
|
+
*/
|
|
627
|
+
|
|
628
|
+
[data-ui='timeline'] [data-part='content'] {
|
|
629
|
+
/**
|
|
630
|
+
* No column gap: the timestamp carries the distance itself, so a body
|
|
631
|
+
* with no timestamp has no empty column and no gap beside it.
|
|
632
|
+
*/
|
|
633
|
+
column-gap: 0;
|
|
634
|
+
display: grid;
|
|
635
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
636
|
+
/* No row gap either: an empty row would still cost one, so each line
|
|
637
|
+
below the first carries its own distance. */
|
|
638
|
+
row-gap: 0;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
[data-ui='timeline'] [data-part='content'] > :not([data-part='title'], [data-part='time']) {
|
|
642
|
+
grid-column: 1 / -1;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
[data-ui='timeline'] [data-part='content'] > :is([data-part='actor'], [data-part='description']) {
|
|
646
|
+
margin-block-start: var(--slotted-timeline-content-gap, var(--slotted-space-2, 0.25rem));
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
[data-ui='timeline'] [data-part='title'] {
|
|
650
|
+
color: var(--_strong);
|
|
651
|
+
font-weight: var(--slotted-timeline-title-weight, var(--slotted-font-weight-medium, 500));
|
|
652
|
+
grid-column: 1;
|
|
653
|
+
min-inline-size: 0;
|
|
654
|
+
overflow-wrap: anywhere;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
[data-ui='timeline'] [data-part='content'] > [data-part='time'] {
|
|
658
|
+
grid-column: 2;
|
|
659
|
+
grid-row: 1;
|
|
660
|
+
margin-inline-start: var(--_gap);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
[data-ui='timeline'] [data-part='time'] {
|
|
664
|
+
color: var(--_muted);
|
|
665
|
+
font-size: var(--slotted-timeline-time-font-size, var(--slotted-font-size-xs, 0.75rem));
|
|
666
|
+
font-variant-numeric: tabular-nums;
|
|
667
|
+
white-space: nowrap;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
[data-ui='timeline'] [data-part='actor'] {
|
|
671
|
+
align-items: center;
|
|
672
|
+
color: var(--_muted);
|
|
673
|
+
column-gap: var(--slotted-space-3, 0.375rem);
|
|
674
|
+
display: flex;
|
|
675
|
+
font-size: var(--_meta-size);
|
|
676
|
+
min-inline-size: 0;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
[data-ui='timeline'] [data-part='description'] {
|
|
680
|
+
color: var(--_muted);
|
|
681
|
+
font-size: var(--_meta-size);
|
|
682
|
+
min-inline-size: 0;
|
|
683
|
+
overflow-wrap: anywhere;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
[data-ui='timeline'] [data-part='actions'] {
|
|
687
|
+
column-gap: var(--_gap);
|
|
688
|
+
display: flex;
|
|
689
|
+
flex-wrap: wrap;
|
|
690
|
+
margin-block-start: var(--slotted-space-4, 0.5rem);
|
|
691
|
+
row-gap: var(--slotted-space-2, 0.25rem);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/* ── The article ────────────────────────────────────────────────────────
|
|
695
|
+
*
|
|
696
|
+
* In feed mode every item is a tab stop, so it draws the theme's ring when
|
|
697
|
+
* the keyboard lands on it. The ring stands off the item by the offset the
|
|
698
|
+
* theme states, around the whole row rather than around the words.
|
|
699
|
+
*/
|
|
700
|
+
|
|
701
|
+
[data-ui='timeline'] [data-part='item'][tabindex]:focus-visible {
|
|
702
|
+
border-radius: var(--slotted-timeline-radius, var(--slotted-control-radius, 4px));
|
|
703
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
704
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/* ── Groups ─────────────────────────────────────────────────────────────
|
|
708
|
+
*
|
|
709
|
+
* A period with a heading and its own list. The heading spans the whole
|
|
710
|
+
* width and the line breaks at it: a group is a break in time, and the
|
|
711
|
+
* track that ran into it would say the opposite.
|
|
712
|
+
*/
|
|
713
|
+
|
|
714
|
+
[data-ui='timeline'] [data-part='group'] {
|
|
715
|
+
display: block;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
[data-ui='timeline'] [data-part='group'] + [data-part='group'] {
|
|
719
|
+
margin-block-start: var(--_item-gap);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* A flex box, so a trigger inside it is the whole line: an inline-flex
|
|
724
|
+
* trigger on the heading's baseline added the font's descent under its
|
|
725
|
+
* 24 pixels, and the heading measured 26.5.
|
|
726
|
+
*/
|
|
727
|
+
[data-ui='timeline'] [data-part='group-label'] {
|
|
728
|
+
align-items: center;
|
|
729
|
+
color: var(--_muted);
|
|
730
|
+
display: flex;
|
|
731
|
+
font-size: var(--_meta-size);
|
|
732
|
+
font-weight: var(--slotted-timeline-group-weight, var(--slotted-font-weight-semibold, 600));
|
|
733
|
+
line-height: var(--_leading);
|
|
734
|
+
margin: 0 0 var(--slotted-timeline-group-gap, var(--slotted-space-4, 0.5rem));
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
[data-ui='timeline'] [data-part='group-trigger'] {
|
|
738
|
+
align-items: center;
|
|
739
|
+
appearance: none;
|
|
740
|
+
background: none;
|
|
741
|
+
border: 0;
|
|
742
|
+
border-radius: var(--slotted-timeline-radius, var(--slotted-control-radius, 4px));
|
|
743
|
+
color: inherit;
|
|
744
|
+
column-gap: var(--slotted-space-2, 0.25rem);
|
|
745
|
+
cursor: pointer;
|
|
746
|
+
display: inline-flex;
|
|
747
|
+
font: inherit;
|
|
748
|
+
/* The row's own height, so the target is never under the minimum. */
|
|
749
|
+
min-block-size: var(--slotted-target-min, 24px);
|
|
750
|
+
padding: 0;
|
|
751
|
+
text-align: start;
|
|
752
|
+
transition:
|
|
753
|
+
color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing),
|
|
754
|
+
translate var(--slotted-duration-instant) var(--slotted-control-transition-easing);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
[data-ui='timeline'] [data-part='group-trigger']:enabled:hover {
|
|
758
|
+
color: var(--_strong);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* The heading has no ground to step, and its hover already takes the
|
|
763
|
+
* strongest ink, so a press answers in place: the label settles by a
|
|
764
|
+
* hairline, the press `button` draws on a solid fill.
|
|
765
|
+
*/
|
|
766
|
+
[data-ui='timeline'] [data-part='group-trigger']:enabled:active {
|
|
767
|
+
color: var(--_strong);
|
|
768
|
+
translate: 0 var(--slotted-border-width-thin, 1px);
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
[data-ui='timeline'] [data-part='group-trigger']:focus-visible {
|
|
772
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
773
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* The binding's `chevron-down` glyph, turned rather than swapped: a chevron
|
|
778
|
+
* that rotates between down and up is the same mark in every direction. The
|
|
779
|
+
* part sizes the icon box and the box turns.
|
|
780
|
+
*/
|
|
781
|
+
[data-ui='timeline'] [data-part='group-indicator'] {
|
|
782
|
+
--slotted-icon-size: var(--_icon);
|
|
783
|
+
|
|
784
|
+
display: inline-flex;
|
|
785
|
+
flex: none;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* A fold is one movement: the chevron, the list's height, its ink and the
|
|
790
|
+
* heading's distance to it share a duration and a curve, the disclosure
|
|
791
|
+
* motion `collapsible` draws. Measured frame by frame before this rule, the
|
|
792
|
+
* list faded while the page below stood still and then jumped 56 pixels in
|
|
793
|
+
* one frame, the exiting curve held the list at 0.9 for the first fifty-five milliseconds
|
|
794
|
+
* after the press, and the chevron finished seventy milliseconds after the list had gone.
|
|
795
|
+
*/
|
|
796
|
+
[data-ui='timeline'] [data-part='group'] {
|
|
797
|
+
--_fold: var(--slotted-duration-medium)
|
|
798
|
+
var(--slotted-control-transition-easing, var(--slotted-easing-standard));
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
[data-ui='timeline'] [data-part='group-indicator'] > [data-ui='icon'] {
|
|
802
|
+
rotate: -90deg;
|
|
803
|
+
transition: rotate var(--_fold);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
[data-ui='timeline']
|
|
807
|
+
[data-open]
|
|
808
|
+
> [data-part='group-label']
|
|
809
|
+
[data-part='group-indicator']
|
|
810
|
+
> [data-ui='icon'] {
|
|
811
|
+
rotate: 0deg;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* A folded list stays laid out at no height rather than leaving the page:
|
|
816
|
+
* the page below then slides with it instead of jumping, and a group open
|
|
817
|
+
* at the first render has no earlier style to grow from, so nothing moves
|
|
818
|
+
* while a page loads. `hidden` still says what it did — the binding writes
|
|
819
|
+
* it, and `visibility` takes the folded events out of the accessibility
|
|
820
|
+
* tree and the tab order, at the end of the fold and at the start of an
|
|
821
|
+
* opening. The clip margin keeps the current marker's ring and a focus
|
|
822
|
+
* ring at the list's edge whole.
|
|
823
|
+
*/
|
|
824
|
+
[data-ui='timeline'] [data-part='group-list'] {
|
|
825
|
+
interpolate-size: allow-keywords;
|
|
826
|
+
opacity: 1;
|
|
827
|
+
overflow: clip;
|
|
828
|
+
overflow-clip-margin: max(
|
|
829
|
+
round(up, var(--_reach), 1px),
|
|
830
|
+
calc(var(--slotted-focus-ring-width, 2px) + var(--slotted-focus-ring-offset, 2px))
|
|
831
|
+
);
|
|
832
|
+
transition:
|
|
833
|
+
block-size var(--_fold),
|
|
834
|
+
opacity var(--_fold),
|
|
835
|
+
visibility var(--_fold);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
[data-ui='timeline'] [data-part='group-list'][hidden] {
|
|
839
|
+
block-size: 0;
|
|
840
|
+
display: flex;
|
|
841
|
+
opacity: 0;
|
|
842
|
+
visibility: hidden;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/* A folded group ends at its heading; the distance to the next is the group's own. */
|
|
846
|
+
[data-ui='timeline'] [data-part='group-label'] {
|
|
847
|
+
transition: margin-block-end var(--_fold);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
[data-ui='timeline'] [data-part='group-label']:has(+ [data-part='group-list'][hidden]) {
|
|
851
|
+
margin-block-end: 0;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/* ── Fresh, more and empty ──────────────────────────────────────────────
|
|
855
|
+
*
|
|
856
|
+
* Three things that are not events. `fresh` is the pill that holds new
|
|
857
|
+
* events back until the reader asks for them; `more` is the end of what has
|
|
858
|
+
* been loaded; `empty` is the list with nothing in it yet.
|
|
859
|
+
*/
|
|
860
|
+
|
|
861
|
+
[data-ui='timeline'] [data-part='fresh'],
|
|
862
|
+
[data-ui='timeline'] button[data-part='more'] {
|
|
863
|
+
align-items: center;
|
|
864
|
+
appearance: none;
|
|
865
|
+
background-color: var(--_surface);
|
|
866
|
+
border: var(--slotted-border-width-thin, 1px) solid var(--_ring);
|
|
867
|
+
border-radius: var(--slotted-radius-full, 9999px);
|
|
868
|
+
color: var(--_strong);
|
|
869
|
+
column-gap: var(--_gap);
|
|
870
|
+
cursor: pointer;
|
|
871
|
+
/* Block-level, so no line box of the list's leading stands around it. */
|
|
872
|
+
display: flex;
|
|
873
|
+
font: inherit;
|
|
874
|
+
font-size: var(--_meta-size);
|
|
875
|
+
font-weight: var(--slotted-timeline-title-weight, var(--slotted-font-weight-medium, 500));
|
|
876
|
+
inline-size: fit-content;
|
|
877
|
+
justify-content: center;
|
|
878
|
+
line-height: var(--slotted-control-line-height, 1);
|
|
879
|
+
min-block-size: var(--slotted-control-height-sm, 30px);
|
|
880
|
+
padding-inline: var(--slotted-control-padding-inline-md, 13px);
|
|
881
|
+
transition:
|
|
882
|
+
background-color var(--slotted-control-transition-duration)
|
|
883
|
+
var(--slotted-control-transition-easing),
|
|
884
|
+
border-color var(--slotted-control-transition-duration)
|
|
885
|
+
var(--slotted-control-transition-easing),
|
|
886
|
+
color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
[data-ui='timeline'] [data-part='fresh'] {
|
|
890
|
+
--_tone-solid: var(--slotted-tone-accent-solid, Highlight);
|
|
891
|
+
--_tone-surface: var(--slotted-tone-accent-surface, Canvas);
|
|
892
|
+
--_tone-border: var(--slotted-tone-accent-border, Highlight);
|
|
893
|
+
--_tone-text: var(--slotted-tone-accent-text, Highlight);
|
|
894
|
+
/**
|
|
895
|
+
* The pill arrives and leaves as the group lists fold: its height, its
|
|
896
|
+
* border, the distance under it and its ink move together, so the events
|
|
897
|
+
* below slide by the pill's height rather than jumping by it in a frame.
|
|
898
|
+
*/
|
|
899
|
+
--_fold: var(--slotted-duration-medium)
|
|
900
|
+
var(--slotted-control-transition-easing, var(--slotted-easing-standard));
|
|
901
|
+
|
|
902
|
+
background-color: var(--_tone-surface);
|
|
903
|
+
border-color: var(--_tone-border);
|
|
904
|
+
color: var(--_tone-text);
|
|
905
|
+
interpolate-size: allow-keywords;
|
|
906
|
+
margin-block-end: var(--_item-gap);
|
|
907
|
+
opacity: 1;
|
|
908
|
+
overflow: clip;
|
|
909
|
+
transition:
|
|
910
|
+
background-color var(--slotted-control-transition-duration)
|
|
911
|
+
var(--slotted-control-transition-easing),
|
|
912
|
+
border-color var(--slotted-control-transition-duration)
|
|
913
|
+
var(--slotted-control-transition-easing),
|
|
914
|
+
color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing),
|
|
915
|
+
block-size var(--_fold),
|
|
916
|
+
min-block-size var(--_fold),
|
|
917
|
+
border-block-width var(--_fold),
|
|
918
|
+
margin-block-end var(--_fold),
|
|
919
|
+
opacity var(--_fold),
|
|
920
|
+
display var(--_fold) allow-discrete;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
/**
|
|
924
|
+
* The bindings keep the pill mounted once it has appeared and write
|
|
925
|
+
* `hidden` at a count of zero; `allow-discrete` holds it on the page until
|
|
926
|
+
* it has folded away. Its first appearance grows from nothing, because the
|
|
927
|
+
* pill arriving is itself the news. Scale is not used: the pill holds text
|
|
928
|
+
* (`text-scale.test.mjs`).
|
|
929
|
+
*/
|
|
930
|
+
@starting-style {
|
|
931
|
+
[data-ui='timeline'] [data-part='fresh']:not([hidden]) {
|
|
932
|
+
block-size: 0;
|
|
933
|
+
border-block-width: 0;
|
|
934
|
+
margin-block-end: 0;
|
|
935
|
+
min-block-size: 0;
|
|
936
|
+
opacity: 0;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
[data-ui='timeline'] [data-part='fresh'][hidden] {
|
|
941
|
+
block-size: 0;
|
|
942
|
+
border-block-width: 0;
|
|
943
|
+
display: none;
|
|
944
|
+
margin-block-end: 0;
|
|
945
|
+
min-block-size: 0;
|
|
946
|
+
opacity: 0;
|
|
947
|
+
pointer-events: none;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* The pill answers with a state layer: its own text colour, at a low
|
|
952
|
+
* strength, mixed into the tinted ground, the step `tag` and `avatar` take
|
|
953
|
+
* for the same reason. The tinted ramp ends at the surface the pill rests
|
|
954
|
+
* on — `subtle-hover` lightened it toward the page in the light scheme, and
|
|
955
|
+
* matched the page in the dark one, and `subtle-active` was the rest colour.
|
|
956
|
+
*/
|
|
957
|
+
[data-ui='timeline'] [data-part='fresh']:enabled:hover {
|
|
958
|
+
background-color: color-mix(
|
|
959
|
+
in oklab,
|
|
960
|
+
var(--_tone-surface),
|
|
961
|
+
currentColor var(--slotted-timeline-state-layer-hover, 8%)
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
[data-ui='timeline'] [data-part='fresh']:enabled:active {
|
|
966
|
+
background-color: color-mix(
|
|
967
|
+
in oklab,
|
|
968
|
+
var(--_tone-surface),
|
|
969
|
+
currentColor var(--slotted-timeline-state-layer-active, 14%)
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
[data-ui='timeline'] button[data-part='more']:enabled:hover {
|
|
974
|
+
background-color: var(--slotted-tone-secondary-subtle-hover, Canvas);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
[data-ui='timeline'] button[data-part='more']:enabled:active {
|
|
978
|
+
background-color: var(--slotted-tone-secondary-subtle-active, Canvas);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/* A press lands at once, as a `button` does; the release eases back. */
|
|
982
|
+
[data-ui='timeline'] :is([data-part='fresh'], button[data-part='more']):enabled:active {
|
|
983
|
+
transition-duration: var(--slotted-duration-instant);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
[data-ui='timeline'] [data-part='fresh']:focus-visible,
|
|
987
|
+
[data-ui='timeline'] button[data-part='more']:focus-visible {
|
|
988
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
989
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
/**
|
|
993
|
+
* The end of the loaded list, in the body's own column so it reads as the
|
|
994
|
+
* next event's place rather than as a footer.
|
|
995
|
+
*/
|
|
996
|
+
[data-ui='timeline'] [data-part='more'] {
|
|
997
|
+
margin-block-start: var(--_item-gap);
|
|
998
|
+
margin-inline-start: calc(var(--_opposite-column, 0px) + var(--_rail) + var(--_gap));
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
[data-ui='timeline'] [data-part='list']:has([data-part='opposite']) ~ [data-part='more'] {
|
|
1002
|
+
margin-inline-start: calc(var(--_opposite) + var(--_rail) + 2 * var(--_gap));
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
[data-ui='timeline'] div[data-part='more'] {
|
|
1006
|
+
align-items: center;
|
|
1007
|
+
color: var(--_muted);
|
|
1008
|
+
column-gap: var(--_gap);
|
|
1009
|
+
display: flex;
|
|
1010
|
+
font-size: var(--_meta-size);
|
|
1011
|
+
min-block-size: var(--slotted-control-height-sm, 30px);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
[data-ui='timeline'] [data-part='more'] > [data-ui='spinner'] {
|
|
1015
|
+
--slotted-spinner-size: var(--_icon);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
[data-ui='timeline'] [data-part='empty'] {
|
|
1019
|
+
color: var(--_muted);
|
|
1020
|
+
padding-block: var(--_item-gap);
|
|
1021
|
+
text-align: center;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/* ── Placement ──────────────────────────────────────────────────────────
|
|
1025
|
+
*
|
|
1026
|
+
* `start` mirrors the row: the body before the rail, the opposite side
|
|
1027
|
+
* after it. `alternate` gives every row both sides and the items take turns,
|
|
1028
|
+
* so the rail runs down the middle. Both are logical: in a right-to-left
|
|
1029
|
+
* document `start` is the same timeline mirrored.
|
|
1030
|
+
*/
|
|
1031
|
+
|
|
1032
|
+
[data-ui='timeline'][data-placement='start'] [data-part='item'] {
|
|
1033
|
+
grid-template-columns:
|
|
1034
|
+
[content] minmax(0, 1fr)
|
|
1035
|
+
[rail] var(--_rail)
|
|
1036
|
+
[opposite] var(--_opposite-column, 0);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
[data-ui='timeline'][data-placement='start']
|
|
1040
|
+
:where([data-part='list']:not(:has([data-part='opposite'])))
|
|
1041
|
+
[data-part='item'] {
|
|
1042
|
+
grid-template-columns: [content] minmax(0, 1fr) [rail] var(--_rail);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
[data-ui='timeline'][data-placement='start'] [data-part='content'] {
|
|
1046
|
+
text-align: end;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
[data-ui='timeline'][data-placement='start'] [data-part='content'] {
|
|
1050
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
[data-ui='timeline'][data-placement='start'] [data-part='content'] > [data-part='title'] {
|
|
1054
|
+
grid-column: 2;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
[data-ui='timeline'][data-placement='start'] [data-part='content'] > [data-part='time'] {
|
|
1058
|
+
grid-column: 1;
|
|
1059
|
+
margin-inline: 0 var(--_gap);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
[data-ui='timeline'][data-placement='start'] :is([data-part='actor'], [data-part='actions']) {
|
|
1063
|
+
justify-content: flex-end;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
[data-ui='timeline'][data-placement='start'] [data-part='opposite'] {
|
|
1067
|
+
text-align: start;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
[data-ui='timeline'][data-placement='start'] [data-part='more'] {
|
|
1071
|
+
margin-inline-start: 0;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* The first side is a whole number of pixels and the second takes the
|
|
1076
|
+
* rest: two equal fractions of an odd remainder put the rail, and every
|
|
1077
|
+
* marker on it, at half a pixel.
|
|
1078
|
+
*/
|
|
1079
|
+
[data-ui='timeline'][data-placement='alternate'] [data-part='item'] {
|
|
1080
|
+
grid-template-columns:
|
|
1081
|
+
[before] round(down, calc((100% - var(--_rail)) / 2 - var(--_gap)), 1px)
|
|
1082
|
+
[rail] var(--_rail)
|
|
1083
|
+
[after] minmax(0, 1fr);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
[data-ui='timeline'][data-placement='alternate'] [data-part='content'] {
|
|
1087
|
+
grid-column: after;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
[data-ui='timeline'][data-placement='alternate'] [data-part='opposite'] {
|
|
1091
|
+
grid-column: before;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
/**
|
|
1095
|
+
* Even rows swap sides. Parity is read from the list rather than written by
|
|
1096
|
+
* a binding, and an item that names its own side wins.
|
|
1097
|
+
*/
|
|
1098
|
+
[data-ui='timeline'][data-placement='alternate']
|
|
1099
|
+
[data-part='item']:nth-child(even)
|
|
1100
|
+
[data-part='content'],
|
|
1101
|
+
[data-ui='timeline'][data-placement='alternate'] [data-side='start'] [data-part='content'] {
|
|
1102
|
+
grid-column: before;
|
|
1103
|
+
text-align: end;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
[data-ui='timeline'][data-placement='alternate']
|
|
1107
|
+
[data-part='item']:nth-child(even)
|
|
1108
|
+
[data-part='opposite'],
|
|
1109
|
+
[data-ui='timeline'][data-placement='alternate'] [data-side='start'] [data-part='opposite'] {
|
|
1110
|
+
grid-column: after;
|
|
1111
|
+
text-align: start;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
[data-ui='timeline'][data-placement='alternate'] [data-side='end'] [data-part='content'] {
|
|
1115
|
+
grid-column: after;
|
|
1116
|
+
text-align: start;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
[data-ui='timeline'][data-placement='alternate'] [data-side='end'] [data-part='opposite'] {
|
|
1120
|
+
grid-column: before;
|
|
1121
|
+
text-align: end;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
[data-ui='timeline'][data-placement='alternate']
|
|
1125
|
+
[data-part='item']:nth-child(even)
|
|
1126
|
+
[data-part='content'],
|
|
1127
|
+
[data-ui='timeline'][data-placement='alternate'] [data-side='start'] [data-part='content'] {
|
|
1128
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
[data-ui='timeline'][data-placement='alternate']
|
|
1132
|
+
[data-part='item']:nth-child(even)
|
|
1133
|
+
[data-part='content']
|
|
1134
|
+
> [data-part='title'],
|
|
1135
|
+
[data-ui='timeline'][data-placement='alternate']
|
|
1136
|
+
[data-side='start']
|
|
1137
|
+
[data-part='content']
|
|
1138
|
+
> [data-part='title'] {
|
|
1139
|
+
grid-column: 2;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
[data-ui='timeline'][data-placement='alternate']
|
|
1143
|
+
[data-part='item']:nth-child(even)
|
|
1144
|
+
[data-part='content']
|
|
1145
|
+
> [data-part='time'],
|
|
1146
|
+
[data-ui='timeline'][data-placement='alternate']
|
|
1147
|
+
[data-side='start']
|
|
1148
|
+
[data-part='content']
|
|
1149
|
+
> [data-part='time'] {
|
|
1150
|
+
grid-column: 1;
|
|
1151
|
+
margin-inline: 0 var(--_gap);
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
[data-ui='timeline'][data-placement='alternate']
|
|
1155
|
+
[data-part='item']:nth-child(even)
|
|
1156
|
+
:is([data-part='actor'], [data-part='actions']),
|
|
1157
|
+
[data-ui='timeline'][data-placement='alternate']
|
|
1158
|
+
[data-side='start']
|
|
1159
|
+
:is([data-part='actor'], [data-part='actions']) {
|
|
1160
|
+
justify-content: flex-end;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
[data-ui='timeline'][data-placement='alternate'] [data-part='more'] {
|
|
1164
|
+
margin-inline-start: calc(50% + var(--_rail) / 2 + var(--_gap));
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
/* ── Horizontal ─────────────────────────────────────────────────────────
|
|
1168
|
+
*
|
|
1169
|
+
* The same grid turned on its side: the rail above the body, the line
|
|
1170
|
+
* running along the marker's centre to the next item, and the list rolling
|
|
1171
|
+
* in the inline axis when there are more events than width. Every item is
|
|
1172
|
+
* the same width, so the markers stay a track apart however long the
|
|
1173
|
+
* titles are.
|
|
1174
|
+
*/
|
|
1175
|
+
|
|
1176
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='list'] {
|
|
1177
|
+
display: grid;
|
|
1178
|
+
grid-auto-columns: minmax(
|
|
1179
|
+
var(--slotted-timeline-track-min, var(--slotted-space-12, 4rem)),
|
|
1180
|
+
1fr
|
|
1181
|
+
);
|
|
1182
|
+
grid-auto-flow: column;
|
|
1183
|
+
overflow-x: auto;
|
|
1184
|
+
overscroll-behavior-x: contain;
|
|
1185
|
+
/**
|
|
1186
|
+
* A scroll container clips what stands outside it, and the ring of the
|
|
1187
|
+
* current marker stands outside the rail by its offset and its width: the
|
|
1188
|
+
* list keeps that much room above and before the first marker, rounded
|
|
1189
|
+
* up to a whole pixel: the ring's 3.5 put every marker and every scene
|
|
1190
|
+
* below the list at half a pixel.
|
|
1191
|
+
*/
|
|
1192
|
+
padding-block: round(up, var(--_reach), 1px) var(--slotted-space-2, 0.25rem);
|
|
1193
|
+
padding-inline: round(up, var(--_reach), 1px);
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='item'] {
|
|
1197
|
+
/**
|
|
1198
|
+
* The rows keep their own height. Every item in the row is stretched to
|
|
1199
|
+
* the tallest, and `auto` rows would share that extra space out — which
|
|
1200
|
+
* put the marker of a one-line event seven pixels under its neighbours'.
|
|
1201
|
+
*/
|
|
1202
|
+
align-content: start;
|
|
1203
|
+
align-items: start;
|
|
1204
|
+
column-gap: 0;
|
|
1205
|
+
grid-template-columns: minmax(0, 1fr);
|
|
1206
|
+
grid-template-rows: [before] auto [rail] auto [after] auto;
|
|
1207
|
+
margin-block-end: 0;
|
|
1208
|
+
padding-inline-end: var(--_item-gap);
|
|
1209
|
+
/* The distance is on the cells, so an empty row above the rail costs nothing. */
|
|
1210
|
+
row-gap: 0;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='item']:last-child {
|
|
1214
|
+
padding-inline-end: 0;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
/**
|
|
1218
|
+
* A square as tall and as wide as the rail at the start of the item, with
|
|
1219
|
+
* the marker centred in it, so every centre sits half a rail in and the
|
|
1220
|
+
* line runs from one to the next along the same row.
|
|
1221
|
+
*/
|
|
1222
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='rail'] {
|
|
1223
|
+
align-items: start;
|
|
1224
|
+
align-self: start;
|
|
1225
|
+
block-size: var(--_rail);
|
|
1226
|
+
grid-column: 1;
|
|
1227
|
+
grid-row: rail;
|
|
1228
|
+
justify-content: center;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='marker'] {
|
|
1232
|
+
--_lift: 0px;
|
|
1233
|
+
|
|
1234
|
+
margin-inline-start: calc((var(--_rail) - var(--_marker)) / 2);
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='connector'] {
|
|
1238
|
+
/* Widths only: the colour and the dash are the rules above, for both edges. */
|
|
1239
|
+
border-block-start-width: var(--_rule);
|
|
1240
|
+
border-inline-start-width: 0;
|
|
1241
|
+
block-size: 0;
|
|
1242
|
+
inline-size: auto;
|
|
1243
|
+
inset-block-end: auto;
|
|
1244
|
+
inset-block-start: calc(50% - var(--_rule) / 2);
|
|
1245
|
+
inset-inline-end: calc(-1 * var(--_item-gap) - var(--_rail) / 2);
|
|
1246
|
+
inset-inline-start: calc(var(--_rail) / 2);
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='content'] {
|
|
1250
|
+
align-self: start;
|
|
1251
|
+
grid-column: 1;
|
|
1252
|
+
grid-row: after;
|
|
1253
|
+
margin-block: var(--_gap) 0;
|
|
1254
|
+
text-align: start;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='opposite'] {
|
|
1258
|
+
align-self: start;
|
|
1259
|
+
grid-column: 1;
|
|
1260
|
+
grid-row: before;
|
|
1261
|
+
margin-block: 0 var(--_gap);
|
|
1262
|
+
text-align: start;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
[data-ui='timeline'][data-orientation='horizontal'][data-placement='start'] [data-part='content'],
|
|
1266
|
+
[data-ui='timeline'][data-orientation='horizontal'][data-placement='alternate']
|
|
1267
|
+
[data-part='item']:nth-child(even)
|
|
1268
|
+
[data-part='content'] {
|
|
1269
|
+
grid-column: 1;
|
|
1270
|
+
grid-row: before;
|
|
1271
|
+
margin-block: 0 var(--_gap);
|
|
1272
|
+
text-align: start;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
[data-ui='timeline'][data-orientation='horizontal'][data-placement='start']
|
|
1276
|
+
[data-part='opposite'],
|
|
1277
|
+
[data-ui='timeline'][data-orientation='horizontal'][data-placement='alternate']
|
|
1278
|
+
[data-part='item']:nth-child(even)
|
|
1279
|
+
[data-part='opposite'] {
|
|
1280
|
+
grid-column: 1;
|
|
1281
|
+
grid-row: after;
|
|
1282
|
+
margin-block: var(--_gap) 0;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
/**
|
|
1286
|
+
* One column, as a flex column rather than as a one-column grid: the areas
|
|
1287
|
+
* the placements swap are then irrelevant, and the DOM order — title, time,
|
|
1288
|
+
* actor, description, actions — is the order a narrow body reads in.
|
|
1289
|
+
*/
|
|
1290
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='content'] {
|
|
1291
|
+
display: flex;
|
|
1292
|
+
flex-direction: column;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
/* On a line of its own the timestamp may wrap: nowrap is for the title's line. */
|
|
1296
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='content'] > [data-part='time'] {
|
|
1297
|
+
margin-inline: 0;
|
|
1298
|
+
white-space: normal;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
[data-ui='timeline'][data-orientation='horizontal']
|
|
1302
|
+
:is([data-part='actor'], [data-part='actions']) {
|
|
1303
|
+
justify-content: flex-start;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
[data-ui='timeline'][data-orientation='horizontal'] [data-part='more'] {
|
|
1307
|
+
margin-block-start: var(--_gap);
|
|
1308
|
+
margin-inline-start: 0;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/* ── Narrow width ───────────────────────────────────────────────────────
|
|
1312
|
+
*
|
|
1313
|
+
* Two things give way when the column is narrow. The timestamp leaves the
|
|
1314
|
+
* title's line and takes its own, so a title of nine words keeps the whole
|
|
1315
|
+
* measure; and below the breakpoint a horizontal timeline becomes a column
|
|
1316
|
+
* and an alternating one keeps to one side — the composition change section
|
|
1317
|
+
* 2.7 of `docs/component-features.md` asks for rather than a smaller version
|
|
1318
|
+
* of the same row. A timeline the consumer set to `reflow={false}` is left
|
|
1319
|
+
* alone.
|
|
1320
|
+
*
|
|
1321
|
+
* The breakpoints are literals because `@container (min-width: var(--x))` is
|
|
1322
|
+
* invalid CSS, which rule 4 of `docs/token-foundation.md` states.
|
|
1323
|
+
*/
|
|
1324
|
+
|
|
1325
|
+
@container slotted-timeline (max-width: 20rem) {
|
|
1326
|
+
[data-ui='timeline'][data-orientation='vertical'] [data-part='content'] {
|
|
1327
|
+
display: flex;
|
|
1328
|
+
flex-direction: column;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
[data-ui='timeline'][data-orientation='vertical'] [data-part='content'] > [data-part='time'] {
|
|
1332
|
+
margin-inline: 0;
|
|
1333
|
+
white-space: normal;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
/**
|
|
1337
|
+
* The opposite column gives way: eight rem of a twenty-rem column is the
|
|
1338
|
+
* body's measure. The opposite side takes the line above the body, and
|
|
1339
|
+
* the rail spans both.
|
|
1340
|
+
*/
|
|
1341
|
+
[data-ui='timeline'][data-orientation='vertical']:not([data-reflow='false'])
|
|
1342
|
+
[data-part='list']
|
|
1343
|
+
[data-part='item']:nth-child(n) {
|
|
1344
|
+
grid-template-columns: [rail] var(--_rail) [content] minmax(0, 1fr);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
[data-ui='timeline'][data-orientation='vertical']:not([data-reflow='false'])
|
|
1348
|
+
[data-part='item']:nth-child(n)
|
|
1349
|
+
> [data-part='opposite'] {
|
|
1350
|
+
grid-column: content;
|
|
1351
|
+
grid-row: 1;
|
|
1352
|
+
text-align: start;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
[data-ui='timeline'][data-orientation='vertical']:not([data-reflow='false'])
|
|
1356
|
+
[data-part='item']:nth-child(n):has(> [data-part='opposite'])
|
|
1357
|
+
> [data-part='content'] {
|
|
1358
|
+
grid-row: 2;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
[data-ui='timeline'][data-orientation='vertical']:not([data-reflow='false'])
|
|
1362
|
+
[data-part='item']:nth-child(n):has(> [data-part='opposite'])
|
|
1363
|
+
> [data-part='rail'] {
|
|
1364
|
+
grid-row: 1 / 3;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
[data-ui='timeline'][data-orientation='vertical']:not([data-reflow='false'])
|
|
1368
|
+
[data-part='item']:nth-child(n)
|
|
1369
|
+
> [data-part='content'] {
|
|
1370
|
+
grid-column: content;
|
|
1371
|
+
text-align: start;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
[data-ui='timeline'][data-orientation='vertical']:not([data-reflow='false'])
|
|
1375
|
+
[data-part='item']:nth-child(n)
|
|
1376
|
+
:is([data-part='actor'], [data-part='actions']) {
|
|
1377
|
+
justify-content: flex-start;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
[data-ui='timeline'][data-orientation='vertical']:not([data-reflow='false'])
|
|
1381
|
+
[data-part='more'] {
|
|
1382
|
+
margin-inline-start: calc(var(--_rail) + var(--_gap));
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
@container slotted-timeline (max-width: 30rem) {
|
|
1387
|
+
[data-ui='timeline'][data-orientation='horizontal']:not([data-reflow='false'])
|
|
1388
|
+
[data-part='list'] {
|
|
1389
|
+
display: flex;
|
|
1390
|
+
flex-direction: column;
|
|
1391
|
+
overflow-x: visible;
|
|
1392
|
+
padding: 0;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
[data-ui='timeline'][data-orientation='horizontal']:not([data-reflow='false'])
|
|
1396
|
+
[data-part='item'] {
|
|
1397
|
+
align-items: stretch;
|
|
1398
|
+
column-gap: var(--_gap);
|
|
1399
|
+
grid-template-columns: [rail] var(--_rail) [content] minmax(0, 1fr);
|
|
1400
|
+
grid-template-rows: none;
|
|
1401
|
+
margin-block-end: var(--_item-gap);
|
|
1402
|
+
padding-inline-end: 0;
|
|
1403
|
+
row-gap: 0;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
[data-ui='timeline'][data-orientation='horizontal']:not([data-reflow='false'])
|
|
1407
|
+
[data-part='item']:last-child {
|
|
1408
|
+
margin-block-end: 0;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
[data-ui='timeline'][data-orientation='horizontal']:not([data-reflow='false'])
|
|
1412
|
+
[data-part='rail'] {
|
|
1413
|
+
align-items: center;
|
|
1414
|
+
align-self: stretch;
|
|
1415
|
+
block-size: auto;
|
|
1416
|
+
grid-column: rail;
|
|
1417
|
+
/* Two rows when the opposite side takes the first; one row otherwise. */
|
|
1418
|
+
grid-row: 1 / 3;
|
|
1419
|
+
justify-content: flex-start;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
[data-ui='timeline'][data-orientation='horizontal']:not([data-reflow='false'])
|
|
1423
|
+
[data-part='marker'] {
|
|
1424
|
+
--_lift: round(nearest, calc((1lh - var(--_marker)) / 2), 1px);
|
|
1425
|
+
|
|
1426
|
+
margin-inline-start: 0;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
[data-ui='timeline'][data-orientation='horizontal']:not([data-reflow='false'])
|
|
1430
|
+
[data-part='connector'] {
|
|
1431
|
+
border-block-start-width: 0;
|
|
1432
|
+
border-inline-start-width: var(--_rule);
|
|
1433
|
+
block-size: auto;
|
|
1434
|
+
inline-size: 0;
|
|
1435
|
+
inset-block-end: calc(-0.5lh - var(--_item-gap));
|
|
1436
|
+
inset-block-start: 0.5lh;
|
|
1437
|
+
inset-inline-end: auto;
|
|
1438
|
+
inset-inline-start: calc(50% - var(--_rule) / 2);
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
/**
|
|
1442
|
+
* `:nth-child(n)` weighs the same as the parity the alternate rules name,
|
|
1443
|
+
* so the column wins over them here; a container query adds no weight of
|
|
1444
|
+
* its own.
|
|
1445
|
+
*/
|
|
1446
|
+
[data-ui='timeline'][data-orientation='horizontal']:not([data-reflow='false'])
|
|
1447
|
+
[data-part='item']:nth-child(n)
|
|
1448
|
+
> [data-part='opposite'] {
|
|
1449
|
+
align-self: baseline;
|
|
1450
|
+
grid-column: content;
|
|
1451
|
+
grid-row: 1;
|
|
1452
|
+
margin-block: 0;
|
|
1453
|
+
text-align: start;
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
[data-ui='timeline'][data-orientation='horizontal']:not([data-reflow='false'])
|
|
1457
|
+
[data-part='item']:nth-child(n)
|
|
1458
|
+
> [data-part='content'] {
|
|
1459
|
+
align-self: baseline;
|
|
1460
|
+
grid-column: content;
|
|
1461
|
+
grid-row: auto;
|
|
1462
|
+
margin-block: 0;
|
|
1463
|
+
text-align: start;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
[data-ui='timeline'][data-orientation='horizontal']:not([data-reflow='false'])
|
|
1467
|
+
[data-part='more'] {
|
|
1468
|
+
margin-block-start: var(--_item-gap);
|
|
1469
|
+
margin-inline-start: calc(var(--_rail) + var(--_gap));
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
/**
|
|
1473
|
+
* Alternate keeps one side: two columns of a hundred and eighty pixels each
|
|
1474
|
+
* are two columns of three words. The opposite side takes the line above
|
|
1475
|
+
* the body, in reading order.
|
|
1476
|
+
*/
|
|
1477
|
+
[data-ui='timeline'][data-orientation='vertical'][data-placement='alternate']:not(
|
|
1478
|
+
[data-reflow='false']
|
|
1479
|
+
)
|
|
1480
|
+
[data-part='item'] {
|
|
1481
|
+
grid-template-columns: [rail] var(--_rail) [content] minmax(0, 1fr);
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
[data-ui='timeline'][data-orientation='vertical'][data-placement='alternate']:not(
|
|
1485
|
+
[data-reflow='false']
|
|
1486
|
+
)
|
|
1487
|
+
[data-part='item']
|
|
1488
|
+
:is([data-part='content'], [data-part='opposite']) {
|
|
1489
|
+
grid-column: content;
|
|
1490
|
+
text-align: start;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
[data-ui='timeline'][data-orientation='vertical'][data-placement='alternate']:not(
|
|
1494
|
+
[data-reflow='false']
|
|
1495
|
+
)
|
|
1496
|
+
[data-part='item']
|
|
1497
|
+
[data-part='opposite'] {
|
|
1498
|
+
grid-row: 1;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
[data-ui='timeline'][data-orientation='vertical'][data-placement='alternate']:not(
|
|
1502
|
+
[data-reflow='false']
|
|
1503
|
+
)
|
|
1504
|
+
[data-part='item']:has(> [data-part='opposite'])
|
|
1505
|
+
> [data-part='content'] {
|
|
1506
|
+
grid-row: 2;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
[data-ui='timeline'][data-orientation='vertical'][data-placement='alternate']:not(
|
|
1510
|
+
[data-reflow='false']
|
|
1511
|
+
)
|
|
1512
|
+
[data-part='item']:has(> [data-part='opposite'])
|
|
1513
|
+
> [data-part='rail'] {
|
|
1514
|
+
grid-row: 1 / 3;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
[data-ui='timeline'][data-orientation='vertical'][data-placement='alternate']:not(
|
|
1518
|
+
[data-reflow='false']
|
|
1519
|
+
)
|
|
1520
|
+
[data-part='item']:nth-child(n)
|
|
1521
|
+
[data-part='content'] {
|
|
1522
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
[data-ui='timeline'][data-orientation='vertical'][data-placement='alternate']:not(
|
|
1526
|
+
[data-reflow='false']
|
|
1527
|
+
)
|
|
1528
|
+
[data-part='item']:nth-child(n)
|
|
1529
|
+
[data-part='content']
|
|
1530
|
+
> [data-part='title'] {
|
|
1531
|
+
grid-column: 1;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
[data-ui='timeline'][data-orientation='vertical'][data-placement='alternate']:not(
|
|
1535
|
+
[data-reflow='false']
|
|
1536
|
+
)
|
|
1537
|
+
[data-part='item']:nth-child(n)
|
|
1538
|
+
[data-part='content']
|
|
1539
|
+
> [data-part='time'] {
|
|
1540
|
+
grid-column: 2;
|
|
1541
|
+
margin-inline: var(--_gap) 0;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
[data-ui='timeline'][data-orientation='vertical'][data-placement='alternate']:not(
|
|
1545
|
+
[data-reflow='false']
|
|
1546
|
+
)
|
|
1547
|
+
[data-part='item']
|
|
1548
|
+
:is([data-part='actor'], [data-part='actions']) {
|
|
1549
|
+
justify-content: flex-start;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
[data-ui='timeline'][data-orientation='vertical'][data-placement='alternate']:not(
|
|
1553
|
+
[data-reflow='false']
|
|
1554
|
+
)
|
|
1555
|
+
[data-part='more'] {
|
|
1556
|
+
margin-inline-start: calc(var(--_rail) + var(--_gap));
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
/* ── Forced colours ─────────────────────────────────────────────────────
|
|
1561
|
+
*
|
|
1562
|
+
* The system replaces every painted surface with the page's own background
|
|
1563
|
+
* and every border with one ink, and drops every shadow. The shapes survive
|
|
1564
|
+
* that — core, hollow, filled, filled and ringed — because the filled disc
|
|
1565
|
+
* is drawn in borders, the core keeps the system's text ink through
|
|
1566
|
+
* `forced-color-adjust`, and the current ring is redrawn here as an outline.
|
|
1567
|
+
* A finished marker keeps its fill, so it reads apart from a pending one in
|
|
1568
|
+
* the system's highlight. The chevron and the check are `Glyph` elements
|
|
1569
|
+
* drawn in `currentColor`, which the system has already forced.
|
|
1570
|
+
*/
|
|
1571
|
+
|
|
1572
|
+
@media (forced-colors: active) {
|
|
1573
|
+
/* The core in the marker's own ink, which the system has already forced. */
|
|
1574
|
+
[data-ui='timeline'] [data-part='marker']:empty::after {
|
|
1575
|
+
background-color: currentColor;
|
|
1576
|
+
forced-color-adjust: none;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
[data-ui='timeline'] [data-complete]:not([data-current]) [data-part='marker'] {
|
|
1580
|
+
background-color: Highlight;
|
|
1581
|
+
border-color: Highlight;
|
|
1582
|
+
color: HighlightText;
|
|
1583
|
+
forced-color-adjust: none;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
/* The check in the finished disc's forced ink, not the author's ground. */
|
|
1587
|
+
[data-ui='timeline'] [data-part='marker'] > [data-ui='icon'][data-check] {
|
|
1588
|
+
color: inherit;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
[data-ui='timeline'] [data-current]:not([data-loading]) [data-part='marker'] {
|
|
1592
|
+
outline: var(--_edge) solid CanvasText;
|
|
1593
|
+
outline-offset: var(--slotted-border-width-thick, 2px);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|