@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,48 @@
1
+ /*
2
+ * k22 A - status page: centred in the content area, biased slightly upward by the
3
+ * 90 px bottom padding. Used by the o03 load failure, the p27 system states and the
4
+ * p08e empty library views. The playlist empty state uses the inline variant (p17).
5
+ * The title is a heading, the icon is aria-hidden, and a failure sets role="alert".
6
+ */
7
+
8
+ .hs-status-page {
9
+ flex: 1;
10
+ display: flex;
11
+ flex-direction: column;
12
+ align-items: center;
13
+ justify-content: center;
14
+ text-align: center;
15
+ gap: 10px;
16
+ padding: 24px 24px 90px;
17
+ box-sizing: border-box;
18
+ color: var(--hs-fg);
19
+ }
20
+
21
+ .hs-status-page__icon {
22
+ width: 64px;
23
+ height: 64px;
24
+ color: var(--hs-fg-muted);
25
+ opacity: 0.8;
26
+ }
27
+
28
+ .hs-status-page__title {
29
+ margin: 6px 0 0;
30
+ font: 750 23px/1.2 var(--hs-font-display);
31
+ letter-spacing: -0.02em;
32
+ }
33
+
34
+ .hs-status-page__text {
35
+ margin: 0;
36
+ max-width: 46ch;
37
+ color: var(--hs-fg-muted);
38
+ }
39
+
40
+ .hs-status-page__action {
41
+ margin-top: 8px;
42
+ }
43
+
44
+ /* p17: the inline empty state under a playlist hero keeps the page compact. */
45
+ .hs-status-page--inline {
46
+ padding-top: 32px;
47
+ padding-bottom: 48px;
48
+ }
@@ -0,0 +1,130 @@
1
+ /*
2
+ * @hearthsound/design - stepper
3
+ *
4
+ * k29 B: six 28 px markers across the top on desktop, the compact step line on
5
+ * phones. p06 renamed step 6 to Summary. Values from shared/approved/
6
+ * components.css (.stepper, .stepdot, .stepline) and spec/components.md.
7
+ */
8
+
9
+ .hs-stepper {
10
+ display: flex;
11
+ align-items: flex-start;
12
+ list-style: none;
13
+ margin: 0;
14
+ padding: 0;
15
+ }
16
+
17
+ .hs-step {
18
+ display: flex;
19
+ flex-direction: column;
20
+ align-items: center;
21
+ gap: 6px;
22
+ width: 84px;
23
+ font: 400 12px var(--hs-font-body);
24
+ text-align: center;
25
+ color: var(--hs-fg-muted);
26
+ }
27
+
28
+ .hs-step__marker {
29
+ width: 28px;
30
+ height: 28px;
31
+ border-radius: 50%;
32
+ display: inline-flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ flex: none;
36
+ font: 650 13px var(--hs-font-body);
37
+ background: var(--hs-control-tone);
38
+ color: var(--hs-fg-muted);
39
+ }
40
+
41
+ .hs-step__marker .hs-icon {
42
+ width: 14px;
43
+ height: 14px;
44
+ }
45
+
46
+ /* Done: acid disc with the 14 px check. */
47
+ .hs-step--done {
48
+ color: var(--hs-fg);
49
+ }
50
+
51
+ .hs-step--done .hs-step__marker {
52
+ background: var(--hs-accent-bg);
53
+ color: var(--hs-accent-fg);
54
+ }
55
+
56
+ /* Current: the text-colour disc, label at weight 600. */
57
+ .hs-step[aria-current='step'] {
58
+ color: var(--hs-fg);
59
+ font-weight: 600;
60
+ }
61
+
62
+ .hs-step[aria-current='step'] .hs-step__marker {
63
+ background: var(--hs-fg);
64
+ color: var(--hs-view-bg);
65
+ }
66
+
67
+ .hs-step__connector {
68
+ flex: 1;
69
+ height: 2px;
70
+ margin-top: 13px;
71
+ background: color-mix(in srgb, var(--hs-fg) 16%, transparent);
72
+ }
73
+
74
+ /* The connector after a done step is accent. */
75
+ .hs-step--done + .hs-step__connector {
76
+ background: var(--hs-accent-bg);
77
+ }
78
+
79
+ /* ------------------------------------------------------------------ */
80
+ /* Phone step line (k29) */
81
+ /* ------------------------------------------------------------------ */
82
+
83
+ .hs-step-line {
84
+ display: grid;
85
+ grid-template-columns: repeat(6, 1fr);
86
+ gap: 8px 4px;
87
+ }
88
+
89
+ .hs-step-line__row {
90
+ grid-column: 1 / -1;
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 10px;
94
+ font: 600 13px var(--hs-font-body);
95
+ }
96
+
97
+ .hs-step-line__row .hs-step__marker {
98
+ font-weight: 650;
99
+ }
100
+
101
+ .hs-step-line__count {
102
+ color: var(--hs-fg-muted);
103
+ font-weight: 500;
104
+ }
105
+
106
+ .hs-step-line__segment {
107
+ height: 6px;
108
+ border-radius: 3px;
109
+ background: color-mix(in srgb, var(--hs-fg) 16%, transparent);
110
+ }
111
+
112
+ .hs-step-line__segment--done {
113
+ background: var(--hs-accent-bg);
114
+ }
115
+
116
+ .hs-step-line__segment--current {
117
+ background: var(--hs-fg);
118
+ }
119
+
120
+ @media (max-width: 720px) {
121
+ .hs-stepper {
122
+ display: none;
123
+ }
124
+ }
125
+
126
+ @media (min-width: 721px) {
127
+ .hs-step-line {
128
+ display: none;
129
+ }
130
+ }
@@ -0,0 +1,88 @@
1
+ /*
2
+ * k20-r3 D - toast: a pill, ink in light and popover in dark, placed per l11 and l11d.
3
+ *
4
+ * Markup, in the l11d dock (banner.css owns .hs-overlay-dock):
5
+ * <div class="hs-overlay-dock">
6
+ * <div class="hs-banner hs-banner--warning hs-banner--floating">...</div>
7
+ * <div class="hs-toast-region" role="status" aria-label="Messages">
8
+ * <div class="hs-toast" role="status">
9
+ * <svg class="hs-icon hs-toast__glyph">...</svg>
10
+ * <span class="hs-toast__message">Added to Road Trip.</span>
11
+ * <button class="hs-toast__action" type="button">Dismiss</button>
12
+ * </div>
13
+ * </div>
14
+ * </div>
15
+ * The dock is in column-reverse order: the banner sits on the player edge and the toast
16
+ * stacks 12 px above it. The region never takes focus; the action is reachable through
17
+ * the region. Errors use role="alert" on the toast. 5 s, paused on hover and focus.
18
+ */
19
+
20
+ .hs-toast-region {
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ gap: 12px;
25
+ width: 100%;
26
+ pointer-events: none;
27
+ }
28
+
29
+ .hs-toast {
30
+ pointer-events: auto;
31
+ display: inline-flex;
32
+ align-items: center;
33
+ gap: 10px;
34
+ height: 48px;
35
+ padding: 0 6px 0 16px;
36
+ box-sizing: border-box;
37
+ border-radius: var(--hs-radius-full);
38
+ font: 400 14px var(--hs-font-body);
39
+ color: var(--hs-toast-fg);
40
+ background: var(--hs-toast-bg);
41
+ box-shadow: var(--hs-toast-shadow);
42
+ max-width: calc(100vw - 24px);
43
+ }
44
+
45
+ .hs-toast__glyph {
46
+ --hs-icon-size: 16px;
47
+ color: var(--hs-toast-glyph);
48
+ }
49
+
50
+ .hs-toast__message {
51
+ flex: 1;
52
+ min-width: 0;
53
+ overflow: hidden;
54
+ text-overflow: ellipsis;
55
+ white-space: nowrap;
56
+ }
57
+
58
+ /* Flat text button: 32 px, weight 600, inherits the toast's ink. */
59
+ .hs-toast__action {
60
+ display: inline-flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ flex: none;
64
+ height: 32px;
65
+ padding: 0 12px;
66
+ margin: 0;
67
+ border: 0;
68
+ border-radius: var(--hs-radius-control);
69
+ background: transparent;
70
+ color: inherit;
71
+ font: 600 14px var(--hs-font-body);
72
+ cursor: default;
73
+ appearance: none;
74
+ }
75
+
76
+ .hs-toast__action:focus-visible {
77
+ outline: none;
78
+ background: var(--hs-accent-tint);
79
+ color: var(--hs-accent-text);
80
+ box-shadow: var(--hs-focus-shadow);
81
+ }
82
+
83
+ /* l11 A: phones cap the width at 100vw - 24 px and the toast fills it. */
84
+ @media (max-width: 720px) {
85
+ .hs-toast {
86
+ width: 100%;
87
+ }
88
+ }
@@ -0,0 +1,29 @@
1
+ /*
2
+ * k27 C - tooltip: ink in light, popover in dark, matching the toast (k20-r3 D).
3
+ *
4
+ * Markup: <span class="hs-tooltip" role="tooltip" id="...">Text</span> placed below its
5
+ * control, with the control carrying aria-describedby and the same text as its name.
6
+ * The tooltip is never focusable and ignores pointer events.
7
+ *
8
+ * Behaviour is the client's (b04):
9
+ * - hover: shown after an 800 ms pause;
10
+ * - keyboard focus: shown at once (and hidden on blur);
11
+ * - touch: shown after a 500 ms long-press, hidden 1.5 s after the finger lifts;
12
+ * - Escape hides it;
13
+ * - the placement is below the control.
14
+ * Uses: the "Failed" pill in the player, mini player, now playing and queue rows carries
15
+ * the failure reason as its tooltip (o07).
16
+ */
17
+
18
+ .hs-tooltip {
19
+ position: absolute;
20
+ z-index: 20;
21
+ padding: 6px 10px;
22
+ border-radius: var(--hs-radius-control);
23
+ font: 500 13px var(--hs-font-body);
24
+ white-space: nowrap;
25
+ pointer-events: none;
26
+ background: var(--hs-tooltip-bg);
27
+ color: var(--hs-tooltip-fg);
28
+ box-shadow: var(--hs-tooltip-shadow);
29
+ }
@@ -0,0 +1,336 @@
1
+ /*
2
+ * @hearthsound/design - track rows
3
+ *
4
+ * k12-r1 A, k12-ctx, p08 column subgrid, p21-r2 actions area, k17-r3 feedback
5
+ * glyph, k12-rm equaliser. Values from shared/approved/components.css
6
+ * (.tr2, .eq, .tlist, p21-r2) and spec/components.md.
7
+ */
8
+
9
+ /* ------------------------------------------------------------------ */
10
+ /* List grid - rows share columns through subgrid (p08) */
11
+ /* ------------------------------------------------------------------ */
12
+
13
+ .hs-track-list {
14
+ display: grid;
15
+ grid-template-columns: 40px minmax(0, 1.5fr) minmax(0, 1fr) auto auto 44px;
16
+ column-gap: 12px;
17
+ align-content: start;
18
+ }
19
+
20
+ .hs-track-list--album {
21
+ grid-template-columns: 40px minmax(0, 1fr) auto auto 44px;
22
+ }
23
+
24
+ /* List columns minus the album column (artist Top Songs, Uploads on desktop). */
25
+ .hs-track-list--no-album {
26
+ grid-template-columns: 40px minmax(0, 1fr) auto auto 44px;
27
+ }
28
+
29
+ .hs-track-list > .hs-track-row {
30
+ grid-column: 1 / -1;
31
+ grid-template-columns: subgrid;
32
+ }
33
+
34
+ /* ------------------------------------------------------------------ */
35
+ /* Row */
36
+ /* ------------------------------------------------------------------ */
37
+
38
+ .hs-track-row {
39
+ display: grid;
40
+ grid-template-columns: 40px minmax(0, 1.5fr) minmax(0, 1fr) auto auto 44px;
41
+ column-gap: 12px;
42
+ align-items: center;
43
+ min-height: 52px;
44
+ padding: 0 8px 0 6px;
45
+ border-radius: var(--hs-radius-row);
46
+ position: relative;
47
+ font: 400 14px/1.35 var(--hs-font-body);
48
+ color: var(--hs-fg);
49
+ transition: background var(--hs-duration-hover) var(--hs-ease);
50
+ }
51
+
52
+ /* Album context (k12-ctx): numbered lead, no album column. */
53
+ .hs-track-row--album {
54
+ grid-template-columns: 40px minmax(0, 1fr) auto auto 44px;
55
+ }
56
+
57
+ .hs-track-row--album .hs-track-row__album {
58
+ display: none;
59
+ }
60
+
61
+ /* No-album list context: cover lead, album name as the second line (p16-r1). */
62
+ .hs-track-row--no-album,
63
+ .hs-track-row--queue {
64
+ grid-template-columns: 40px minmax(0, 1fr) auto auto 44px;
65
+ }
66
+
67
+ .hs-track-row--no-album .hs-track-row__album,
68
+ .hs-track-row--queue .hs-track-row__album {
69
+ display: none;
70
+ }
71
+
72
+ /* Lead: cover in list context, track number in album context. */
73
+ .hs-track-row__lead {
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ width: 40px;
78
+ height: 40px;
79
+ position: relative;
80
+ color: var(--hs-fg-muted);
81
+ font-variant-numeric: tabular-nums;
82
+ font-size: 13px;
83
+ }
84
+
85
+ .hs-track-row__art {
86
+ width: 40px;
87
+ height: 40px;
88
+ border-radius: var(--hs-radius-art-small);
89
+ display: block;
90
+ object-fit: cover;
91
+ }
92
+
93
+ .hs-track-row__lead .hs-art-placeholder {
94
+ border-radius: var(--hs-radius-art-small);
95
+ }
96
+
97
+ .hs-track-row__number {
98
+ transition: opacity var(--hs-duration-hover) var(--hs-ease);
99
+ }
100
+
101
+ /* Hover: play icon over the cover darkened 50% (list) or in place of the
102
+ * number (album context, k12-r1 board). */
103
+ .hs-track-row__overlay {
104
+ position: absolute;
105
+ inset: 0;
106
+ border-radius: var(--hs-radius-art-small);
107
+ background: rgb(0 0 0 / 50%);
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ opacity: 0;
112
+ transition: opacity var(--hs-duration-hover) var(--hs-ease);
113
+ }
114
+
115
+ .hs-track-row__overlay .hs-icon {
116
+ color: #fff;
117
+ width: 16px;
118
+ height: 16px;
119
+ }
120
+
121
+ .hs-track-row--album .hs-track-row__overlay {
122
+ background: transparent;
123
+ }
124
+
125
+ .hs-track-row--album .hs-track-row__overlay .hs-icon {
126
+ color: inherit;
127
+ }
128
+
129
+ .hs-track-row:hover .hs-track-row__overlay,
130
+ .hs-track-row:focus-within .hs-track-row__overlay,
131
+ .hs-track-row--current .hs-track-row__overlay {
132
+ opacity: 1;
133
+ }
134
+
135
+ .hs-track-row--album:hover .hs-track-row__number,
136
+ .hs-track-row--album:focus-within .hs-track-row__number {
137
+ opacity: 0;
138
+ }
139
+
140
+ .hs-track-row__text {
141
+ display: flex;
142
+ flex-direction: column;
143
+ gap: 2px;
144
+ min-width: 0;
145
+ }
146
+
147
+ .hs-track-row__title,
148
+ .hs-track-row__artist,
149
+ .hs-track-row__album {
150
+ overflow: hidden;
151
+ text-overflow: ellipsis;
152
+ white-space: nowrap;
153
+ }
154
+
155
+ .hs-track-row__artist,
156
+ .hs-track-row__album,
157
+ .hs-track-row__duration {
158
+ color: var(--hs-fg-muted);
159
+ }
160
+
161
+ .hs-track-row__duration {
162
+ font-size: 13px;
163
+ font-variant-numeric: tabular-nums;
164
+ text-align: right;
165
+ }
166
+
167
+ .hs-track-row--current .hs-track-row__title {
168
+ font-weight: 650;
169
+ }
170
+
171
+ /* Queue only (l06): played rows dim their content. */
172
+ .hs-track-row--played .hs-track-row__text,
173
+ .hs-track-row--played .hs-track-row__album {
174
+ opacity: 0.55;
175
+ }
176
+
177
+ /* ------------------------------------------------------------------ */
178
+ /* Equaliser (k12-r1) */
179
+ /* ------------------------------------------------------------------ */
180
+
181
+ .hs-eq {
182
+ display: inline-flex;
183
+ align-items: flex-end;
184
+ gap: 2px;
185
+ height: 14px;
186
+ }
187
+
188
+ .hs-eq i {
189
+ width: 3px;
190
+ border-radius: 1px;
191
+ background: var(--hs-accent-bg);
192
+ animation: hs-eq 1s ease-in-out infinite;
193
+ }
194
+
195
+ .hs-eq i:nth-child(1) {
196
+ height: 60%;
197
+ animation-delay: -0.3s;
198
+ }
199
+
200
+ .hs-eq i:nth-child(2) {
201
+ height: 100%;
202
+ animation-delay: -0.6s;
203
+ }
204
+
205
+ .hs-eq i:nth-child(3) {
206
+ height: 40%;
207
+ }
208
+
209
+ .hs-eq--paused i {
210
+ animation: none;
211
+ }
212
+
213
+ @keyframes hs-eq {
214
+ 50% {
215
+ height: 25%;
216
+ }
217
+ }
218
+
219
+ /* ------------------------------------------------------------------ */
220
+ /* Feedback glyph (k17-r3, p21-r2) */
221
+ /* ------------------------------------------------------------------ */
222
+
223
+ .hs-feedback-glyph {
224
+ display: inline-flex;
225
+ align-items: center;
226
+ justify-content: center;
227
+ color: var(--hs-accent-text);
228
+ }
229
+
230
+ .hs-feedback-glyph .hs-icon {
231
+ width: 16px;
232
+ height: 16px;
233
+ }
234
+
235
+ /* ------------------------------------------------------------------ */
236
+ /* Actions area (p21-r2): fixed width, like / dislike / menu */
237
+ /* ------------------------------------------------------------------ */
238
+
239
+ .hs-track-row__actions {
240
+ display: flex;
241
+ align-items: center;
242
+ }
243
+
244
+ .hs-track-row__actions .hs-button {
245
+ width: 32px;
246
+ height: 32px;
247
+ color: var(--hs-fg-muted);
248
+ }
249
+
250
+ .hs-track-row__actions .hs-button--on {
251
+ background: transparent;
252
+ color: var(--hs-accent-text);
253
+ }
254
+
255
+ @media (min-width: 721px) {
256
+ .hs-track-row__actions {
257
+ position: relative;
258
+ width: 96px;
259
+ justify-content: flex-end;
260
+ }
261
+
262
+ /* At rest only the state glyph shows, in the rightmost (menu) spot. */
263
+ .hs-track-row__actions .hs-feedback-glyph {
264
+ position: absolute;
265
+ right: 0;
266
+ top: 50%;
267
+ transform: translateY(-50%);
268
+ width: 32px;
269
+ height: 32px;
270
+ }
271
+
272
+ .hs-track-row:hover .hs-track-row__actions .hs-feedback-glyph,
273
+ .hs-track-row:focus-within .hs-track-row__actions .hs-feedback-glyph {
274
+ display: none;
275
+ }
276
+
277
+ .hs-track-row:not(:hover):not(:focus-within) .hs-track-row__actions .hs-button {
278
+ visibility: hidden;
279
+ }
280
+ }
281
+
282
+ .hs-track-row:hover {
283
+ background: var(--hs-control-tone);
284
+ }
285
+
286
+ .hs-track-row:focus-visible {
287
+ outline: none;
288
+ background: var(--hs-accent-tint);
289
+ box-shadow: var(--hs-focus-shadow);
290
+ }
291
+
292
+ /* ------------------------------------------------------------------ */
293
+ /* Phones (l07, p21-r2): menu always visible, glyph beside it */
294
+ /* ------------------------------------------------------------------ */
295
+
296
+ @media (max-width: 720px) {
297
+ .hs-track-list,
298
+ .hs-track-list--album,
299
+ .hs-track-list--no-album {
300
+ grid-template-columns: 40px minmax(0, 1fr) auto auto;
301
+ }
302
+
303
+ .hs-track-row,
304
+ .hs-track-row--album,
305
+ .hs-track-row--no-album,
306
+ .hs-track-row--queue {
307
+ grid-template-columns: 40px minmax(0, 1fr) auto;
308
+ }
309
+
310
+ .hs-track-row__album,
311
+ .hs-track-row__status,
312
+ .hs-track-row__duration {
313
+ display: none;
314
+ }
315
+
316
+ .hs-track-row__actions .hs-button:not([aria-haspopup]) {
317
+ display: none;
318
+ }
319
+
320
+ .hs-track-row__actions {
321
+ width: auto;
322
+ gap: 0;
323
+ }
324
+ }
325
+
326
+ @media (prefers-reduced-motion: reduce) {
327
+ .hs-eq i {
328
+ animation: none;
329
+ }
330
+
331
+ .hs-track-row,
332
+ .hs-track-row__number,
333
+ .hs-track-row__overlay {
334
+ transition: none;
335
+ }
336
+ }
@@ -0,0 +1,70 @@
1
+ /*
2
+ * @hearthsound/design - uploads
3
+ *
4
+ * k31-r1 A drop zone (neutral grey, acid tint with a dashed outline while
5
+ * dragging) and the p21-r1 upload items: k11-r1 two-line rows with a k10 pill,
6
+ * no progress bar. Values from shared/approved/components.css (.dz) and
7
+ * spec/components.md.
8
+ */
9
+
10
+ .hs-drop-zone {
11
+ display: flex;
12
+ flex-direction: column;
13
+ align-items: center;
14
+ justify-content: center;
15
+ gap: 10px;
16
+ text-align: center;
17
+ padding: 34px 20px;
18
+ border-radius: var(--hs-radius-card);
19
+ background: var(--hs-group-bg);
20
+ border: 2px dashed transparent;
21
+ transition: background var(--hs-duration-hover) var(--hs-ease),
22
+ border-color var(--hs-duration-hover) var(--hs-ease);
23
+ }
24
+
25
+ .hs-drop-zone > .hs-icon {
26
+ width: 40px;
27
+ height: 40px;
28
+ color: var(--hs-fg-muted);
29
+ }
30
+
31
+ .hs-drop-zone__hint {
32
+ color: var(--hs-fg-muted);
33
+ }
34
+
35
+ .hs-drop-zone--over {
36
+ background: var(--hs-accent-tint);
37
+ border-color: var(--hs-accent-bg);
38
+ }
39
+
40
+ @media (prefers-reduced-motion: reduce) {
41
+ .hs-drop-zone {
42
+ transition: none;
43
+ }
44
+ }
45
+
46
+ /* Upload items: no duration-style bar; the pill carries the state. */
47
+ .hs-upload-row .hs-setting-row__text {
48
+ gap: 4px;
49
+ }
50
+
51
+ .hs-upload-row > .hs-pill {
52
+ max-width: 45%;
53
+ overflow: hidden;
54
+ text-overflow: ellipsis;
55
+ }
56
+
57
+ @media (max-width: 720px) {
58
+ .hs-drop-zone {
59
+ padding: 24px 16px;
60
+ }
61
+
62
+ .hs-upload-row {
63
+ flex-wrap: wrap;
64
+ }
65
+
66
+ .hs-upload-row > .hs-pill {
67
+ max-width: 100%;
68
+ margin-left: 28px;
69
+ }
70
+ }