@ptbdynamic/plinth 0.0.0-stage → 0.2.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.
Files changed (150) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +258 -2
  3. package/package.json +99 -4
  4. package/packages/css/dist/avatar.css +122 -0
  5. package/packages/css/dist/badge.css +76 -0
  6. package/packages/css/dist/button.css +273 -0
  7. package/packages/css/dist/callout.css +143 -0
  8. package/packages/css/dist/code-block.css +283 -0
  9. package/packages/css/dist/confirm-dialog.css +183 -0
  10. package/packages/css/dist/data-table.css +470 -0
  11. package/packages/css/dist/dialog.css +113 -0
  12. package/packages/css/dist/drawer.css +156 -0
  13. package/packages/css/dist/fonts/geist/LICENSE +93 -0
  14. package/packages/css/dist/fonts/geist/geist-cyrillic-ext-wght-normal.woff2 +0 -0
  15. package/packages/css/dist/fonts/geist/geist-cyrillic-wght-normal.woff2 +0 -0
  16. package/packages/css/dist/fonts/geist/geist-latin-ext-wght-normal.woff2 +0 -0
  17. package/packages/css/dist/fonts/geist/geist-latin-wght-normal.woff2 +0 -0
  18. package/packages/css/dist/fonts/geist/geist-vietnamese-wght-normal.woff2 +0 -0
  19. package/packages/css/dist/fonts/geist-mono/LICENSE +93 -0
  20. package/packages/css/dist/fonts/geist-mono/geist-mono-cyrillic-ext-wght-normal.woff2 +0 -0
  21. package/packages/css/dist/fonts/geist-mono/geist-mono-cyrillic-wght-normal.woff2 +0 -0
  22. package/packages/css/dist/fonts/geist-mono/geist-mono-latin-ext-wght-normal.woff2 +0 -0
  23. package/packages/css/dist/fonts/geist-mono/geist-mono-latin-wght-normal.woff2 +0 -0
  24. package/packages/css/dist/fonts/geist-mono/geist-mono-symbols2-wght-normal.woff2 +0 -0
  25. package/packages/css/dist/fonts/geist-mono/geist-mono-vietnamese-wght-normal.woff2 +0 -0
  26. package/packages/css/dist/fonts/index.css +109 -0
  27. package/packages/css/dist/header.css +110 -0
  28. package/packages/css/dist/icon.css +51 -0
  29. package/packages/css/dist/list-card.css +76 -0
  30. package/packages/css/dist/list-row.css +164 -0
  31. package/packages/css/dist/menu-sheet.css +84 -0
  32. package/packages/css/dist/menu.css +245 -0
  33. package/packages/css/dist/modal.css +367 -0
  34. package/packages/css/dist/page-header.css +124 -0
  35. package/packages/css/dist/pill-row.css +197 -0
  36. package/packages/css/dist/plinth.css +4446 -0
  37. package/packages/css/dist/section-menu.css +226 -0
  38. package/packages/css/dist/sheet.css +239 -0
  39. package/packages/css/dist/text-field.css +230 -0
  40. package/packages/css/dist/textarea.css +169 -0
  41. package/packages/css/dist/tokens.css +413 -0
  42. package/packages/react/dist/PlinthAvatar.d.ts +17 -0
  43. package/packages/react/dist/PlinthBadge.d.ts +7 -0
  44. package/packages/react/dist/PlinthButton.d.ts +29 -0
  45. package/packages/react/dist/PlinthCallout.d.ts +16 -0
  46. package/packages/react/dist/PlinthCodeBlock.d.ts +24 -0
  47. package/packages/react/dist/PlinthConfirmDialog.d.ts +38 -0
  48. package/packages/react/dist/PlinthDataTable.d.ts +11 -0
  49. package/packages/react/dist/PlinthDataTableCell.d.ts +15 -0
  50. package/packages/react/dist/PlinthDataTableColumn.d.ts +13 -0
  51. package/packages/react/dist/PlinthDataTableEmpty.d.ts +9 -0
  52. package/packages/react/dist/PlinthDataTableRow.d.ts +9 -0
  53. package/packages/react/dist/PlinthDataTableSort.d.ts +4 -0
  54. package/packages/react/dist/PlinthDialog.d.ts +26 -0
  55. package/packages/react/dist/PlinthDrawer.d.ts +29 -0
  56. package/packages/react/dist/PlinthIcon.d.ts +10 -0
  57. package/packages/react/dist/PlinthIconButton.d.ts +26 -0
  58. package/packages/react/dist/PlinthListCard.d.ts +14 -0
  59. package/packages/react/dist/PlinthListRow.d.ts +29 -0
  60. package/packages/react/dist/PlinthMenu.d.ts +12 -0
  61. package/packages/react/dist/PlinthMenuGroup.d.ts +9 -0
  62. package/packages/react/dist/PlinthMenuItem.d.ts +26 -0
  63. package/packages/react/dist/PlinthMenuSeparator.d.ts +4 -0
  64. package/packages/react/dist/PlinthMenuSheet.d.ts +24 -0
  65. package/packages/react/dist/PlinthPageHeader.d.ts +17 -0
  66. package/packages/react/dist/PlinthPill.d.ts +17 -0
  67. package/packages/react/dist/PlinthPillRow.d.ts +13 -0
  68. package/packages/react/dist/PlinthSectionMenu.d.ts +11 -0
  69. package/packages/react/dist/PlinthSectionMenuItem.d.ts +20 -0
  70. package/packages/react/dist/PlinthSheet.d.ts +26 -0
  71. package/packages/react/dist/PlinthTextField.d.ts +24 -0
  72. package/packages/react/dist/PlinthTextarea.d.ts +24 -0
  73. package/packages/react/dist/avatar.d.ts +12 -0
  74. package/packages/react/dist/button.d.ts +21 -0
  75. package/packages/react/dist/callout.d.ts +19 -0
  76. package/packages/react/dist/code-block.d.ts +16 -0
  77. package/packages/react/dist/confirm-dialog.d.ts +23 -0
  78. package/packages/react/dist/data-table.d.ts +15 -0
  79. package/packages/react/dist/dialog.d.ts +10 -0
  80. package/packages/react/dist/drawer.d.ts +20 -0
  81. package/packages/react/dist/heading.d.ts +5 -0
  82. package/packages/react/dist/icon.d.ts +5 -0
  83. package/packages/react/dist/index.d.ts +49 -0
  84. package/packages/react/dist/index.js +1326 -0
  85. package/packages/react/dist/list-row.d.ts +5 -0
  86. package/packages/react/dist/markup.d.ts +9 -0
  87. package/packages/react/dist/menu.d.ts +7 -0
  88. package/packages/react/dist/page-header.d.ts +5 -0
  89. package/packages/react/dist/sheet.d.ts +12 -0
  90. package/packages/react/dist/size.d.ts +13 -0
  91. package/packages/react/dist/swipe.d.ts +15 -0
  92. package/packages/react/dist/text-field.d.ts +10 -0
  93. package/packages/react/dist/tones.d.ts +5 -0
  94. package/packages/tokens/dist/index.d.ts +230 -0
  95. package/packages/tokens/dist/index.js +4091 -0
  96. package/packages/tokens/dist/tailwind-theme.css +80 -0
  97. package/packages/tokens/dist/tokens.css +413 -0
  98. package/packages/tokens/dist/tokens.json +3875 -0
  99. package/packages/vue/dist/PlinthAvatar.vue.d.ts +24 -0
  100. package/packages/vue/dist/PlinthBadge.vue.d.ts +21 -0
  101. package/packages/vue/dist/PlinthButton.vue.d.ts +42 -0
  102. package/packages/vue/dist/PlinthCallout.vue.d.ts +31 -0
  103. package/packages/vue/dist/PlinthCodeBlock.vue.d.ts +49 -0
  104. package/packages/vue/dist/PlinthConfirmDialog.vue.d.ts +51 -0
  105. package/packages/vue/dist/PlinthDataTable.vue.d.ts +21 -0
  106. package/packages/vue/dist/PlinthDataTableCell.vue.d.ts +29 -0
  107. package/packages/vue/dist/PlinthDataTableColumn.vue.d.ts +26 -0
  108. package/packages/vue/dist/PlinthDataTableEmpty.vue.d.ts +19 -0
  109. package/packages/vue/dist/PlinthDataTableRow.vue.d.ts +19 -0
  110. package/packages/vue/dist/PlinthDataTableSort.vue.d.ts +13 -0
  111. package/packages/vue/dist/PlinthDialog.vue.d.ts +45 -0
  112. package/packages/vue/dist/PlinthDrawer.vue.d.ts +48 -0
  113. package/packages/vue/dist/PlinthIcon.vue.d.ts +23 -0
  114. package/packages/vue/dist/PlinthIconButton.vue.d.ts +37 -0
  115. package/packages/vue/dist/PlinthListCard.vue.d.ts +26 -0
  116. package/packages/vue/dist/PlinthListRow.vue.d.ts +38 -0
  117. package/packages/vue/dist/PlinthMenu.vue.d.ts +24 -0
  118. package/packages/vue/dist/PlinthMenuGroup.vue.d.ts +17 -0
  119. package/packages/vue/dist/PlinthMenuItem.vue.d.ts +34 -0
  120. package/packages/vue/dist/PlinthMenuSeparator.vue.d.ts +3 -0
  121. package/packages/vue/dist/PlinthMenuSheet.vue.d.ts +48 -0
  122. package/packages/vue/dist/PlinthPageHeader.vue.d.ts +27 -0
  123. package/packages/vue/dist/PlinthPill.vue.d.ts +28 -0
  124. package/packages/vue/dist/PlinthPillRow.vue.d.ts +22 -0
  125. package/packages/vue/dist/PlinthSectionMenu.vue.d.ts +22 -0
  126. package/packages/vue/dist/PlinthSectionMenuItem.vue.d.ts +28 -0
  127. package/packages/vue/dist/PlinthSheet.vue.d.ts +45 -0
  128. package/packages/vue/dist/PlinthTextField.vue.d.ts +51 -0
  129. package/packages/vue/dist/PlinthTextarea.vue.d.ts +42 -0
  130. package/packages/vue/dist/avatar.d.ts +12 -0
  131. package/packages/vue/dist/button.d.ts +5 -0
  132. package/packages/vue/dist/callout.d.ts +19 -0
  133. package/packages/vue/dist/code-block.d.ts +16 -0
  134. package/packages/vue/dist/confirm-dialog.d.ts +23 -0
  135. package/packages/vue/dist/data-table.d.ts +15 -0
  136. package/packages/vue/dist/dialog.d.ts +10 -0
  137. package/packages/vue/dist/drawer.d.ts +20 -0
  138. package/packages/vue/dist/heading.d.ts +5 -0
  139. package/packages/vue/dist/icon.d.ts +5 -0
  140. package/packages/vue/dist/index.d.ts +53 -0
  141. package/packages/vue/dist/index.js +1732 -0
  142. package/packages/vue/dist/list-row.d.ts +5 -0
  143. package/packages/vue/dist/menu.d.ts +8 -0
  144. package/packages/vue/dist/page-header.d.ts +5 -0
  145. package/packages/vue/dist/sheet.d.ts +12 -0
  146. package/packages/vue/dist/size.d.ts +13 -0
  147. package/packages/vue/dist/slots.d.ts +3 -0
  148. package/packages/vue/dist/swipe.d.ts +12 -0
  149. package/packages/vue/dist/text-field.d.ts +10 -0
  150. package/packages/vue/dist/tones.d.ts +5 -0
@@ -0,0 +1,124 @@
1
+ /*
2
+ * Page header: the bar at the top of a page, with a leading action, the page's heading and
3
+ * trailing actions. On a phone it is the screen's top bar; in an app shell it heads the page beside
4
+ * the sidebar, under the app bar. It sticks to the top as the content scrolls under it.
5
+ *
6
+ * <header class="plinth-page-header" data-top>
7
+ * <div class="plinth-page-header-leading">
8
+ * <a class="plinth-button plinth-icon-button" href="/inbox" data-variant="ghost"
9
+ * data-size="md" aria-label="Back">
10
+ * <span class="plinth-icon" data-size="md" data-mirror aria-hidden="true"><svg>…</svg></span>
11
+ * </a>
12
+ * </div>
13
+ * <h1 class="plinth-page-header-heading">Inbox</h1>
14
+ * <div class="plinth-page-header-actions">
15
+ * <button type="button" class="plinth-button plinth-icon-button" data-variant="ghost"
16
+ * data-size="md" aria-label="Search">…</button>
17
+ * </div>
18
+ * </header>
19
+ *
20
+ * The root is a <header>. At the top of the page (not inside <main>, <article>, <section>, <aside>
21
+ * or <nav>) it is the page's banner landmark, so a page has one there; inside <main>, as in an app
22
+ * shell, it is no landmark, only the page's header. The heading is required: an <h1> by default, or
23
+ * <h2> to <h6> (level) when the page sits beside another page's <h1>, such as an open ticket beside
24
+ * the list on a wide screen. The level doesn't change the look. The heading stays on one line and
25
+ * ends in an ellipsis when it doesn't fit.
26
+ *
27
+ * The leading part holds one action, usually an icon button: a menu button that opens a sheet
28
+ * (commandfor and command="show-modal") on a top-level page, or a back link (with data-mirror on
29
+ * its icon so it points the other way in right-to-left text) on a page under it. The actions part
30
+ * holds the trailing actions: at most three icon buttons (put the rest in a menu), or a primary
31
+ * button such as New ticket. Both are optional, and printed only when they have content. Every
32
+ * icon button needs its own name (label). The page header needs button.css and icon.css for them.
33
+ *
34
+ * Variant (the app sets it, the page header doesn't guess):
35
+ * - data-top: the page header is the screen's top bar, at the very top of a phone's screen. It
36
+ * adds env(safe-area-inset-top) above its height, which pads it below the status bar and the
37
+ * notch on a phone that draws under them (viewport-fit=cover). Leave it off under an app bar.
38
+ *
39
+ * Its height is the page-header.height component token (56px). The inline padding clears the
40
+ * notch on a phone held sideways. It is sticky on the layer.sticky z-index, so it sits above the
41
+ * page and below sheets and menus (the top layer), and it sticks --plinth-page-header-offset from
42
+ * the top: 0 by default, or the app bar's height in a shell that has one. Content scrolls under
43
+ * it, so the app sets scroll-padding-block-start on its scrolling element (the offset plus the
44
+ * height, plus env(safe-area-inset-top) with data-top) to keep a focused element or an anchor's
45
+ * target from landing under the page header.
46
+ *
47
+ * The actions sit var(--plinth-space-2) apart, so on a touch screen the 40px hit areas of 32px
48
+ * icon buttons don't overlap.
49
+ *
50
+ * The app owns the state: the page header has no states of its own. What the actions do is the
51
+ * app's (a link, a commandfor, wire:click, @click on the icon button).
52
+ */
53
+
54
+ @layer plinth {
55
+ .plinth-page-header {
56
+ position: sticky;
57
+ inset-block-start: var(--plinth-page-header-offset);
58
+ z-index: var(--plinth-layer-sticky);
59
+ box-sizing: border-box;
60
+ display: flex;
61
+ gap: var(--plinth-space-2);
62
+ align-items: center;
63
+ min-block-size: var(--plinth-page-header-height);
64
+ padding-inline: max(var(--plinth-space-2), env(safe-area-inset-left))
65
+ max(var(--plinth-space-2), env(safe-area-inset-right));
66
+ font-family: var(--plinth-font-family-body);
67
+ color: var(--plinth-color-text);
68
+ background-color: var(--plinth-color-surface);
69
+ border-block-end: var(--plinth-border-width-thin) solid var(--plinth-color-divider);
70
+ }
71
+
72
+ .plinth-page-header:dir(rtl) {
73
+ padding-inline: max(var(--plinth-space-2), env(safe-area-inset-right))
74
+ max(var(--plinth-space-2), env(safe-area-inset-left));
75
+ }
76
+
77
+ /* The screen's top bar clears the status bar and the notch. */
78
+ .plinth-page-header[data-top] {
79
+ min-block-size: calc(var(--plinth-page-header-height) + env(safe-area-inset-top));
80
+ padding-block-start: env(safe-area-inset-top);
81
+ }
82
+
83
+ .plinth-page-header-leading,
84
+ .plinth-page-header-actions {
85
+ display: flex;
86
+ flex: none;
87
+ gap: var(--plinth-space-2);
88
+ align-items: center;
89
+ }
90
+
91
+ .plinth-page-header-heading {
92
+ flex: 1 1 auto;
93
+ min-inline-size: 0;
94
+ margin: 0;
95
+ overflow: hidden;
96
+ text-overflow: ellipsis;
97
+ font-size: var(--plinth-font-size-lg);
98
+ font-weight: var(--plinth-font-weight-semibold);
99
+ line-height: var(--plinth-font-leading-tight);
100
+ letter-spacing: var(--plinth-font-tracking-tight);
101
+ white-space: nowrap;
102
+ }
103
+
104
+ /* Without a leading action or trailing actions, the heading keeps the text's distance from the edge. */
105
+ .plinth-page-header-heading:first-child {
106
+ margin-inline-start: var(--plinth-space-2);
107
+ }
108
+
109
+ .plinth-page-header-heading:last-child {
110
+ margin-inline-end: var(--plinth-space-2);
111
+ }
112
+
113
+ @media (min-width: 768px) {
114
+ .plinth-page-header {
115
+ padding-inline: max(var(--plinth-space-4), env(safe-area-inset-left))
116
+ max(var(--plinth-space-4), env(safe-area-inset-right));
117
+ }
118
+
119
+ .plinth-page-header:dir(rtl) {
120
+ padding-inline: max(var(--plinth-space-4), env(safe-area-inset-right))
121
+ max(var(--plinth-space-4), env(safe-area-inset-left));
122
+ }
123
+ }
124
+ }
@@ -0,0 +1,197 @@
1
+ /*
2
+ * Pill row: a row of pills for filters, segments or sub-pages.
3
+ *
4
+ * <div class="plinth-pill-row" role="group" aria-label="Status">
5
+ * <button type="button" class="plinth-pill" aria-pressed="true">
6
+ * <span class="plinth-pill-label">Open</span>
7
+ * <span class="plinth-pill-count">12</span>
8
+ * </button>
9
+ * <button type="button" class="plinth-pill" aria-pressed="false">
10
+ * <span class="plinth-pill-label">Closed</span>
11
+ * </button>
12
+ * </div>
13
+ *
14
+ * The root is a <div role="group">, named by aria-label (label in Blade and Vue) or by the app's
15
+ * own aria-labelledby. A row of links that navigates is <nav class="plinth-pill-row"> instead,
16
+ * with no role (nav in Blade and Vue), and its pills are links:
17
+ *
18
+ * <a class="plinth-pill" href="…" aria-current="page"><span class="plinth-pill-label">…</span></a>
19
+ *
20
+ * Each pill is its own component (<x-plinth::pill>, PlinthPill), so the app's attributes and
21
+ * listeners land on the pill (ADR 2). The count is optional. plinth-pill-label has no rule of its
22
+ * own: it is a hook for a project's styles.
23
+ *
24
+ * States, set by the app:
25
+ * - selected: a button pill always prints aria-pressed, "true" or "false"; a link pill prints
26
+ * aria-current="page" for the page being shown. Selected takes the selection tint
27
+ * (accent-subtle, accent-text) inside a 2px accent edge (border-width.thick), where the others
28
+ * have a 1px neutral one, so colour is not its only cue. A pressed button still answers hover
29
+ * and press with a step on the tint (accent-subtle-hover, accent-subtle-active).
30
+ * - disabled: `disabled` on a <button>; on a link, no href, role="link" and aria-disabled="true".
31
+ * - hover only where the device can hover; the focus ring on :focus-visible.
32
+ *
33
+ * Layout: on a phone the row scrolls sideways, with no visible scrollbar, and snaps to the pills;
34
+ * from 768px it wraps. The row's padding keeps the focus ring and the 40px touch target of the
35
+ * pills inside the scrolling area, whatever --plinth-pill-height is (32px by default). A pill is
36
+ * at least 40px wide.
37
+ */
38
+
39
+ @layer plinth {
40
+ .plinth-pill-row {
41
+ box-sizing: border-box;
42
+ display: flex;
43
+ gap: var(--plinth-space-2);
44
+ align-items: center;
45
+ max-inline-size: 100%;
46
+ padding-block: max(
47
+ var(--plinth-space-1),
48
+ (var(--plinth-touch-target) - var(--plinth-pill-height)) / 2
49
+ );
50
+ padding-inline: var(--plinth-space-1);
51
+ margin: 0;
52
+ overflow-x: auto;
53
+ overscroll-behavior-inline: contain;
54
+ scroll-snap-type: inline proximity;
55
+ scroll-padding-inline: var(--plinth-space-1);
56
+ scrollbar-width: none;
57
+ }
58
+
59
+ .plinth-pill {
60
+ position: relative;
61
+ box-sizing: border-box;
62
+ display: inline-flex;
63
+ flex: none;
64
+ gap: var(--plinth-space-2);
65
+ align-items: center;
66
+ justify-content: center;
67
+ min-inline-size: var(--plinth-touch-target);
68
+ min-block-size: var(--plinth-pill-height);
69
+ padding-block: 0;
70
+ padding-inline: var(--plinth-space-3);
71
+ margin: 0;
72
+ font-family: var(--plinth-font-family-body);
73
+ font-size: var(--plinth-font-size-sm);
74
+ font-weight: var(--plinth-font-weight-medium);
75
+ line-height: var(--plinth-font-leading-tight);
76
+ color: var(--plinth-color-text);
77
+ white-space: nowrap;
78
+ text-decoration: none;
79
+ cursor: pointer;
80
+ user-select: none;
81
+ scroll-snap-align: start;
82
+ background-color: transparent;
83
+ border: var(--plinth-border-width-thin) solid var(--plinth-color-border-strong);
84
+ border-radius: var(--plinth-radius-pill);
85
+ transition:
86
+ background-color var(--plinth-duration-fast) var(--plinth-easing-standard),
87
+ border-color var(--plinth-duration-fast) var(--plinth-easing-standard),
88
+ box-shadow var(--plinth-duration-fast) var(--plinth-easing-standard),
89
+ color var(--plinth-duration-fast) var(--plinth-easing-standard);
90
+ }
91
+
92
+ /* A 40px touch target through an invisible hit area, as on the button (ADR 3). */
93
+ @media (pointer: coarse) {
94
+ .plinth-pill::before {
95
+ position: absolute;
96
+ inset-block-start: 50%;
97
+ inset-inline: 0;
98
+ block-size: max(100%, var(--plinth-touch-target));
99
+ content: '';
100
+ translate: 0 -50%;
101
+ }
102
+ }
103
+
104
+ @media (hover: hover) {
105
+ a.plinth-pill[href]:not([aria-current='page']):hover,
106
+ button.plinth-pill:enabled:not([aria-pressed='true']):hover {
107
+ background-color: var(--plinth-color-surface-hover);
108
+ }
109
+ }
110
+
111
+ a.plinth-pill[href]:not([aria-current='page']):active,
112
+ button.plinth-pill:enabled:not([aria-pressed='true']):active {
113
+ background-color: var(--plinth-color-surface-sunken);
114
+ }
115
+
116
+ /* The border and an inset ring make the 2px edge, so selecting doesn't move the label. */
117
+ .plinth-pill:is([aria-pressed='true'], [aria-current='page']) {
118
+ color: var(--plinth-color-accent-text);
119
+ background-color: var(--plinth-color-accent-subtle);
120
+ border-color: var(--plinth-color-accent);
121
+ box-shadow: inset 0 0 0 calc(var(--plinth-border-width-thick) - var(--plinth-border-width-thin))
122
+ var(--plinth-color-accent);
123
+ }
124
+
125
+ /*
126
+ * A pressed button can be pressed again, so it answers hover and press with a step on the tint.
127
+ * Not in forced colours, where the tint would replace the system highlight under the label.
128
+ */
129
+ @media (hover: hover) and (forced-colors: none) {
130
+ button.plinth-pill:enabled[aria-pressed='true']:hover {
131
+ background-color: var(--plinth-color-accent-subtle-hover);
132
+ }
133
+ }
134
+
135
+ @media (forced-colors: none) {
136
+ button.plinth-pill:enabled[aria-pressed='true']:active {
137
+ background-color: var(--plinth-color-accent-subtle-active);
138
+ }
139
+ }
140
+
141
+ .plinth-pill:disabled,
142
+ .plinth-pill[aria-disabled='true'] {
143
+ cursor: not-allowed;
144
+ opacity: var(--plinth-opacity-disabled);
145
+ }
146
+
147
+ .plinth-pill:focus-visible {
148
+ outline: var(--plinth-focus-ring-width) solid var(--plinth-color-focus-ring);
149
+ outline-offset: var(--plinth-focus-ring-offset);
150
+ }
151
+
152
+ /* A gap between the ring and the accent edge, so focus and selection read apart. */
153
+ .plinth-pill:is([aria-pressed='true'], [aria-current='page']):focus-visible {
154
+ outline-offset: var(--plinth-focus-ring-offset-filled);
155
+ }
156
+
157
+ .plinth-pill-count {
158
+ font-weight: var(--plinth-font-weight-regular);
159
+ font-variant-numeric: tabular-nums;
160
+ color: var(--plinth-color-text-muted);
161
+ }
162
+
163
+ .plinth-pill:is([aria-pressed='true'], [aria-current='page']) .plinth-pill-count {
164
+ color: inherit;
165
+ }
166
+
167
+ /* Wider screens have room: the pills wrap onto more lines instead of scrolling. */
168
+ @media (min-width: 768px) {
169
+ .plinth-pill-row {
170
+ flex-wrap: wrap;
171
+ overflow-x: visible;
172
+ }
173
+ }
174
+
175
+ @media (forced-colors: active) {
176
+ .plinth-pill {
177
+ border-color: ButtonText;
178
+ }
179
+
180
+ .plinth-pill:is([aria-pressed='true'], [aria-current='page']) {
181
+ color: HighlightText;
182
+ background-color: Highlight;
183
+ border-color: Highlight;
184
+ }
185
+
186
+ .plinth-pill:is([aria-pressed='true'], [aria-current='page']) .plinth-pill-count {
187
+ color: HighlightText;
188
+ }
189
+
190
+ .plinth-pill:disabled,
191
+ .plinth-pill[aria-disabled='true'] {
192
+ color: GrayText;
193
+ background-color: Canvas;
194
+ border-color: GrayText;
195
+ }
196
+ }
197
+ }