@hearthsound/design 0.0.0-stage → 0.1.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 (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -2
  3. package/THIRD-PARTY.md +46 -0
  4. package/css/base.css +245 -0
  5. package/css/components/admin.css +257 -0
  6. package/css/components/banner.css +140 -0
  7. package/css/components/button.css +309 -0
  8. package/css/components/card.css +339 -0
  9. package/css/components/check.css +202 -0
  10. package/css/components/dialog.css +85 -0
  11. package/css/components/field.css +296 -0
  12. package/css/components/list.css +260 -0
  13. package/css/components/menu.css +282 -0
  14. package/css/components/page-header.css +230 -0
  15. package/css/components/pill.css +101 -0
  16. package/css/components/player.css +524 -0
  17. package/css/components/progress.css +173 -0
  18. package/css/components/section.css +86 -0
  19. package/css/components/segmented.css +64 -0
  20. package/css/components/shell.css +281 -0
  21. package/css/components/sidebar.css +170 -0
  22. package/css/components/slider.css +92 -0
  23. package/css/components/status-page.css +48 -0
  24. package/css/components/stepper.css +130 -0
  25. package/css/components/toast.css +88 -0
  26. package/css/components/tooltip.css +29 -0
  27. package/css/components/track.css +336 -0
  28. package/css/components/upload.css +70 -0
  29. package/css/index.css +35 -0
  30. package/css/tokens.css +375 -0
  31. package/dist/icons.d.ts +56 -0
  32. package/dist/icons.js +56 -0
  33. package/dist/icons.svg +55 -0
  34. package/fonts/OFL-BricolageGrotesque.txt +93 -0
  35. package/fonts/OFL-Geist.txt +92 -0
  36. package/fonts/bricolage-var.woff2 +0 -0
  37. package/fonts/geist-mono.woff2 +0 -0
  38. package/fonts/geist-var.woff2 +0 -0
  39. package/icons/LICENSE +10 -0
  40. package/icons/adwaita-account.svg +1 -0
  41. package/icons/adwaita-acquire.svg +1 -0
  42. package/icons/adwaita-add.svg +1 -0
  43. package/icons/adwaita-album.svg +1 -0
  44. package/icons/adwaita-artist.svg +1 -0
  45. package/icons/adwaita-back.svg +1 -0
  46. package/icons/adwaita-check.svg +1 -0
  47. package/icons/adwaita-close.svg +1 -0
  48. package/icons/adwaita-collapse.svg +1 -0
  49. package/icons/adwaita-dark-mode.svg +1 -0
  50. package/icons/adwaita-delete.svg +1 -0
  51. package/icons/adwaita-drag.svg +1 -0
  52. package/icons/adwaita-edit.svg +1 -0
  53. package/icons/adwaita-error.svg +1 -0
  54. package/icons/adwaita-expand.svg +1 -0
  55. package/icons/adwaita-folder.svg +1 -0
  56. package/icons/adwaita-forward.svg +1 -0
  57. package/icons/adwaita-home.svg +1 -0
  58. package/icons/adwaita-layers.svg +1 -0
  59. package/icons/adwaita-like.svg +1 -0
  60. package/icons/adwaita-lock.svg +1 -0
  61. package/icons/adwaita-menu.svg +1 -0
  62. package/icons/adwaita-more.svg +1 -0
  63. package/icons/adwaita-mute.svg +1 -0
  64. package/icons/adwaita-next.svg +1 -0
  65. package/icons/adwaita-pause.svg +1 -0
  66. package/icons/adwaita-play.svg +1 -0
  67. package/icons/adwaita-playlist.svg +1 -0
  68. package/icons/adwaita-plugin.svg +1 -0
  69. package/icons/adwaita-previous.svg +1 -0
  70. package/icons/adwaita-queue.svg +1 -0
  71. package/icons/adwaita-rating-outline.svg +1 -0
  72. package/icons/adwaita-rating.svg +1 -0
  73. package/icons/adwaita-refresh.svg +1 -0
  74. package/icons/adwaita-remote.svg +1 -0
  75. package/icons/adwaita-remove.svg +1 -0
  76. package/icons/adwaita-repeat.svg +1 -0
  77. package/icons/adwaita-reveal.svg +1 -0
  78. package/icons/adwaita-search.svg +1 -0
  79. package/icons/adwaita-settings.svg +1 -0
  80. package/icons/adwaita-shuffle.svg +1 -0
  81. package/icons/adwaita-sign-out.svg +1 -0
  82. package/icons/adwaita-song.svg +1 -0
  83. package/icons/adwaita-sort.svg +1 -0
  84. package/icons/adwaita-storage.svg +1 -0
  85. package/icons/adwaita-users.svg +1 -0
  86. package/icons/adwaita-volume.svg +1 -0
  87. package/icons/adwaita-warning.svg +1 -0
  88. package/icons/custom-dislike-outline.svg +1 -0
  89. package/icons/custom-dislike.svg +1 -0
  90. package/icons/custom-like-outline.svg +1 -0
  91. package/icons/custom-unknown.svg +1 -0
  92. package/icons/custom-upload.svg +1 -0
  93. package/identity/icons/app-icon-dark-16.png +0 -0
  94. package/identity/icons/app-icon-dark-180.png +0 -0
  95. package/identity/icons/app-icon-dark-192.png +0 -0
  96. package/identity/icons/app-icon-dark-32.png +0 -0
  97. package/identity/icons/app-icon-dark-512.png +0 -0
  98. package/identity/icons/app-icon-dark.svg +1 -0
  99. package/identity/icons/app-icon-light-16.png +0 -0
  100. package/identity/icons/app-icon-light-180.png +0 -0
  101. package/identity/icons/app-icon-light-192.png +0 -0
  102. package/identity/icons/app-icon-light-32.png +0 -0
  103. package/identity/icons/app-icon-light-512.png +0 -0
  104. package/identity/icons/app-icon-light.svg +1 -0
  105. package/identity/icons/favicon.svg +1 -0
  106. package/identity/mark/mark-dark.svg +1 -0
  107. package/identity/mark/mark-light.svg +1 -0
  108. package/identity/mark/mark-symbolic.svg +1 -0
  109. package/package.json +35 -4
@@ -0,0 +1,282 @@
1
+ /*
2
+ * @hearthsound/design - menus
3
+ *
4
+ * k05 item anatomy, k18 A submenu (desktop cascade and phone replace-with-list),
5
+ * o01 account menu, k17-r3 song menu with like/dislike and stars. The k26 avatar
6
+ * and account row live in sidebar.css. Values from shared/approved/components.css
7
+ * (.popmenu, .songmenu, .stars, .amenu) and spec/components.md.
8
+ */
9
+
10
+ /* ------------------------------------------------------------------ */
11
+ /* Menu surface (k18, k05 item anatomy) */
12
+ /* ------------------------------------------------------------------ */
13
+
14
+ .hs-menu {
15
+ background: var(--hs-popover-bg);
16
+ border-radius: var(--hs-radius-popover);
17
+ box-shadow: var(--hs-elevation-2);
18
+ padding: 6px;
19
+ box-sizing: border-box;
20
+ min-width: 220px;
21
+ }
22
+
23
+ /* 1 px separators inset 6 px. */
24
+ .hs-menu hr {
25
+ border: 0;
26
+ height: 1px;
27
+ background: var(--hs-separator);
28
+ margin: 2px 6px 4px;
29
+ }
30
+
31
+ .hs-menu__header {
32
+ display: flex;
33
+ align-items: center;
34
+ gap: 6px;
35
+ padding: 2px 2px 6px;
36
+ font-weight: 600;
37
+ white-space: nowrap;
38
+ }
39
+
40
+ .hs-menu__item {
41
+ display: flex;
42
+ align-items: center;
43
+ gap: 8px;
44
+ height: 36px;
45
+ padding: 0 10px;
46
+ border: 0;
47
+ width: 100%;
48
+ background: none;
49
+ border-radius: var(--hs-radius-row);
50
+ position: relative;
51
+ font: 400 14px var(--hs-font-body);
52
+ color: var(--hs-fg);
53
+ text-align: left;
54
+ text-decoration: none;
55
+ box-sizing: border-box;
56
+ }
57
+
58
+ /* "No playlists yet" (c03 item 19): a muted, non-interactive line. */
59
+ .hs-menu__empty {
60
+ padding: 0 10px;
61
+ color: var(--hs-fg-muted);
62
+ font-size: 13px;
63
+ }
64
+
65
+ .hs-menu__item > .hs-icon {
66
+ width: 16px;
67
+ height: 16px;
68
+ color: var(--hs-fg-muted);
69
+ }
70
+
71
+ /* A trailing icon on an item that opens a submenu is the 14 px chevron. */
72
+ .hs-menu__item[aria-haspopup] > .hs-icon:last-child {
73
+ width: 14px;
74
+ height: 14px;
75
+ }
76
+
77
+ .hs-menu__label {
78
+ flex: 1;
79
+ min-width: 0;
80
+ overflow: hidden;
81
+ text-overflow: ellipsis;
82
+ white-space: nowrap;
83
+ }
84
+
85
+ .hs-menu__sub {
86
+ margin-left: auto;
87
+ color: var(--hs-fg-muted);
88
+ font-size: 13px;
89
+ }
90
+
91
+ .hs-menu__cover {
92
+ width: 28px;
93
+ height: 28px;
94
+ border-radius: 5px;
95
+ overflow: hidden;
96
+ flex: none;
97
+ display: block;
98
+ }
99
+
100
+ .hs-menu__cover .hs-mosaic {
101
+ border-radius: inherit;
102
+ }
103
+
104
+ .hs-menu__check {
105
+ width: 16px;
106
+ height: 16px;
107
+ margin-left: auto;
108
+ color: var(--hs-accent-text);
109
+ visibility: hidden;
110
+ flex: none;
111
+ }
112
+
113
+ .hs-menu__item[aria-checked='true'] .hs-menu__check {
114
+ visibility: visible;
115
+ }
116
+
117
+ .hs-menu__item:hover {
118
+ background: var(--hs-control-tone);
119
+ }
120
+
121
+ .hs-menu__item:focus-visible {
122
+ outline: none;
123
+ background: var(--hs-accent-tint);
124
+ color: var(--hs-accent-text);
125
+ font-weight: 600;
126
+ box-shadow: var(--hs-focus-shadow);
127
+ }
128
+
129
+ /* ------------------------------------------------------------------ */
130
+ /* k18 A - add-to-playlist submenu */
131
+ /* ------------------------------------------------------------------ */
132
+
133
+ .hs-submenu {
134
+ position: absolute;
135
+ top: 0;
136
+ left: calc(100% + 6px);
137
+ width: 270px;
138
+ box-sizing: border-box;
139
+ background: var(--hs-popover-bg);
140
+ border-radius: var(--hs-radius-popover);
141
+ box-shadow: var(--hs-elevation-2);
142
+ padding: 6px;
143
+ }
144
+
145
+ .hs-submenu__header {
146
+ display: flex;
147
+ align-items: center;
148
+ gap: 6px;
149
+ padding: 2px 2px 6px;
150
+ font-weight: 600;
151
+ white-space: nowrap;
152
+ }
153
+
154
+ .hs-submenu__back {
155
+ display: inline-flex;
156
+ align-items: center;
157
+ justify-content: center;
158
+ width: 28px;
159
+ height: 28px;
160
+ padding: 0;
161
+ border: 0;
162
+ border-radius: var(--hs-radius-control);
163
+ background: transparent;
164
+ color: var(--hs-fg-muted);
165
+ cursor: default;
166
+ }
167
+
168
+ .hs-submenu__back:hover {
169
+ background: var(--hs-control-tone);
170
+ color: var(--hs-fg);
171
+ }
172
+
173
+ .hs-submenu__back:focus-visible {
174
+ outline: none;
175
+ background: var(--hs-accent-tint);
176
+ color: var(--hs-accent-text);
177
+ box-shadow: var(--hs-focus-shadow);
178
+ }
179
+
180
+ /* Phones: the submenu content replaces the menu, so it stops floating. */
181
+ @media (max-width: 720px) {
182
+ .hs-submenu {
183
+ position: static;
184
+ }
185
+ }
186
+
187
+ /* ------------------------------------------------------------------ */
188
+ /* k17-r3 - song menu */
189
+ /* ------------------------------------------------------------------ */
190
+
191
+ .hs-song-menu {
192
+ width: 270px;
193
+ }
194
+
195
+ .hs-song-menu__feedback-line {
196
+ display: flex;
197
+ align-items: center;
198
+ justify-content: space-between;
199
+ padding: 2px 4px 6px;
200
+ }
201
+
202
+ .hs-song-menu__feedback-line .hs-button {
203
+ width: 40px;
204
+ height: 40px;
205
+ }
206
+
207
+ .hs-song-menu__feedback-line .hs-button--on {
208
+ background: transparent;
209
+ color: var(--hs-accent-text);
210
+ }
211
+
212
+ .hs-song-menu__rating-line {
213
+ display: flex;
214
+ align-items: center;
215
+ justify-content: space-between;
216
+ gap: 8px;
217
+ padding: 2px 4px 6px;
218
+ }
219
+
220
+ /* Rating stars: five 30 x 36 px targets, 18 px glyphs. */
221
+ .hs-stars {
222
+ display: inline-flex;
223
+ }
224
+
225
+ .hs-star {
226
+ width: 30px;
227
+ height: 36px;
228
+ display: inline-flex;
229
+ align-items: center;
230
+ justify-content: center;
231
+ padding: 0;
232
+ border: 0;
233
+ background: transparent;
234
+ border-radius: var(--hs-radius-control);
235
+ color: var(--hs-fg-muted);
236
+ cursor: default;
237
+ }
238
+
239
+ .hs-star .hs-icon {
240
+ width: 18px;
241
+ height: 18px;
242
+ }
243
+
244
+ .hs-star--on {
245
+ color: var(--hs-accent-text);
246
+ }
247
+
248
+ .hs-star:focus-visible {
249
+ outline: none;
250
+ background: var(--hs-accent-tint);
251
+ }
252
+
253
+ /* ------------------------------------------------------------------ */
254
+ /* o01 - account menu (avatar and account row live in sidebar.css) */
255
+ /* ------------------------------------------------------------------ */
256
+
257
+ .hs-account-menu {
258
+ width: 250px;
259
+ }
260
+
261
+ .hs-account-menu__header {
262
+ display: flex;
263
+ align-items: center;
264
+ gap: 10px;
265
+ padding: 6px 8px 10px;
266
+ }
267
+
268
+ .hs-account-menu__who {
269
+ display: flex;
270
+ flex-direction: column;
271
+ gap: 2px;
272
+ min-width: 0;
273
+ }
274
+
275
+ .hs-account-menu__who > :first-child {
276
+ font-weight: 600;
277
+ }
278
+
279
+ .hs-account-menu__who > :last-child {
280
+ color: var(--hs-fg-muted);
281
+ font-size: 13px;
282
+ }
@@ -0,0 +1,230 @@
1
+ /*
2
+ * k25 A - page header: a 72 px sticky row on the view background (never a separate bar
3
+ * surface), the page title as h1, flat icon actions at the right, and the l03 back
4
+ * button. On phones the drawer menu button leads top-level pages (layouts.md 1.2) and the
5
+ * back button replaces it on drill-down pages. The hero below is the l09 detail hero
6
+ * (p15 album, p16-r1 artist, p17 playlist).
7
+ */
8
+
9
+ .hs-page-header {
10
+ position: sticky;
11
+ top: 0;
12
+ z-index: 5;
13
+ display: flex;
14
+ align-items: center;
15
+ gap: 8px;
16
+ height: 72px;
17
+ padding: 0 24px;
18
+ box-sizing: border-box;
19
+ background: var(--hs-view-bg);
20
+ color: var(--hs-fg);
21
+ }
22
+
23
+ .hs-page-header__title {
24
+ flex: 1;
25
+ min-width: 0;
26
+ margin: 0;
27
+ font: 750 var(--hs-type-title-2-size)/1.1 var(--hs-font-display);
28
+ letter-spacing: -0.02em;
29
+ white-space: nowrap;
30
+ overflow: hidden;
31
+ text-overflow: ellipsis;
32
+ }
33
+
34
+ .hs-page-actions {
35
+ display: flex;
36
+ align-items: center;
37
+ gap: 8px;
38
+ margin-left: auto;
39
+ }
40
+
41
+ /* k25 A: the hairline appears only once the page is scrolled. */
42
+ .hs-page-header--scrolled,
43
+ .hs-page-header[data-scrolled] {
44
+ box-shadow: 0 1px 0 var(--hs-separator);
45
+ }
46
+
47
+ /* l03: a flat 36 px icon button leading the header, pulled to the margin. */
48
+ .hs-back {
49
+ margin-left: -8px;
50
+ }
51
+
52
+ /* l01-r1: the phone drawer trigger leads top-level pages only. */
53
+ .hs-page-header__menu {
54
+ display: none;
55
+ margin-left: -8px;
56
+ }
57
+
58
+ /* ------------------------------------------------------------------ */
59
+ /* Phone (l07): 14 px header padding; icon actions stay icon-only */
60
+ /* ------------------------------------------------------------------ */
61
+
62
+ @media (max-width: 720px) {
63
+ .hs-page-header {
64
+ padding: 0 14px;
65
+ }
66
+
67
+ .hs-page-header__menu {
68
+ display: inline-flex;
69
+ }
70
+ }
71
+
72
+ /* ------------------------------------------------------------------ */
73
+ /* l09, p15, p16-r1, p17 - detail hero */
74
+ /* ------------------------------------------------------------------ */
75
+
76
+ .hs-hero {
77
+ display: flex;
78
+ align-items: flex-end;
79
+ gap: 28px;
80
+ padding: 8px 32px 26px;
81
+ box-sizing: border-box;
82
+ }
83
+
84
+ .hs-hero__art {
85
+ display: block;
86
+ flex: none;
87
+ width: 232px;
88
+ height: 232px;
89
+ border-radius: var(--hs-radius-art);
90
+ overflow: hidden;
91
+ background: var(--hs-art-placeholder-bg);
92
+ box-shadow: var(--hs-art-shadow);
93
+ }
94
+
95
+ .hs-hero__art > img {
96
+ display: block;
97
+ width: 100%;
98
+ height: 100%;
99
+ }
100
+
101
+ /* f15c: artist portraits are round. */
102
+ .hs-hero__art--round {
103
+ border-radius: var(--hs-radius-artist);
104
+ }
105
+
106
+ .hs-hero__text {
107
+ display: flex;
108
+ flex-direction: column;
109
+ align-items: flex-start;
110
+ gap: 6px;
111
+ min-width: 0;
112
+ }
113
+
114
+ .hs-hero__text > h1 {
115
+ margin: 0;
116
+ font: 750 var(--hs-type-title-1-size)/1.1 var(--hs-font-display);
117
+ letter-spacing: -0.02em;
118
+ }
119
+
120
+ .hs-hero__by {
121
+ margin: 0;
122
+ font-weight: 600;
123
+ }
124
+
125
+ .hs-hero__meta {
126
+ margin: 0;
127
+ color: var(--hs-fg-muted);
128
+ font-size: 13px;
129
+ }
130
+
131
+ /* p16-r1: the biography is muted, clamped to three lines, with Show more / Show less
132
+ * in place. A visually hidden checkbox carries the expanded state so the text stays
133
+ * visible while collapsed; the label is the disclosure control. */
134
+ .hs-hero__bio {
135
+ position: relative;
136
+ max-width: 62ch;
137
+ margin: 4px 0 0;
138
+ color: var(--hs-fg-muted);
139
+ }
140
+
141
+ .hs-hero__bio > p {
142
+ margin: 0;
143
+ display: -webkit-box;
144
+ -webkit-box-orient: vertical;
145
+ -webkit-line-clamp: 3;
146
+ overflow: hidden;
147
+ }
148
+
149
+ .hs-hero__bio-toggle {
150
+ position: absolute; /* markup also carries .hs-visually-hidden */
151
+ }
152
+
153
+ .hs-hero__bio-toggle:checked ~ p {
154
+ display: block;
155
+ overflow: visible;
156
+ }
157
+
158
+ .hs-hero__more {
159
+ display: inline-block;
160
+ width: max-content;
161
+ margin-top: 4px;
162
+ cursor: default;
163
+ }
164
+
165
+ .hs-hero__more-open {
166
+ display: none;
167
+ }
168
+
169
+ .hs-hero__bio-toggle:checked ~ .hs-hero__more .hs-hero__more-open {
170
+ display: inline;
171
+ }
172
+
173
+ .hs-hero__bio-toggle:checked ~ .hs-hero__more .hs-hero__more-closed {
174
+ display: none;
175
+ }
176
+
177
+ .hs-hero__bio-toggle:focus-visible ~ .hs-hero__more {
178
+ outline: none;
179
+ background: var(--hs-accent-tint);
180
+ }
181
+
182
+ .hs-hero__actions {
183
+ display: flex;
184
+ align-items: center;
185
+ gap: 8px;
186
+ margin-top: 8px;
187
+ flex-wrap: wrap;
188
+ }
189
+
190
+ .hs-hero__actions .hs-button--icon {
191
+ width: 48px;
192
+ height: 48px;
193
+ }
194
+
195
+ .hs-hero__actions .hs-button--icon .hs-icon {
196
+ --hs-icon-size: 20px;
197
+ }
198
+
199
+ /* A pressed like toggle stays transparent with the accent glyph (k17-r3). */
200
+ .hs-hero__actions .hs-button--flat.hs-button--on,
201
+ .hs-hero__actions .hs-button--flat[aria-pressed='true'] {
202
+ background: transparent;
203
+ color: var(--hs-accent-text);
204
+ }
205
+
206
+ @media (max-width: 1280px) {
207
+ .hs-hero {
208
+ padding: 8px 24px 22px;
209
+ }
210
+ }
211
+
212
+ @media (max-width: 720px) {
213
+ .hs-hero {
214
+ flex-direction: column;
215
+ align-items: flex-start;
216
+ gap: 16px;
217
+ padding: 4px 18px 18px;
218
+ }
219
+
220
+ .hs-hero__art {
221
+ width: 200px;
222
+ height: 200px;
223
+ }
224
+ }
225
+
226
+ @media (prefers-reduced-motion: reduce) {
227
+ .hs-hero__art {
228
+ transition: none;
229
+ }
230
+ }
@@ -0,0 +1,101 @@
1
+ /*
2
+ * k10 A - status pill (compact), count badge and row health indicator.
3
+ *
4
+ * Colour and glyph are the state colour on a --hs-status-tint background; in-progress
5
+ * states use --hs-accent-text on --hs-accent-tint, neutral states --hs-fg-muted. Every
6
+ * state carries a glyph and a label, never colour alone (f07). Pills are not focusable;
7
+ * glyphs are aria-hidden and the visible label is the accessible text.
8
+ */
9
+
10
+ .hs-pill {
11
+ --c: var(--hs-fg-muted);
12
+ display: inline-flex;
13
+ align-items: center;
14
+ gap: 5px;
15
+ height: 22px;
16
+ padding: 0 9px 0 7px;
17
+ border-radius: var(--hs-radius-full);
18
+ white-space: nowrap;
19
+ font: 600 12px var(--hs-font-body);
20
+ font-variant-numeric: tabular-nums;
21
+ color: var(--c);
22
+ background: color-mix(in srgb, var(--c) var(--hs-status-tint), transparent);
23
+ }
24
+
25
+ .hs-pill__glyph {
26
+ --hs-icon-size: 12px;
27
+ }
28
+
29
+ .hs-pill--success {
30
+ --c: var(--hs-success);
31
+ }
32
+
33
+ .hs-pill--warning {
34
+ --c: var(--hs-warning);
35
+ }
36
+
37
+ .hs-pill--error {
38
+ --c: var(--hs-error);
39
+ }
40
+
41
+ .hs-pill--neutral {
42
+ --c: var(--hs-fg-muted);
43
+ }
44
+
45
+ /* In-progress states: Searching sources, Downloading N%, Prefetching N%, Uploading N%,
46
+ * Processing. */
47
+ .hs-pill--accent {
48
+ color: var(--hs-accent-text);
49
+ background: var(--hs-accent-tint);
50
+ }
51
+
52
+ /* Count badge: "items" is added as visually hidden text in the markup. */
53
+ .hs-count-badge {
54
+ display: inline-flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ min-width: 20px;
58
+ height: 20px;
59
+ padding: 0 6px;
60
+ box-sizing: border-box;
61
+ border-radius: 10px;
62
+ background: var(--hs-accent-bg);
63
+ color: var(--hs-accent-fg);
64
+ font: 600 12px var(--hs-font-body);
65
+ font-variant-numeric: tabular-nums;
66
+ }
67
+
68
+ /* Row health indicator: a 22 px tinted circle; role="img" with an aria-label, and the
69
+ * label repeated in a tooltip on hover and row focus. */
70
+ .hs-health-indicator {
71
+ --c: var(--hs-fg-muted);
72
+ display: inline-flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ flex: none;
76
+ width: 22px;
77
+ height: 22px;
78
+ border-radius: 50%;
79
+ color: var(--c);
80
+ background: color-mix(in srgb, var(--c) var(--hs-status-tint), transparent);
81
+ }
82
+
83
+ .hs-health-indicator .hs-icon {
84
+ --hs-icon-size: 14px;
85
+ }
86
+
87
+ .hs-health-indicator--success {
88
+ --c: var(--hs-success);
89
+ }
90
+
91
+ .hs-health-indicator--warning {
92
+ --c: var(--hs-warning);
93
+ }
94
+
95
+ .hs-health-indicator--error {
96
+ --c: var(--hs-error);
97
+ }
98
+
99
+ .hs-health-indicator--neutral {
100
+ --c: var(--hs-fg-muted);
101
+ }