@hearthsound/design 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +298 -0
  12. package/css/components/list.css +260 -0
  13. package/css/components/menu.css +335 -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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hearthsound contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,133 @@
1
- # Temporary Holding Version
1
+ # @hearthsound/design
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The design language of Hearthsound: tokens, fonts, icons and component styles. It ships
4
+ plain CSS, so it works in any framework and needs no build step of its own.
5
+
6
+ ## Install
7
+
8
+ ```sh
9
+ npm install @hearthsound/design
10
+ ```
11
+
12
+ Import the stylesheet once per application:
13
+
14
+ ```js
15
+ import '@hearthsound/design/index.css';
16
+ ```
17
+
18
+ `index.css` pulls in `css/tokens.css`, `css/base.css` and every component stylesheet, in
19
+ that order. Individual files can be imported instead, for example
20
+ `@hearthsound/design/css/tokens.css`.
21
+
22
+ ## Schemes: System, Light and Dark
23
+
24
+ The light scheme is the default. Dark follows the operating system unless the page
25
+ chooses otherwise. The choice is a `data-scheme` attribute, which may sit on `<html>` or
26
+ on any subtree:
27
+
28
+ | Attribute | Result |
29
+ |---|---|
30
+ | none | System: dark under `prefers-color-scheme: dark`, light otherwise |
31
+ | `data-scheme="light"` | Light, even on a dark system |
32
+ | `data-scheme="dark"` | Dark, even on a light system |
33
+
34
+ ```html
35
+ <!-- System -->
36
+ <html>
37
+ <!-- Force light -->
38
+ <html data-scheme="light">
39
+ <!-- Force dark -->
40
+ <html data-scheme="dark">
41
+ ```
42
+
43
+ There is one fixed brand accent; there is no accent attribute.
44
+
45
+ ## Class naming
46
+
47
+ Components use BEM-like `hs-` classes:
48
+
49
+ - block: `hs-<component>` (for example `hs-button`, `hs-dialog`);
50
+ - element: `hs-<component>__<part>` (for example `hs-dialog__title`);
51
+ - modifier: `hs-<component>--<modifier>` (for example `hs-button--suggested`);
52
+ - utilities: the type scale (`hs-display`, `hs-title-1` to `hs-title-4`, `hs-heading`,
53
+ `hs-body`, `hs-caption`), `hs-link`, `hs-visually-hidden` and `hs-icon`.
54
+
55
+ State is expressed with real pseudo-classes and ARIA attributes, never helper classes:
56
+ `:hover`, `:focus-visible`, `:disabled`, `[aria-disabled="true"]`, `[aria-pressed="true"]`,
57
+ `[aria-selected="true"]`, `[aria-current]`, `[aria-busy="true"]`, `[aria-invalid="true"]`
58
+ and `[aria-expanded="true"]`. Focus is the approved tint-and-lift treatment shown on
59
+ `:focus-visible` only.
60
+
61
+ Style with the shipped tokens, not raw values:
62
+
63
+ ```css
64
+ .my-shell {
65
+ background: var(--hs-view-bg);
66
+ color: var(--hs-fg);
67
+ padding: var(--hs-space-5);
68
+ border-radius: var(--hs-radius-card);
69
+ }
70
+ ```
71
+
72
+ Tokens cover colour, type, spacing, density, radii, elevation, focus, motion and artwork.
73
+ `css/tokens.css` is the complete list; the light values are the `:root` base and dark
74
+ values apply through the media query and the `data-scheme` attribute.
75
+
76
+ ## Fonts
77
+
78
+ Three OFL faces ship in `fonts/` and are declared in `css/base.css`:
79
+ `Geist` (body, `--hs-font-body`), `Bricolage Grotesque` (display, `--hs-font-display`) and
80
+ `Geist Mono` (machine text, `--hs-font-mono`, ligatures off). The font files are loaded
81
+ relative to the stylesheet, so no path configuration is needed.
82
+
83
+ ## Icons
84
+
85
+ The approved icon set ships as individual SVGs in `icons/` and as a generated sprite in
86
+ `dist/icons.svg`. Each source name in the manifest maps to a file name and symbol id by
87
+ replacing `/` with `-`:
88
+
89
+ - manifest `adwaita/play` -> `icons/adwaita-play.svg` -> symbol `#adwaita-play`;
90
+ - manifest `custom/upload` -> `icons/custom-upload.svg` -> symbol `#custom-upload`.
91
+
92
+ Use the sprite with the `hs-icon` base class:
93
+
94
+ ```js
95
+ import sprite from '@hearthsound/design/icons.svg?url';
96
+ import { iconNames } from '@hearthsound/design/icons'; // string[]
97
+ ```
98
+
99
+ ```html
100
+ <svg class="hs-icon" aria-hidden="true">
101
+ <use href="/path/to/icons.svg#adwaita-play"></use>
102
+ </svg>
103
+ ```
104
+
105
+ `hs-icon` is 16 px by default and inherits `currentColor`; set `--hs-icon-size` to resize
106
+ it. `@hearthsound/design/icons` exports `iconNames` and, in TypeScript, the `IconName`
107
+ union type. Give a labelled icon `role="img"` and an accessible name; otherwise mark it
108
+ `aria-hidden="true"`.
109
+
110
+ ## Identity
111
+
112
+ The approved identity files ship unchanged:
113
+
114
+ - `identity/mark/mark-light.svg`, `mark-dark.svg`: the full-colour mark for each scheme.
115
+ - `identity/mark/mark-symbolic.svg`: the one-colour mark in `currentColor`.
116
+ - `identity/icons/app-icon-light.svg`, `app-icon-dark.svg`: 128 px masters.
117
+ - `identity/icons/app-icon-{light,dark}-{16,32,180,192,512}.png`: exported sizes.
118
+ - `identity/icons/favicon.svg`: one file that switches with `prefers-color-scheme`.
119
+
120
+ Use the full-colour mark only on its own scheme, keep a quarter of the mark's height as
121
+ clear space, and never rebuild a one-colour mark from the full-colour file: use
122
+ `mark-symbolic.svg`. Licence details are in `THIRD-PARTY.md`.
123
+
124
+ ## Development
125
+
126
+ ```sh
127
+ npm run build # writes dist/icons.svg, dist/icons.js and dist/icons.d.ts
128
+ npm run check # build, then verify tokens, imports, ASCII, fonts and icon refs
129
+ npm run specimen # build, then write the unpublished specimen/index.html
130
+ ```
131
+
132
+ `specimen/index.html` shows every component in every state, light and dark side by side.
133
+ It is a development reference and is not published.
package/THIRD-PARTY.md ADDED
@@ -0,0 +1,46 @@
1
+ # Third-party notices
2
+
3
+ The package itself is MIT licensed; see `LICENSE`.
4
+
5
+ ## Fonts
6
+
7
+ ### Geist and Geist Mono
8
+
9
+ Copyright (c) 2023 Vercel, in collaboration with basement.studio.
10
+
11
+ Licensed under the SIL Open Font License, Version 1.1. The full licence text ships as
12
+ `fonts/OFL-Geist.txt`.
13
+
14
+ Files: `fonts/geist-var.woff2`, `fonts/geist-mono.woff2`.
15
+
16
+ ### Bricolage Grotesque
17
+
18
+ Copyright 2022 The Bricolage Grotesque Project Authors
19
+ (https://github.com/ateliertriay/bricolage).
20
+
21
+ Licensed under the SIL Open Font License, Version 1.1. The full licence text ships as
22
+ `fonts/OFL-BricolageGrotesque.txt`.
23
+
24
+ File: `fonts/bricolage-var.woff2`.
25
+
26
+ ## Icons
27
+
28
+ ### Adwaita symbolic icons
29
+
30
+ Copyright the GNOME Project. The icons are licensed under the terms of either the GNU
31
+ LGPL v3 or the Creative Commons Attribution-Share Alike 3.0 United States License. The
32
+ full notice ships as `icons/LICENSE`. When attributing the artwork, "GNOME Project" is
33
+ enough; see http://www.gnome.org.
34
+
35
+ Files: every `icons/adwaita-*.svg`.
36
+
37
+ ### Custom icons derived from Adwaita
38
+
39
+ `icons/custom-like-outline.svg`, `icons/custom-dislike-outline.svg`,
40
+ `icons/custom-dislike.svg`, `icons/custom-upload.svg` and `icons/custom-unknown.svg` are
41
+ drawn from Adwaita shapes and carry the same licence and attribution as the Adwaita set.
42
+
43
+ ## Identity
44
+
45
+ The Hearthsound mark, app icons and favicon are original work of the Hearthsound
46
+ contributors and are covered by the package's MIT licence.
package/css/base.css ADDED
@@ -0,0 +1,245 @@
1
+ /*
2
+ * @hearthsound/design - base
3
+ *
4
+ * Fonts, reset, body typography, the type-scale classes (foundations.md 2.2),
5
+ * the focus indicator carrier, the icon base class and reduced motion.
6
+ * Component looks live in css/components/; this file only owns the page frame.
7
+ */
8
+
9
+ /* f01, f01b, f02, B09 - the three approved faces, shipped in fonts/. */
10
+ @font-face {
11
+ font-family: 'Geist';
12
+ src: url('../fonts/geist-var.woff2') format('woff2');
13
+ font-weight: 100 900;
14
+ font-style: normal;
15
+ font-display: swap;
16
+ }
17
+
18
+ @font-face {
19
+ font-family: 'Bricolage Grotesque';
20
+ src: url('../fonts/bricolage-var.woff2') format('woff2');
21
+ font-weight: 200 800;
22
+ font-style: normal;
23
+ font-display: swap;
24
+ }
25
+
26
+ @font-face {
27
+ font-family: 'Geist Mono';
28
+ src: url('../fonts/geist-mono.woff2') format('woff2');
29
+ font-weight: 100 900;
30
+ font-style: normal;
31
+ font-display: swap;
32
+ }
33
+
34
+ /* ------------------------------------------------------------------ */
35
+ /* Reset */
36
+ /* ------------------------------------------------------------------ */
37
+
38
+ *,
39
+ *::before,
40
+ *::after {
41
+ box-sizing: border-box;
42
+ }
43
+
44
+ html {
45
+ -webkit-text-size-adjust: 100%;
46
+ }
47
+
48
+ body {
49
+ margin: 0;
50
+ background: var(--hs-view-bg);
51
+ color: var(--hs-fg);
52
+ font-family: var(--hs-font-body);
53
+ font-size: var(--hs-type-body-size);
54
+ font-weight: var(--hs-type-body-weight);
55
+ line-height: var(--hs-type-body-lh);
56
+ letter-spacing: var(--hs-type-body-track);
57
+ }
58
+
59
+ button,
60
+ input,
61
+ select,
62
+ textarea {
63
+ font: inherit;
64
+ color: inherit;
65
+ }
66
+
67
+ /* f02 - the mono face is shown with ligatures off. */
68
+ code,
69
+ kbd,
70
+ pre,
71
+ samp {
72
+ font-family: var(--hs-font-mono);
73
+ font-variant-ligatures: none;
74
+ }
75
+
76
+ /* ------------------------------------------------------------------ */
77
+ /* Type scale (f03, l07) */
78
+ /* ------------------------------------------------------------------ */
79
+
80
+ .hs-display {
81
+ font-family: var(--hs-font-display);
82
+ font-size: var(--hs-type-display-size);
83
+ font-weight: var(--hs-type-display-weight);
84
+ line-height: var(--hs-type-display-lh);
85
+ letter-spacing: var(--hs-type-display-track);
86
+ }
87
+
88
+ .hs-title-1 {
89
+ font-family: var(--hs-font-display);
90
+ font-size: var(--hs-type-title-1-size);
91
+ font-weight: var(--hs-type-title-1-weight);
92
+ line-height: var(--hs-type-title-1-lh);
93
+ letter-spacing: var(--hs-type-title-1-track);
94
+ }
95
+
96
+ .hs-title-2 {
97
+ font-family: var(--hs-font-display);
98
+ font-size: var(--hs-type-title-2-size);
99
+ font-weight: var(--hs-type-title-2-weight);
100
+ line-height: var(--hs-type-title-2-lh);
101
+ letter-spacing: var(--hs-type-title-2-track);
102
+ }
103
+
104
+ .hs-title-3 {
105
+ font-family: var(--hs-font-display);
106
+ font-size: var(--hs-type-title-3-size);
107
+ font-weight: var(--hs-type-title-3-weight);
108
+ line-height: var(--hs-type-title-3-lh);
109
+ letter-spacing: var(--hs-type-title-3-track);
110
+ }
111
+
112
+ .hs-title-4 {
113
+ font-family: var(--hs-font-display);
114
+ font-size: var(--hs-type-title-4-size);
115
+ font-weight: var(--hs-type-title-4-weight);
116
+ line-height: var(--hs-type-title-4-lh);
117
+ letter-spacing: var(--hs-type-title-4-track);
118
+ }
119
+
120
+ .hs-heading {
121
+ font-family: var(--hs-font-display);
122
+ font-size: var(--hs-type-heading-size);
123
+ font-weight: var(--hs-type-heading-weight);
124
+ line-height: var(--hs-type-heading-lh);
125
+ letter-spacing: var(--hs-type-heading-track);
126
+ }
127
+
128
+ .hs-body {
129
+ font-family: var(--hs-font-body);
130
+ font-size: var(--hs-type-body-size);
131
+ font-weight: var(--hs-type-body-weight);
132
+ line-height: var(--hs-type-body-lh);
133
+ letter-spacing: var(--hs-type-body-track);
134
+ }
135
+
136
+ .hs-caption {
137
+ font-family: var(--hs-font-body);
138
+ font-size: var(--hs-type-caption-size);
139
+ font-weight: var(--hs-type-caption-weight);
140
+ line-height: var(--hs-type-caption-lh);
141
+ letter-spacing: var(--hs-type-caption-track);
142
+ }
143
+
144
+ /* ------------------------------------------------------------------ */
145
+ /* Links (f06-r4) */
146
+ /* ------------------------------------------------------------------ */
147
+
148
+ a.link,
149
+ .hs-link {
150
+ color: var(--hs-accent-text);
151
+ font-weight: 500;
152
+ text-decoration-line: underline;
153
+ text-decoration-color: var(--hs-accent-bg);
154
+ text-decoration-thickness: 1px;
155
+ text-underline-offset: 2px;
156
+ }
157
+
158
+ /* f06-r4 - light raises the underline to 3 px at a 3 px offset. */
159
+ @media (prefers-color-scheme: light) {
160
+ :root:not([data-scheme='dark']) :where(a.link, .hs-link) {
161
+ text-decoration-thickness: 3px;
162
+ text-underline-offset: 3px;
163
+ }
164
+ }
165
+
166
+ [data-scheme='light'] a.link,
167
+ [data-scheme='light'] .hs-link {
168
+ text-decoration-thickness: 3px;
169
+ text-underline-offset: 3px;
170
+ }
171
+
172
+ [data-scheme='dark'] a.link,
173
+ [data-scheme='dark'] .hs-link {
174
+ text-decoration-thickness: 1px;
175
+ text-underline-offset: 2px;
176
+ }
177
+
178
+ /* f13-r3 - links take a tint background on keyboard focus. */
179
+ a.link:focus-visible,
180
+ .hs-link:focus-visible {
181
+ outline: none;
182
+ background: var(--hs-accent-tint);
183
+ color: var(--hs-accent-text);
184
+ }
185
+
186
+ /* ------------------------------------------------------------------ */
187
+ /* Focus */
188
+ /* ------------------------------------------------------------------ */
189
+
190
+ /*
191
+ * f13-r3, k01b, k03f: focus is the tint-and-lift treatment, never a ring,
192
+ * outline, underline, bar or dot. Each component owns its exact focus rule;
193
+ * this reset removes the user-agent ring so no component has to repeat it.
194
+ * Text-type fields keep --hs-control-tone and show focus through the caret
195
+ * (k03f); filled buttons deepen their fill (k01b).
196
+ */
197
+ :focus-visible {
198
+ outline: none;
199
+ }
200
+
201
+ /* ------------------------------------------------------------------ */
202
+ /* Utilities */
203
+ /* ------------------------------------------------------------------ */
204
+
205
+ .hs-visually-hidden {
206
+ position: absolute;
207
+ width: 1px;
208
+ height: 1px;
209
+ margin: -1px;
210
+ padding: 0;
211
+ overflow: hidden;
212
+ clip: rect(0 0 0 0);
213
+ clip-path: inset(50%);
214
+ white-space: nowrap;
215
+ border: 0;
216
+ }
217
+
218
+ /*
219
+ * f12 A - every icon is an inline SVG using the shipped sprite. Size it with
220
+ * --hs-icon-size (16 px default); colour is inherited through currentColor.
221
+ */
222
+ .hs-icon {
223
+ --hs-icon-size: 16px;
224
+ display: inline-block;
225
+ flex: none;
226
+ width: var(--hs-icon-size);
227
+ height: var(--hs-icon-size);
228
+ fill: currentColor;
229
+ vertical-align: middle;
230
+ }
231
+
232
+ /* ------------------------------------------------------------------ */
233
+ /* Reduced motion (f14b-r1) */
234
+ /* ------------------------------------------------------------------ */
235
+
236
+ /*
237
+ * The duration tokens are overridden to 0ms in tokens.css. Scrolling is
238
+ * immediate as well. Components set their own animation fallbacks (the
239
+ * spinner is the recorded k09-rm exception).
240
+ */
241
+ @media (prefers-reduced-motion: reduce) {
242
+ :root {
243
+ scroll-behavior: auto;
244
+ }
245
+ }
@@ -0,0 +1,257 @@
1
+ /*
2
+ * Admin area composition (l10, p05, p24-r3, p26, p26b).
3
+ * The admin pages reuse the k28 row groups (list.css) and the k13 cards (card.css);
4
+ * this file adds only the admin-specific pieces: the Overview grid, the instance-dialog
5
+ * import-root rows, the plugin permission list, the storage bar with its legend, and
6
+ * the acquisition row spacing.
7
+ *
8
+ * plugin-approval-interim: the Install confirmation (340 px dialog with the permission
9
+ * list, Cancel and a suggested Install) and the File-tab permission list are built but
10
+ * stay switched off until the core reports permissions for uninstalled plugins. Until
11
+ * then no permission list shows before install. No CSS state is added for the switch.
12
+ */
13
+
14
+ /* ------------------------------------------------------------------ */
15
+ /* l10 B - Overview: a card grid; the cards themselves are card.css */
16
+ /* ------------------------------------------------------------------ */
17
+
18
+ .hs-admin-overview {
19
+ display: grid;
20
+ grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
21
+ gap: 16px;
22
+ }
23
+
24
+ @media (max-width: 720px) {
25
+ .hs-admin-overview {
26
+ grid-template-columns: 1fr;
27
+ }
28
+ }
29
+
30
+ /* ------------------------------------------------------------------ */
31
+ /* p05 - instance dialog import-root rows */
32
+ /* ------------------------------------------------------------------ */
33
+
34
+ /* A grey group inside the Files section of the 640 px instance dialog. */
35
+ .hs-import-roots {
36
+ display: flex;
37
+ flex-direction: column;
38
+ border-radius: var(--hs-radius-card);
39
+ overflow: hidden;
40
+ background: var(--hs-group-bg);
41
+ box-shadow: var(--hs-group-shadow);
42
+ }
43
+
44
+ .hs-import-root {
45
+ display: flex;
46
+ align-items: center;
47
+ gap: 8px;
48
+ padding: 8px 10px;
49
+ box-sizing: border-box;
50
+ }
51
+
52
+ .hs-import-roots .hs-import-root + .hs-import-root {
53
+ box-shadow: inset 0 1px 0 var(--hs-separator);
54
+ }
55
+
56
+ .hs-import-roots > .hs-setting-row {
57
+ box-shadow: inset 0 1px 0 var(--hs-separator);
58
+ }
59
+
60
+ .hs-import-root__id {
61
+ flex: none;
62
+ width: 110px;
63
+ }
64
+
65
+ .hs-import-root__path {
66
+ flex: 1;
67
+ min-width: 0;
68
+ }
69
+
70
+ .hs-import-root__path .hs-field__value {
71
+ font: 12.5px var(--hs-font-mono);
72
+ }
73
+
74
+ .hs-import-root__mode {
75
+ flex: none;
76
+ width: 96px;
77
+ }
78
+
79
+ .hs-import-roots__hint {
80
+ margin: 6px 0 0;
81
+ color: var(--hs-fg-muted);
82
+ font-size: 12.5px;
83
+ }
84
+
85
+ /* Phones: the path takes the full first line; Id and Mode share the second. */
86
+ @media (max-width: 720px) {
87
+ .hs-import-root {
88
+ flex-wrap: wrap;
89
+ }
90
+
91
+ .hs-import-root__path {
92
+ flex-basis: 100%;
93
+ order: -1;
94
+ }
95
+
96
+ .hs-import-root__id,
97
+ .hs-import-root__mode {
98
+ width: calc(50% - 4px);
99
+ }
100
+ }
101
+
102
+ /* ------------------------------------------------------------------ */
103
+ /* p24-r3 - plugin permission list */
104
+ /* ------------------------------------------------------------------ */
105
+
106
+ .hs-permission-list {
107
+ display: flex;
108
+ flex-direction: column;
109
+ gap: 6px;
110
+ margin-top: 6px;
111
+ }
112
+
113
+ .hs-permission-row {
114
+ display: flex;
115
+ align-items: center;
116
+ gap: 10px;
117
+ font-size: 13px;
118
+ }
119
+
120
+ .hs-permission-row__scope {
121
+ flex: none;
122
+ min-width: 64px;
123
+ font: 12px var(--hs-font-mono);
124
+ color: var(--hs-fg);
125
+ }
126
+
127
+ .hs-permission-row__detail {
128
+ flex: 1;
129
+ min-width: 0;
130
+ color: var(--hs-fg-muted);
131
+ }
132
+
133
+ .hs-permission-row .hs-pill {
134
+ flex: none;
135
+ margin-left: auto;
136
+ }
137
+
138
+ @media (max-width: 720px) {
139
+ .hs-permission-row {
140
+ flex-wrap: wrap;
141
+ row-gap: 2px;
142
+ }
143
+
144
+ .hs-permission-row__detail {
145
+ flex-basis: 100%;
146
+ order: 3;
147
+ }
148
+ }
149
+
150
+ /* ------------------------------------------------------------------ */
151
+ /* p26 - storage usage bar and legend */
152
+ /* ------------------------------------------------------------------ */
153
+
154
+ .hs-storage-usage {
155
+ display: flex;
156
+ flex-direction: column;
157
+ gap: 14px;
158
+ max-width: 760px;
159
+ padding: 18px;
160
+ border-radius: var(--hs-radius-card);
161
+ background: var(--hs-group-bg);
162
+ box-shadow: var(--hs-group-shadow);
163
+ }
164
+
165
+ .hs-storage-bar {
166
+ display: flex;
167
+ height: 14px;
168
+ border-radius: var(--hs-radius-full);
169
+ overflow: hidden;
170
+ background: color-mix(in srgb, var(--hs-fg) 12%, transparent);
171
+ }
172
+
173
+ .hs-storage-bar > i {
174
+ display: block;
175
+ height: 100%;
176
+ }
177
+
178
+ .hs-storage-legend {
179
+ display: grid;
180
+ grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
181
+ gap: 12px;
182
+ }
183
+
184
+ .hs-storage-legend__item {
185
+ display: flex;
186
+ align-items: flex-start;
187
+ gap: 8px;
188
+ }
189
+
190
+ .hs-storage-legend__swatch {
191
+ flex: none;
192
+ width: 12px;
193
+ height: 12px;
194
+ margin-top: 3px;
195
+ border-radius: 3px;
196
+ }
197
+
198
+ .hs-storage-legend__text {
199
+ display: flex;
200
+ flex-direction: column;
201
+ }
202
+
203
+ .hs-storage-pinned {
204
+ margin: 0;
205
+ color: var(--hs-fg-muted);
206
+ font-size: 13px;
207
+ }
208
+
209
+ /* p26: Library acid, Cache acid at 55% over the view, Folders muted, the rest free. */
210
+ .hs-storage-bar__library,
211
+ .hs-storage-legend__swatch--library {
212
+ background: var(--hs-accent-bg);
213
+ }
214
+
215
+ .hs-storage-bar__cache,
216
+ .hs-storage-legend__swatch--cache {
217
+ background: color-mix(in srgb, var(--hs-accent-bg) 55%, var(--hs-view-bg));
218
+ }
219
+
220
+ .hs-storage-bar__folders,
221
+ .hs-storage-legend__swatch--folders {
222
+ background: var(--hs-fg-muted);
223
+ }
224
+
225
+ .hs-storage-bar__free,
226
+ .hs-storage-legend__swatch--free {
227
+ background: color-mix(in srgb, var(--hs-fg) 12%, transparent);
228
+ }
229
+
230
+ /* ------------------------------------------------------------------ */
231
+ /* p26b - acquisition rows */
232
+ /* ------------------------------------------------------------------ */
233
+
234
+ .hs-setting-row--acquisition {
235
+ align-items: flex-start;
236
+ padding-top: 12px;
237
+ padding-bottom: 12px;
238
+ }
239
+
240
+ .hs-setting-row--acquisition .hs-setting-row__text {
241
+ gap: 3px;
242
+ }
243
+
244
+ .hs-setting-row--acquisition .hs-setting-row__subtitle {
245
+ font-size: 13px;
246
+ }
247
+
248
+ .hs-setting-row--acquisition .hs-pill {
249
+ flex: none;
250
+ }
251
+
252
+ /* Phones: the summary wraps and the menu stays a flat icon button. */
253
+ @media (max-width: 720px) {
254
+ .hs-setting-row--acquisition .hs-setting-row__subtitle {
255
+ white-space: normal;
256
+ }
257
+ }