@hearthscale/app-ui 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.
@@ -0,0 +1,574 @@
1
+ # The `hs-*` class names — versioned API
2
+
3
+ Every class below is public API from the moment the first app renders
4
+ against it: themes select on these names, and the top maintenance cost in
5
+ comparable ecosystems is undocumented class names that move. Renaming or
6
+ removing one is a break — one major per release train, named in the release
7
+ notes. Adding a name is free.
8
+
9
+ Scope:
10
+
11
+ - **`.hs-shell`** is the theme root (`<ThemeRoot>`), the glass frame every
12
+ surface renders in; its palette is the token set on `.hs-shell` /
13
+ `.hs-shell[data-theme='light']`. Nothing leaks into a page that does not
14
+ opt in.
15
+
16
+ ## Shell frame
17
+
18
+ Model presentation uses `.hs-model-avatar` for publisher artwork,
19
+ `.hs-model-details` / `.hs-model-details-row` for the fact rows,
20
+ `.hs-model-detail-fact` / `.hs-model-detail-chip` for labeled metadata, and
21
+ `.hs-model-capabilities-labeled` for icon-and-label capability chips. The compact
22
+ capability variant retains `.hs-model-capabilities` / `.hs-model-capability`.
23
+
24
+ | Class | Marks |
25
+ | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
26
+ | `hs-shell` | the theme root carrying the token set |
27
+ | `hs-shell-frame` | a window's frame; its `data-*` carry the desktop frame's states |
28
+ | `hs-side` | the side column: the rail |
29
+ | `hs-plugrow` | one app row in the sidebar |
30
+ | `hs-projrow` | a project row in the sidebar |
31
+ | `hs-sess`, `hs-sessrow`, `hs-stitle` | a session list, one session row, its title |
32
+ | `hs-session-row` | a session or helper row; `data-filed` in a project, `data-child` for a helper, `data-dragged` while carried |
33
+ | `hs-helper-mark` | the helper mark at the end of a helper row |
34
+ | `hs-project-row`, `hs-app-row` | a project row, an app row; `data-over` while a drag hovers it |
35
+ | `hs-sidebar-plus`, `hs-sidebar-spacer` | a row's new-session mark; the room the windowed list keeps for rows it does not draw |
36
+ | `hs-sidebar-rail-mark` | an app's mark on its rail plate |
37
+ | `hs-rail-plate-bypass` | the warning mark on the rail plate of an app at Bypass all permissions |
38
+ | `hs-rowact` | the actions that appear on a hovered row |
39
+ | `hs-pinned` | the pin mark on a pinned session row |
40
+ | `hs-spin` | a mark that turns while work runs, on an HTML box |
41
+ | `hs-profile-glyph` | the account mark on the ladder |
42
+ | `hs-model-picker`, `hs-model-trigger`, `hs-model-trigger-name`, `hs-model-trigger-chevron` | the composer's models, one trigger per kind, its name and chevron |
43
+ | `hs-picker`, `hs-picker-search` | the model picker, its search |
44
+ | `hs-picker-list`, `hs-picker-empty` | the models, "No model matches." or why none can run |
45
+ | `hs-picker-row`, `hs-picker-row-text`, `hs-picker-row-name`, `hs-picker-row-sub` | one model (`data-state` is `ready`, `absent`, `downloading` or `unavailable`; `data-download` where a press downloads it or asks a paired Server for it), its name and where it runs |
46
+ | `hs-picker-row-action` | the Download on the row of a model this computer's Server has not downloaded, or the Ask on the row of one a paired Server has not |
47
+ | `hs-picker-row-check` | the place of the mark of the model in use, which every row keeps |
48
+ | `hs-provider-mark` | a provider's place or cloud mark |
49
+ | `hs-rview`, `hs-ptab`, `hs-tabscroll` | a tab's own box, a tab of a strip, the tab strip |
50
+ | `hs-app-surface` | an app's own tab in a row: the shell's chat of a conversation or the enable card; an app's view lays its `hs-sidebar-column` beside its chat in it |
51
+ | `hs-page` | a page of the shell's own in a tab: its navigation, a hairline, and `hs-page-main` |
52
+ | `hs-page-main` | a page's own column: Settings', the documentation's, the Marketplace's or the account's; `data-crowded` while the documentation's column reaches under its Ask press |
53
+ | `hs-window-notice`, `hs-window-notice-text` | a stopped platform's card over the inner window, and its sentence |
54
+ | `hs-window-wrap` | the inner window's box beside the rail |
55
+ | `hs-window-tiles` | the workspace's box, which the requests and notices of the window lie over |
56
+ | `hs-level`, `hs-level-control`, `hs-level-name`, `hs-level-chevron` | the permission level control and its name, which a narrow composer hides; `data-level` names the level in force, `data-open` marks its open menu |
57
+ | `hs-chat-body` | the transcript's box under whatever sits above it |
58
+ | `hs-view-frame`, `hs-view-iframe`, `hs-view-failure` | a hosted view in a view row, or a view surface that fills its tab; its sandboxed frame; `data-mode` is `inline` under its result, `tab` in a tab of its own or for a view surface, `modal` in a modal over its tile, `overlay` over other programs, `popover` at the tray icon; `data-border` is `false` for a view that draws its own edge |
59
+ | `hs-view-modal` | a view in a modal over its tile: the scrim that dims the tile, under the view's clear frame and under the requests that float over the tile |
60
+ | `hs-view-sheet` | the plate a view’s frame sits on |
61
+ | `hs-view-place` | the place of a result’s view under its result; `data-away` while it shows in a tab of its own |
62
+ | `hs-view-bar`, `hs-view-bar-head` | the host's bar of a result's view, under its result and in its modal: the app's mark and name, then the presses that move the view; `data-mode` is `inline` or `modal` |
63
+ | `hs-view-home` | the element a result's view renders into, which moves between its place, its tab and its modal and adds no box |
64
+ | `hs-view-modal-plate` | the plate of a result's view the person moved over the chat, inset from the tile's edges |
65
+ | `hs-ask-float` | a request floating over the inner window, over the soft scrim |
66
+ | `hs-slot-layer`, `hs-slot`, `hs-slot-part` | the layer over a view that fills its tab, `data-animate` while its parts glide to new places; one slot the view reserved, anchored by its insets, `data-kind` its kind (`chat`, `composer`, `cards`, `terminal`, `model`) and `data-slot` its id; the part the shell draws there |
67
+ | `hs-url`, `hs-urlin`, `hs-urlgo`, `hs-urlph` | a browser's address field and its parts |
68
+ | `hs-scroll` | a scroll container with the shell's scrollbar |
69
+ | `hs-menu`, `hs-mitem` | a floating menu surface and one item |
70
+ | `hs-waytile`, `hs-orb` | a colourway tile and one of its orbs; `data-sel` marks the pick |
71
+ | `hs-confirm` | the backdrop of a confirmation dialog, or of a wait with no control, over the shell |
72
+ | `hs-confirm-box` | that dialog; `hs-confirm-title`, `hs-confirm-body` its two lines |
73
+ | `hs-confirm-notes` | the scrolling text under a dialog's body: a release's notes |
74
+ | `hs-confirm-cancel`, `hs-confirm-action` | its two buttons: the way out, and the action it asks for |
75
+ | `hs-sheet-shell` | a small text sheet over the shell |
76
+ | `hs-walk` | a walkthrough; `data-host` is `dialog` (a plate over the shell, on a veil) or `window` (the whole window) |
77
+ | `hs-walk-card`, `hs-walk-close` | its card; the close mark at the card's top right |
78
+ | `hs-walk-image` | the picture band across the top of a card |
79
+ | `hs-server-picture`, `hs-apps-picture`, `hs-picture-mesh`, `hs-picture-tile`, `hs-picture-line`, `hs-heatmap-picture` | an onboarding card's picture over its mesh: the Server and a computer, the wall of apps; the mesh, a glass tile in it, a line between tiles; the heat picture of the hearth mark |
80
+ | `hs-tour`, `hs-tour-part`, `hs-tour-card`, `hs-tour-title`, `hs-tour-text`, `hs-tour-actions`, `hs-tour-fill` | a tour over the window: the veil, the part it lights, the card (`data-placed` once it stands beside the part), the stop's title and words, its buttons and the room that sets Back and Next apart from Close |
81
+ | `hs-walk-main` | the region under the picture that holds the words, the rows and the live content; `data-image` under one |
82
+ | `hs-walk-title`, `hs-walk-sub` | a card's title and the line under it |
83
+ | `hs-walk-rows`, `hs-walk-row` | a card's list (`data-layout` is `list`, `open` or `grid`), and one row of it |
84
+ | `hs-walk-row-mark`, `hs-walk-row-text`, `hs-walk-row-title`, `hs-walk-row-sub` | a row's mark, its words, its title and the line under the title |
85
+ | `hs-walk-body` | the bordered plate a card's live content sits in |
86
+ | `hs-walk-foot`, `hs-walk-dots`, `hs-walk-dot` | the foot, the page dots, one dot; `data-sel` marks the card shown |
87
+ | `hs-walk-foot-start`, `hs-walk-next-off` | Back and a second way off the card; the forward press on a card the reader cannot move past |
88
+ | `hs-onboarding-body`, `hs-onboarding-prose` | the live part of a first-run card; a line of words in it |
89
+ | `hs-onboarding-row` | a glass row that starts an act (`data-press`) or says it is done (`data-ticked`) |
90
+ | `hs-onboarding-row-mark`, `hs-onboarding-row-label`, `hs-onboarding-row-done` | the row's mark, its words, and the check and word of a done act |
91
+ | `hs-onboarding-fine`, `hs-onboarding-problem`, `hs-onboarding-retry` | a quiet line under a press; a failure; the press that tries again |
92
+ | `hs-onboarding-link` | a link in a card's words, in the words' own colour |
93
+ | `hs-titlebar` | the title bar of a window that draws its own caption buttons (the Server, the installer) |
94
+ | `hs-caption-glyph` | a caption glyph under the system's own caption button; `data-hovered` while that button is hovered |
95
+ | `hs-caption-rule` | the hairline between the top lane and the system's caption buttons |
96
+ | `hs-submenu-chevron` | the chevron of a menu row that opens a flyout |
97
+ | `hs-browser-step-off` | a browser's Back or Forward with no page to go to |
98
+ | `hs-tip`, `hs-tipwrap` | a tooltip and the element that anchors one |
99
+ | `hs-tog` | a toggle switch |
100
+ | `hs-in`, `hs-ta`, `hs-ph-icon` | a text input, a textarea, a placeholder with a leading icon |
101
+ | `hs-navhead`, `hs-setrow`, `hs-chip` | a settings nav section label, a settings row, a choice chip |
102
+ | `hs-sethead` | a settings detail page's header: its mark, its name and its sub |
103
+ | `hs-grantrow` | one grant in the access list, a `hs-list-row` with its Revoke; an approval surface |
104
+ | `hs-range`, `hs-tile` | a settings slider; a scheme or colourway tile |
105
+ | `hs-flash` | the row a settings search hit landed on |
106
+ | `hs-mask` | a drop-in icon set's mark, drawn as a mask in the text colour |
107
+
108
+ ## The frame: rail, tiles and surfaces
109
+
110
+ | Class | Marks |
111
+ | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
112
+ | `hs-rail` | the rail at the window's left edge, with `hs-sidebar-rail`; `data-lifting` while a plate is dragged |
113
+ | `hs-rail-top`, `hs-rail-plate` | the mark's zone at the top, an app's plate; `data-lifted` during a drag, `data-slide` while it moves |
114
+ | `hs-fan`, `hs-fan-item`, `hs-fan-arrow`, `hs-fan-dot`, `hs-fan-item-dot` | buttons folded into the place of the last one (`data-axis` is `row` or `column`; `data-open` while unfolded), one button, the arrow on the side it opens to, the dot while a button waits, the dot on the button that waits |
115
+ | `hs-ladder` | the system ladder, a column `hs-fan` at the rail's foot |
116
+ | `hs-ladder-rung` | one rung, an `hs-fan-item`; `data-solid`, `data-active`, `data-pressed` |
117
+ | `hs-workspace` | the tiles' box; `data-drag` is `row`, `column` or `tab` |
118
+ | `hs-workspace-tile`, `hs-tile-panel` | a tile (`data-tile`), its panel |
119
+ | `hs-lane` | a tile's lane; `data-row` is `top` or `low`, `data-caption` where it ends under the caption buttons |
120
+ | `hs-lane-crumb`, `hs-lane-crumb-app`, `hs-lane-crumb-title` | a lone tab's breadcrumb (`data-fit` is `full`, `cut`, `app` or `mark`), which ends with the tab's `hs-tab-close` under the pointer, its app's name, its title; `data-cut` on words cut at their end |
121
+ | `hs-lane-tabs`, `hs-lane-tab`, `hs-lane-tab-mark` | the strip from the second tab on, with the panel tab classes; a tab (`data-fit` is `full`, `cut` or `mark`; `data-hover`; `data-leaving` while it closes; `data-cut` on its cut `hs-tab-label`), its mark |
122
+ | `hs-lane-tabs-wrap`, `hs-lane-tabs-arrow` | the strip with its arrows; the arrow over an end with more tabs past it, which scrolls the strip there (`data-side` is `start` or `end`) |
123
+ | `hs-lane-fan`, `hs-lane-button` | the tile's controls, a row `hs-fan` at the lane's right end; one control (`data-control`; `data-open` on the menu's while the menu is open) |
124
+ | `hs-lane-plus`, `hs-lane-title-field`, `hs-lane-probe` | the plus after the last tab, shown while the lane is hovered; a title edited in place; the unseen measure of the least of a cut title |
125
+ | `hs-lane-rule` | the hairline between two lanes side by side |
126
+ | `hs-tab-card`, `hs-tab-card-title`, `hs-tab-card-preview` | the hover card under a strip's tab (`data-open`), its title, its picture |
127
+ | `hs-divider` | the invisible divider of a split; `data-axis` is `row` or `column` |
128
+ | `hs-tile-drop` | where a dragged tab would land |
129
+ | `hs-surfaces`, `hs-surface` | the stable layer (`data-drag`), one surface (`data-surface`; `data-state` is `live` or `warm`) |
130
+ | `hs-web-page` | an app's web surface: its page, which fills its surface |
131
+ | `hs-page-failed` | a page of an app that did not load: over it, why, and Try again (`data-covered` while a view covers the page) |
132
+
133
+ ## Shell interaction states
134
+
135
+ | Class | Marks |
136
+ | --------------------------------------------------- | ---------------------------------------------------------------------- |
137
+ | `hs-hovbox`, `hs-hovbox-ink` | hover plate; hover plate that also brightens the ink |
138
+ | `hs-hovink`, `hs-hovmut` | hover that brightens ink only / mutes |
139
+ | `hs-boxact`, `hs-boxsel` | the active plate, the selected plate |
140
+ | `hs-glassbtn` | a glass button |
141
+ | `hs-inktext`, `hs-inkmut`, `hs-inkdim`, `hs-inkbad` | the ink an element rests at, so a hover or selection rule can reach it |
142
+
143
+ ## Transcript
144
+
145
+ | Class | Marks |
146
+ | ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
147
+ | `hs-transcript`, `hs-transcript-spacer`, `hs-transcript-rows`, `hs-transcript-row` | the column of rows, and the room under it that holds a sent prompt near the top; the list of the rows drawn near the view, as tall as all of them, and one row placed in it |
148
+ | `hs-turn` | one prompt or one answer, with the actions that show on hover |
149
+ | `hs-md`, `hs-md-link`, `hs-md-picture`, `hs-md-missing` | an answer's markdown (`data-streaming` is `tokens` or `blocks` while it arrives); a link in it; a picture of the turn it names; a named picture that is not there |
150
+ | `hs-abar` | the actions under a prompt or an answer |
151
+ | `hs-chat-action`, `hs-chat-time`, `hs-chat-pager` | one of those actions; the moment on hover; the branch pager |
152
+ | `hs-copy`, `hs-copy-tip` | the Copy action and the "Copied" tip over it |
153
+ | `hs-work-row` | one call; `data-status` is `running`, `waiting`, `completed`, `failed`, `declined`, `stopped`, `skipped` or `unknown` |
154
+ | `hs-work-head` | a line with an action beside it, such as Stop; a row's `data-cell` names a program that runs on |
155
+ | `hs-work-line`, `hs-work-mark`, `hs-work-label`, `hs-work-time`, `hs-work-chevron` | a row's line, its mark, its words, the time the call took (on hover), its chevron (`data-open`) |
156
+ | `hs-work-body` | what an opened call did |
157
+ | `hs-work-nested` | the calls made while a call ran, under its line |
158
+ | `hs-work-command`, `hs-work-path`, `hs-work-text`, `hs-work-output` | its blocks: the command, the path, the prompt or text, the output |
159
+ | `hs-work-decision`, `hs-work-note`, `hs-work-more` | who let it run or refused it (`data-refused`); a quiet line; the raw details' disclosure |
160
+ | `hs-work-live` | the row that names the live turn's running call |
161
+ | `hs-work-toggle`, `hs-work-sentence` | a finished run of calls as one sentence; `data-failure` marks a run that ended in a failure |
162
+ | `hs-work-group` | an opened run; `data-fade` is `top`, `bottom` or `both` where more calls lie beyond its edge |
163
+ | `hs-activity`, `hs-activity-list` | thoughts and calls of one turn (`data-active` while live), and its opened list |
164
+ | `hs-thought`, `hs-thought-preview`, `hs-reasoning` | one thought, its one-line preview, its text |
165
+ | `hs-spawn`, `hs-spawn-members`, `hs-spawn-member` | the helpers a turn handed work to (`data-failure`), their list, one helper |
166
+ | `hs-spawn-head`, `hs-spawn-title`, `hs-spawn-agent`, `hs-spawn-preview` | a helper's line, its title, its agent, its latest words |
167
+ | `hs-working`, `hs-working-clock` | the live turn's header and its clock |
168
+ | `hs-turn-fold` | a settled turn's work behind one line |
169
+ | `hs-thread-mark`, `hs-thread-mark-line`, `hs-thread-mark-text` | a line across the transcript with a caption in it |
170
+ | `hs-fork-origin`, `hs-tail-mark` | where a fork came from; where the model reads word for word again |
171
+ | `hs-level-mark` | where the level a conversation's turns run at changes, with the level's mark and name; `data-level` is `manual`, `auto`, `skip` or `bypass` |
172
+ | `hs-compaction`, `hs-compaction-line`, `hs-compaction-body`, `hs-compaction-where` | the separator of compacted messages, its line, the summary, who wrote it |
173
+ | `hs-notice-row`, `hs-notice-text` | something that went wrong or stopped; `data-tone` is `bad` or `warn` |
174
+ | `hs-app-entry` | an app's own entry |
175
+ | `hs-changed`, `hs-changed-head`, `hs-changed-title`, `hs-changed-files` | the files a turn changed, its head, its title, the file chips |
176
+ | `hs-diff-count` | a line count beside a changed file; `data-kind` is `add` or `del` |
177
+ | `hs-view-row` | a result's view in the transcript |
178
+ | `hs-media`, `hs-media-pictures`, `hs-media-actions` | what a call made; its pictures (`data-count` is `one` or `many`); the actions over a picture |
179
+ | `hs-chat-image`, `hs-chat-image-name` | a picture a call made, in a frame of its size; the name of one that did not load |
180
+ | `hs-audio`, `hs-audio-play`, `hs-audio-name`, `hs-audio-bar`, `hs-audio-fill` | a sound's player, its play and pause, its name, its bar and the part played |
181
+ | `hs-audio-time`, `hs-audio-save` | the player's times and its Save |
182
+ | `hs-media-text`, `hs-media-text-head`, `hs-media-text-name`, `hs-media-text-save`, `hs-media-text-body` | a text a call made, such as a transcript; its head, its name, its Save, its words |
183
+ | `hs-user-bubble`, `hs-user-text`, `hs-user-more` | a prompt, its text (`data-folded`), "Show full message" |
184
+ | `hs-user-tiles`, `hs-user-tile-cell`, `hs-user-tile`, `hs-user-tile-name` | a prompt's pictures, one cell, the tile, the name of one that did not load |
185
+ | `hs-user-caption`, `hs-user-caption-toggle`, `hs-user-caption-text` | what a model read in a picture, its disclosure, its words |
186
+ | `hs-user-file`, `hs-user-file-name` | another file a prompt carried, and its name |
187
+ | `hs-turn-rail`, `hs-turn-rail-mark`, `hs-turn-rail-line`, `hs-turn-preview` | the rail of prompts, one mark, its line (`data-bright` for the turns on screen), the hover preview |
188
+ | `hs-jump-place`, `hs-jump` | where the "Scroll to end" pill sits, and the pill |
189
+ | `hs-chat` | the chat; `data-layout` is `composer` where it draws the composer alone |
190
+ | `hs-compose-position`, `hs-compose-box`, `hs-chat-fade` | the composer's column (`data-empty` on the opening screen), its box, the fade at the top |
191
+ | `hs-composer`, `hs-composer-dock`, `hs-composer-main` | the composer (`data-answering` while a request waits, `data-narrow` in its narrow form), the drawers on its top edge, its glass box |
192
+ | `hs-composer-field`, `hs-composer-editor`, `hs-composer-placeholder` | the editor's box, the editor, its placeholder |
193
+ | `hs-composer-footer`, `hs-composer-fill`, `hs-composer-tool`, `hs-composer-stop`, `hs-composer-send` | the footer, its spacer, a tool such as attach (`data-state` on Dictate is `opening`, `listening` or `transcribing`), Stop, Send |
194
+ | `hs-drawer`, `hs-drawer-dot`, `hs-drawer-fill`, `hs-drawer-text` | a drawer on the composer (`data-tone` is `info` or `menu`), its dot, its spacer, its sentence |
195
+ | `hs-composer-menu`, `hs-composer-menu-list`, `hs-composer-menu-row` | the `/` and `@` menu, its list, one row (`data-active`) |
196
+ | `hs-composer-menu-mark`, `hs-composer-menu-label`, `hs-composer-menu-sub`, `hs-composer-menu-status` | a row's mark, name and description; the searching or none-found words |
197
+ | `hs-inline-chip`, `hs-inline-chip-mark` | a file, a folder, a skill or an app's item in the editor or a sent prompt (`data-kind` is `file`, `folder`, `skill` or `mention`), its mark |
198
+ | `hs-composer-shelf`, `hs-shelf-tiles`, `hs-shelf-tile`, `hs-shelf-tile-open`, `hs-shelf-remove` | what rides the next prompt; its pictures, one tile, the tile's opener, a remove button |
199
+ | `hs-shelf-file`, `hs-shelf-file-name`, `hs-shelf-file-size` | another file on the shelf, its name, its size |
200
+ | `hs-shelf-chips`, `hs-shelf-chip`, `hs-shelf-chip-note` | the chips (`data-kind` is `folder`, `terminal`, or `context` for what a view adds, with `data-chip` its id), the "read only" note |
201
+ | `hs-shelf-refused` | a file the composer could not attach, or a level change the platform refused, in words |
202
+ | `hs-ring`, `hs-ring-panel`, `hs-ring-title`, `hs-ring-share`, `hs-ring-note` | the context ring, its popover, the popover's title, the share used, its sentence |
203
+ | `hs-ring-actions`, `hs-ring-answer`, `hs-ring-details-toggle`, `hs-ring-details` | Compact and the daemon's answer; the Details disclosure and what it holds |
204
+ | `hs-ring-fact`, `hs-ring-layer`, `hs-ring-layer-line`, `hs-ring-cost`, `hs-ring-text` | a fact of the prompt; one layer, its line (`data-static` for a tool's), its cost, its text |
205
+ | `hs-ask`, `hs-ask-head`, `hs-ask-mark`, `hs-ask-title`, `hs-ask-app`, `hs-ask-count` | a request (`data-placement` is `docked` or `floating`, `data-narrow` in its narrow form), its head, mark, title, app, and "1 of 3" |
206
+ | `hs-ask-body`, `hs-ask-note`, `hs-ask-data`, `hs-ask-command` | its sentence, a warning under it, a path or a code in it, the command it would run or what a tool call would do |
207
+ | `hs-ask-change`, `hs-ask-hunk`, `hs-ask-line`, `hs-ask-sign` | the lines an edit would change, one edit, one line (`data-kind` is `del` or `add`), its sign |
208
+ | `hs-ask-tools`, `hs-ask-tool`, `hs-ask-tool-name`, `hs-ask-tool-text` | a connector's tools, one tool, its name, its description |
209
+ | `hs-ask-actions`, `hs-ask-keys`, `hs-ask-options`, `hs-ask-option` | the request's buttons and the keys that answer it; a question's options, one option |
210
+ | `hs-ask-scroll`, `hs-ask-message`, `hs-ask-form` | a form's words, fields and preview, which scroll as one inside the card; its words, which keep their lines; its fields |
211
+ | `hs-ask-field`, `hs-ask-field-head`, `hs-ask-field-title`, `hs-ask-field-switch` | one field (`data-kind` names its kind, `data-problem` while it holds a value it may not send), its head, its title, the switch of a yes or no |
212
+ | `hs-ask-problem`, `hs-ask-refusal` | why a field cannot be sent; the platform's words when it refused the form |
213
+ | `hs-ask-chips`, `hs-ask-add` | a field's choices, the presses of its suggestions or words; the row that adds a word or a file |
214
+ | `hs-ask-picks`, `hs-ask-pick`, `hs-ask-pick-press`, `hs-ask-picture`, `hs-ask-pick-title`, `hs-ask-pick-mark` | a list of choices with pictures or of resources, one row (`data-sel` while chosen), its press, its picture, its title, the mark of whether it is chosen |
215
+ | `hs-chat-destination` | the project the first message of an opening screen goes into |
216
+ | `hs-drop-overlay`, `hs-drop-pill` | files dragged over the chat, and the words over them |
217
+ | `hs-user-blocks`, `hs-user-queued` | the terminal lines a prompt carried; the words under a message that waits (`data-queued` on its turn) |
218
+ | `hs-shine` | a live label's shine |
219
+ | `hs-unknown-part` | a transcript part no registered view claims |
220
+ | `hs-unknown-part-head`, `hs-unknown-part-context`, `hs-unknown-part-data` | its disclosure line; the text it fed the model; its raw data |
221
+
222
+ | Primitive | Marks |
223
+ | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
224
+ | `hs-status` | a state in words at the end of a row; `data-tone` is `ok`, `bad`, `warn`, `info` or `dim` |
225
+ | `hs-meter`, `hs-meter-track`, `hs-meter-fill` | how much of something is done or used; `data-variant` is `bar` or `ring`, `data-tone` `bad` near its limit |
226
+ | `hs-kbd` | a key the person can press |
227
+ | `hs-input` | a one-line field with a box; `data-variant` is `text`, `number` or `password` |
228
+ | `hs-chip`, `hs-chip-mark`, `hs-chip-text` | a small named thing; `data-tone` is `neutral`, `info`, `ok`, `warn` or `bad`; a choice chip carries `data-sel` and no tone |
229
+ | `hs-app-icon` | an app's own icon, or the mark of an app or a plugin |
230
+ | `hs-system-icon` | the machine's own icon for a file or a folder |
231
+ | `hs-file-kind` | a file's kind as a coloured mark until its system icon arrives; `data-kind` names the kind |
232
+ | `hs-lightbox`, `hs-lightbox-bar`, `hs-lightbox-button` | pictures over the window, its bar, a control on it |
233
+ | `hs-lightbox-step`, `hs-lightbox-body`, `hs-lightbox-stage` | the step to a picture beside (`data-side`), the body, the stage (`data-zoomed`) |
234
+ | `hs-lightbox-broken`, `hs-lightbox-caption`, `hs-lightbox-note`, `hs-lightbox-reread` | a picture that did not load, the caption, the note under it, "Read the picture again" |
235
+
236
+ ## Documentation
237
+
238
+ | Class | Marks |
239
+ | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
240
+ | `hs-docs-root`, `hs-docs-root-title`, `hs-docs-root-mark` | the documentation root on screen, which opens a menu of the others; its name; a root's mark in that menu |
241
+ | `hs-docs-folder-chevron`, `hs-docs-folder-pages` | a folder's chevron in the navigation (`data-open`); its pages, on a line beneath it |
242
+ | `hs-docs-ask` | the press at the page's top right that asks an app about the page |
243
+ | `hs-docs-page-foot` | under a page, over its pager: the date it was last changed |
244
+ | `hs-docs-unreachable` | a page or the whole documentation that could not be read, and its retry |
245
+
246
+ ## Diff
247
+
248
+ | Class | Marks |
249
+ | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
250
+ | `hs-diff` | the diff view, carrying the mono face its rows are set in; `data-wrap` wraps its rows |
251
+ | `hs-diff-bar` | its bar: the counts, collapse-all, and a raw patch's reason |
252
+ | `hs-diff-act` | a control on that bar |
253
+ | `hs-diff-reason`, `hs-diff-picked` | a raw patch's reason on the bar; the number of lines selected |
254
+ | `hs-diff-counts` | the added and deleted counts, each a `hs-diff-count` |
255
+ | `hs-diff-chevron`, `hs-diff-status` | a file header's chevron; its state: added, deleted or renamed |
256
+ | `hs-diff-file`, `hs-diff-path` | one file's header, sticky over that file's rows; the path on it |
257
+ | `hs-diff-row` | one unified row; `data-kind` is `add`, `del` or `ctx`, and `data-sel` marks it selected |
258
+ | `hs-diff-no`, `hs-diff-sign`, `hs-diff-text` | a row's two line-number gutters, its marker column, its text |
259
+ | `hs-diff-split`, `hs-diff-side` | a split row, `data-sel` marking it selected; its old or new half, `data-kind` `add`, `del`, `ctx` or `none` for an empty one, each with one gutter, a marker and a text |
260
+ | `hs-diff-tok` | a coloured token of a row's text, in `--shiki-light` or `--shiki-dark` by the scheme |
261
+ | `hs-diff-gap`, `hs-diff-hunk` | an unmodified run that expands in place; the hunk header beside it |
262
+ | `hs-diff-raw` | a patch the parser did not read, shown as text |
263
+
264
+ ## Product components (`packages/ui/src`)
265
+
266
+ One class per component, named after it: `hs-button`, `hs-card`, `hs-chart`,
267
+ `hs-code-block`, `hs-diagram`, `hs-hearth-pulse`, `hs-icon-button`,
268
+ `hs-label`, `hs-lockup`, `hs-mark`, `hs-modal`, `hs-modal-backdrop`,
269
+ `hs-mono`, `hs-notice`, `hs-page-title`,
270
+ `hs-terminal`, `hs-text-field`.
271
+
272
+ | Class | Marks |
273
+ | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
274
+ | `hs-button` | a text button; `data-variant` is `primary`, `secondary`, `ghost` or `danger`, `data-size` is `sm`, `md` or `lg`, `data-full` stretches it |
275
+ | `hs-icon-button` | a mark-only button; `data-size` is `sm`, `md` or `lg` |
276
+ | `hs-card` | a grouped surface; `data-variant` is `solid`, `glass` or `gate` (opaque), `data-tone` `warn` or `info` for one that asks |
277
+ | `hs-label` | a caption in the interface font |
278
+ | `hs-lockup-box`, `hs-lockup-mark`, `hs-lockup-word` | the lockup's 38px box, the mark on its floor, the wordmark beside it |
279
+ | `hs-model-avatar-initial` | a publisher's first letter where it has no picture |
280
+ | `hs-mono` | machine text inside a sentence or a row |
281
+ | `hs-page-title`, `hs-page-lead` | a page's heading (`data-hero` centres and enlarges it) and the line under it |
282
+ | `hs-fact-row`, `hs-fact-label`, `hs-fact-value` | a row of an information table, its label and its wrapping value |
283
+ | `hs-link-row`, `hs-link-row-chevron` | a row that opens its own page, and its chevron |
284
+ | `hs-list-row`, `hs-list-row-actions` | a row of a managed list, and the actions at its end |
285
+ | `hs-grant-groups`, `hs-grant-group-head`, `hs-grant-group-name`, `hs-grant-group-summary`, `hs-grant-group-chevron` | the access list, one card per app: its folding head, the app's name, the summary of what it holds, the chevron |
286
+ | `hs-grant-group-bypass` | the warning mark on the head of an app at Bypass all permissions |
287
+ | `hs-segmented`, `hs-segmented-option` | a choice of a few options, all in sight, and one option; `aria-checked` marks the chosen one |
288
+ | `hs-market-install-note` | why an install cannot start, or why it failed; `data-tone` is `warn` or `bad` |
289
+ | `hs-market-rate`, `hs-market-rate-star` | the site's rating control, and one of its five stars; `data-lit` on the stars up to the one the reader gave |
290
+ | `hs-market-rate-in`, `hs-market-rate-failed` | the press that sends a reader who is not signed in to sign in; the words where a rating cannot be read or saved |
291
+ | `hs-row-mark` | the mark before a row's label |
292
+ | `hs-nav-rail-press` | a press of the collapsed settings nav, a mark whose name floats beside it; `data-sel` on the page on screen |
293
+ | `hs-overlay-scroll`, `hs-overlay-thumb` | a scroller whose bar lies over the right end of its rows (`OverlayScroll`), and that bar; `data-shown` is `false` while the rows fit, `data-drag` is `true` while it is dragged |
294
+ | `hs-glyph-side-wide`, `hs-glyph-side-narrow` | with `hs-icon`, Hearthscale's own marks of a sidebar open wide and folded narrow, in the text colour |
295
+ | `hs-fact-lines` | a fact whose value is a list, one line per item |
296
+ | `hs-app-review` | the facts an update added, listed on an app's settings page |
297
+ | `hs-archive-facts` | an archived conversation's date and its number of entries |
298
+ | `hs-link` | a link that runs a handler instead of carrying an address |
299
+ | `hs-code-head`, `hs-code-language`, `hs-code-reason` | a code block's header bar, its language and the reason the code is shown as text |
300
+ | `hs-code-copy`, `hs-code-pre` | a code block's copy control and its text |
301
+ | `hs-modal-head`, `hs-modal-title` | a dialog's header and its title |
302
+ | `hs-report-body` | a dialog of what is sent: usage events as they leave, and performance reports in words with the text that is sent behind a press |
303
+ | `hs-report-exact` | the press of a report that shows the text that is sent, and that text |
304
+ | `hs-field-label`, `hs-field-input`, `hs-field-note`, `hs-field-hint` | a text field's label, input, the note beside the label, the line under the input |
305
+ | `hs-overlay-note`, `hs-overlay-note-title`, `hs-overlay-note-text` | an app's note over the person's other programs (`OverlayNote`), its title and its text |
306
+ | `hs-overlay-page` | with `hs-shell`, the theme root of the window an app's note shows in, which shows the programs behind it |
307
+ | `hs-view-window-page` | on the `html` of the page of the window an app's view shows in: a clear page with no margin |
308
+ | `hs-view-window` | with `hs-shell`, the theme root of the window an app's view shows in, over other programs or at the tray icon, which shows the programs behind it |
309
+ | `data-swatch` | on any element, a colour of the category palette by name (`rose` to `slate`): it sets `--swatch`, `--swatch-tint` and `--swatch-ink` for the element and what it holds |
310
+ | `hs-tinted` | an item of a category colour (`data-swatch`): its soft fill with its text in the colour's ink; `data-selected` fills it with the colour |
311
+ | `hs-swatch-dot` | the colour of an item in a row of text |
312
+ | `hs-swatch-picker`, `hs-swatch-choice` | the choice of a category colour (`SwatchPicker`), and one colour in it; `aria-checked` marks the chosen one |
313
+ | `hs-slider`, `hs-slider-value` | a slider's row (`Slider`): its `hs-range` track, and the value in words after it |
314
+ | `hs-popover` | a small panel beside the element it opens from (`Popover`) |
315
+ | `hs-toast-place`, `hs-toast`, `hs-toast-text` | where a toast shows: at the bottom of the window, or above an element with `data-above`; the toast (`Toast`) and its words |
316
+ | `hs-picker-field` | with `hs-input`, the field of a date or a time picker; `data-empty` while nothing is chosen |
317
+ | `hs-date-grid`, `hs-date-grid-head`, `hs-date-grid-month` | a month of days to choose from (`DateGrid`), its head and the month's name |
318
+ | `hs-date-grid-days`, `hs-date-grid-row`, `hs-date-grid-weekday`, `hs-date-grid-day` | the days' grid, one week, a weekday's name and one day; `data-today`, `data-outside` (of the month) and `aria-selected` on the day |
319
+ | `hs-person-mark` | a person's picture or initials (`PersonMark`); `data-size` is `sm`, `md` or `lg` |
320
+ | `hs-virtual-list`, `hs-virtual-list-rows`, `hs-virtual-list-row` | a list that draws only the rows in sight (`VirtualList`), the box of all its rows, and one row |
321
+ | `hs-picture-compare`, `hs-picture-compare-after`, `hs-picture-compare-handle`, `hs-picture-compare-knob`, `hs-picture-compare-name` | two pictures split by a line (`PictureCompare`): the second picture, the line's handle and its knob, and a picture's name (`data-side`) |
322
+ | `hs-rich-text` | with `hs-md`, the page of the rich text editor (`RichTextEditor`); `[data-model]` marks words a model wrote |
323
+
324
+ ## Server dashboard and installer
325
+
326
+ The Server dashboard and the installer window wear the shell frame
327
+ (`hs-shell-frame`, `hs-frame-*`, `hs-titlebar*`, `hs-side`, `hs-window*`)
328
+ and add these:
329
+
330
+ | Class | Marks |
331
+ | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
332
+ | `hs-caption-button` | a caption button a window with no system caption draws; `data-danger` on the close button |
333
+ | `hs-server-nav`, `hs-server-nav-pages`, `hs-server-nav-footer` | the dashboard's navigation column, its page list, its power action |
334
+ | `hs-server-window` | the box of the dashboard's page panel beside its navigation column |
335
+ | `hs-server-waiting` | the words a dashboard page shows while the Server is not running or not reached |
336
+ | `hs-server-pending` | a row's title with a pulse, while the account link waits on the browser |
337
+ | `hs-server-help` | the endpoint id's help in a dialog |
338
+ | `hs-installer-run`, `hs-installer-rows` | a run's card body, the bar over the list, and the list |
339
+ | `hs-installer-bar`, `hs-installer-fill` | the run's glass bar and its gold fill |
340
+ | `hs-installer-stage` | one stage of a run; `data-state` is `done`, `current`, `pending` or `failed` |
341
+ | `hs-installer-slot`, `hs-installer-dot` | a mark's slot at the start of a row; the dot of the current or a waiting stage |
342
+ | `hs-installer-label`, `hs-installer-detail` | a row's words, and the quiet detail at its end |
343
+ | `hs-installer-stopped`, `hs-installer-stopped-text` | a stopped run's sentence and its Retry; the sentence |
344
+ | `hs-installer-folder` | the install folder, a glass press that opens the folder dialog |
345
+ | `hs-installer-offer`, `hs-installer-specs`, `hs-installer-spec`, `hs-installer-spec-mark` | the set-up's offer, the machine's facts, one fact, its mark |
346
+ | `hs-installer-picks`, `hs-installer-pick`, `hs-installer-tick` | the receipt's rows, one row (`data-ticked`, `data-fixed`), its tick box |
347
+
348
+ ## The usage dashboard
349
+
350
+ The pages the api draws at `admin.` (`DashboardFrame`, `Bento`, `BentoTile`,
351
+ `Figures`, `BarSeries`, `DataTable`, `WorldMap`):
352
+
353
+ | Class | Marks |
354
+ | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
355
+ | `hs-dashboard` | a dashboard page on the shell's colour field, with the frame's grain over it |
356
+ | `hs-dashboard-bar`, `hs-dashboard-plate` | the bar at the top of the window, and its floating glass plate |
357
+ | `hs-dashboard-brand` | the lockup at the start of the bar |
358
+ | `hs-dashboard-nav`, `hs-dashboard-link` | the links to the pages, and one link; `aria-current="page"` on the page on screen, whose plate shows |
359
+ | `hs-dashboard-menu-toggle`, `hs-dashboard-menu`, `hs-dashboard-menu-open`, `hs-dashboard-menu-close` | on a narrow screen: the box that holds whether the sheet of links is open, the menu button, and its two marks |
360
+ | `hs-dashboard-main`, `hs-dashboard-title`, `hs-dashboard-note` | the page under the bar (`data-centered` on a page that says one thing), its title, a sentence that says why it shows no figures |
361
+ | `hs-bento` | the grid of tiles: twelve columns on a wide screen, one on a narrow one |
362
+ | `hs-bento-tile` | a glass tile; `data-span` is its share of the twelve columns, `data-tall` two rows high, `data-aside` with a part beside what it holds |
363
+ | `hs-bento-title`, `hs-bento-body`, `hs-bento-aside` | a tile's name, what it holds, and the narrower part beside that, which scrolls |
364
+ | `hs-figures`, `hs-figure`, `hs-figure-value`, `hs-figure-label` | headline numbers: their row of glass tiles, one tile, its number, the name of what it counts; inside a tile, the figures lie on it one under the other |
365
+ | `hs-bar-series`, `hs-bar-series-top`, `hs-bar-series-plot`, `hs-bar-series-bar`, `hs-bar-series-fill`, `hs-bar-series-axis` | counts over time: the chart, its largest count, the bars, one period's bar and its gold fill, the first and last periods |
366
+ | `hs-data-table`, `hs-data-table-empty` | a table of figures flush with its tile, `data-numeric` on the cells of a column of figures; the words in place of no rows |
367
+ | `hs-world-map`, `hs-world-map-plot`, `hs-world-map-country` | a map of counts by country, its picture, one country (`data-counted` where it has a count, its strength in `--share`) |
368
+ | `hs-world-map-hi`, `hs-world-map-lo` | the stops of the gold a counted country is filled with |
369
+ | `hs-world-map-scale`, `hs-world-map-ramp` | the scale under the map: the smallest and largest counts, and the gold between them |
370
+
371
+ ## Rules
372
+
373
+ - A theme overrides token values and selects on these names; it never
374
+ depends on DOM structure between them.
375
+ - Every class takes its corner from a role token: `--r-ctl`, `--r-card`,
376
+ `--r-tile`, the small corner `--r-sm`, or a shape (`--r-pill`,
377
+ `--r-round`, `--r-icon`). [`TOKENS.md`](TOKENS.md) lists the classes of
378
+ each role. A theme reshapes corners through `--r` and the role tokens, and
379
+ selects a class only to give one family a corner of its own.
380
+ - `hs-confirm*`, `hs-grantrow` and `hs-tog` are the approval surfaces: their
381
+ presence and operability (`display`, `visibility`, `opacity`,
382
+ `pointer-events`, `position`) are pinned in `theme.css`'s `hs.guard` layer,
383
+ which no theme can reach past; their colour, type and shape are themeable.
384
+ - New UI lands with an `hs-*` name when a theme could reasonably want it.
385
+ - Removing a class, or moving what it marks, is recorded as a break.
386
+
387
+ ## Component presentation hooks
388
+
389
+ The selectors in [`src/shell.css`](src/shell.css) are the full inventory of
390
+ named shell presentation hooks. They follow these component families:
391
+
392
+ | Surface | Class families |
393
+ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
394
+ | Frame and title bar | `hs-frame-*`, `hs-window*`, `hs-titlebar*`, `hs-toolbar*` |
395
+ | Sidebar | `hs-sidebar-*`, `hs-session-*`, `hs-project-*`, `hs-app-*`, `hs-selection-*` (the selection toolbar) |
396
+ | Chat and composer | `hs-chat*`, `hs-compose*`, `hs-user-*`, `hs-assistant-*`, `hs-turn-preview-*` |
397
+ | Panels | `hs-panel-*`, `hs-browser-*`, `hs-file-*`, `hs-files-*`, `hs-document-*`, `hs-terminal-*`, `hs-changes-*`, `hs-find-*`, `hs-tab-*` |
398
+ | Settings | `hs-settings-*`, `hs-setting-*`, `hs-appearance-*`, `hs-provider-*`, `hs-nav-*`, `hs-search-*`, `hs-colour*`, `hs-theme-*`, `hs-size-*` |
399
+ | Documentation | `hs-docs-*` |
400
+ | Marketplace | `hs-market*` |
401
+ | Models | `hs-model-*`, `hs-picker-*` |
402
+ | Server dashboard | `hs-server-*` |
403
+ | Usage dashboard | `hs-dashboard-*`, `hs-bento-*`, `hs-figure*`, `hs-bar-series-*`, `hs-data-table*`, `hs-world-map-*` |
404
+ | Forms | `hs-select*`, `hs-toggle-*`, `hs-code-*` (a code block, and the one-time code's slots) |
405
+ | Overlays | `hs-menu-*`, `hs-submenu-*`, `hs-confirm-*`, `hs-sheet-*`, `hs-tooltip*` |
406
+
407
+ Selection uses `data-sel="true"`; settings buttons expose `data-strong` and
408
+ `data-danger`, menu items expose `data-disabled`, and selects expose `data-open`.
409
+ `hs-floating-tip` is a help tip placed beside its mark, `hs-range-value` the
410
+ value beside a slider, `hs-size-step` a step of a size stepper,
411
+ `hs-row-anchor` a row that positions a mark over its corner, and
412
+ `hs-push-end` an element pushed to the end of its row.
413
+ Prefer these hooks to selectors coupled to child order or inline styles.
414
+
415
+ Hooks outside the families: `hs-main-view` is an app's own surface in a tile,
416
+ `data-covered` while its view covers the tab's parts, and
417
+ `hs-empty-view` with `hs-empty-view-title` a place with nothing in it yet
418
+ (`EmptyState`), such as the view of a window with no app; `hs-view` the root
419
+ of a packaged view's document, beside `hs-shell`;
420
+ `hs-breadcrumb-separator` the mark
421
+ between two places of a trail; `hs-flex-spacer` the room that pushes what
422
+ follows it to the end of its row; `hs-navrow` a settings or documentation
423
+ nav row; `hs-info-row` a settings row with a value; `hs-sethead-action`
424
+ the control at the end of a detail page's header; `hs-help-button` and
425
+ `hs-help-mark` a help tip's mark, with and without a page behind it;
426
+ `hs-address-go`, `hs-site-button` and `hs-path-segment` the panel
427
+ browser's go mark, its site press, and one folder of the Files path;
428
+ `hs-preview-open` the press that opens a previewed file in its app;
429
+ `hs-brand-mark` a vendor's logo; `hs-signin-method` the sign-in control;
430
+ `hs-light-only` and `hs-dark-only` a picture drawn in one scheme only.
431
+
432
+ Virtual slot classes (`hs-session-slot`, `hs-subagent-slot`, `hs-project-slot`) are measured by `SidebarRowMetrics`. Give each role a
433
+ positive uniform height; put visual padding inside its slot, without external
434
+ margins. Theme row-height tokens provide the defaults.
435
+
436
+ Approval classes can be selected directly for cosmetic changes. The final
437
+ layer reserves presence and interaction; it does not pin typography or shape.
438
+
439
+ The file tree measures `hs-file-row` too, including live density edits. Glyphs
440
+ accept `className` for role-specific styling in both the SVG and masked-icon
441
+ paths; `hs-glyph` and `hs-mask` identify those two renderers. `hs-icon` is a
442
+ mark of the Remix Icon font beside its `ri-<name>` class, in the box of its
443
+ font size; the rules that reach a drawn mark reach it too.
444
+
445
+ A file's preview in a view: `hs-document-view` holds Markdown, a CSV, a
446
+ diagram or a chart drawn from the file's text, a CSV as a Markdown table;
447
+ `hs-file-partial` says that only the head of a long file shows.
448
+
449
+ Model browsing uses `hs-model-browser*`, `hs-model-header*`, `hs-model-tile`,
450
+ `hs-model-stat`, `hs-model-stats`, `hs-model-capabilities`, `hs-model-capability`
451
+ and `hs-model-card`. Selected rows use `aria-pressed="true"`.
452
+
453
+ Settings grouping: `hs-settings-card` (`SettingsCard`) owns the outer border;
454
+ `hs-settings-group` / `hs-settings-group-title` divide its content.
455
+ `hs-settings-note` and `hs-settings-actions` inset descriptions and buttons;
456
+ `hs-settings-card-header` aligns collapsible group labels with row content.
457
+ `--content-width` sets the shared composer/settings column width.
458
+ `hs-settings-management` is the separate, right-aligned management footer.
459
+ `hs-menu-position` owns popup placement. While a menu that closes when the
460
+ pointer leaves it is open, its popup root (`hs-shell` or `hs-modal`) carries
461
+ `data-hover-popup="true"`, and no `iframe` or `webview` inside takes the
462
+ pointer.
463
+ `hs-modal` is a positioned popup root with visible overflow; scrolling belongs
464
+ to its content so menus and help tips stay above the dialog without clipping.
465
+
466
+ `hs-selection-dialog`, `hs-selection-dialog-body`, `hs-selection-list`,
467
+ `hs-selection-option`, `hs-selection-icon`, `hs-selection-name`,
468
+ `hs-selection-description` and `hs-selection-error` style `SelectionDialog`.
469
+
470
+ Documentation images use `hs-docs-image` inside `hs-docs-image-link`, which
471
+ opens the original image at full size. `hs-docs-figure` groups the image and
472
+ its semantic `figcaption`. Figures inherit the current theme and maintain
473
+ their own spacing within the article.
474
+
475
+ Model management: `hs-model-library-*` styles library rows, facts, state and
476
+ hover actions; `.hs-model-hover-action` becomes visible on row hover or focus.
477
+ `hs-settings-tabs` uses `aria-selected` to paint its active glass button.
478
+ `hs-settings-breadcrumbs` and `hs-settings-crumb*` name inner-window locations.
479
+ Compact controls use `hs-settings-input`, `hs-settings-file` and
480
+ `hs-settings-textarea`. Model settings use
481
+ `hs-model-settings-*`; runtime controls use `hs-model-runtime-*`; downloads use
482
+ `hs-model-download*`, and a companion picker's label and repository field
483
+ `hs-model-companion-*`; generated image/audio previews use `hs-model-media-output`.
484
+ `hs-model-error` carries inline request failures. These selectors live in
485
+ `src/shell.css` and read the shared theme tokens.
486
+
487
+ `hs-model-runtime-row`, `hs-model-runtime-header`, `hs-model-runtime-label`,
488
+ `hs-model-runtime-status`, `hs-model-runtime-controls` and
489
+ `hs-model-runtime-control` style `ModelRuntimeRow`. Its container query stacks
490
+ the controls below a 470px card width without changing other settings layouts.
491
+
492
+ - `.hs-sidebar-action` — the full-width shared sidebar action (`SidebarAction`).
493
+ - `.hs-model-fit` — memory fit estimate with explanatory tooltip; `data-fit`
494
+ selects `full`, `partial`, `unlikely` or `unknown`; `data-variant` selects
495
+ `badge` or the noninteractive `icon` at the right of a menu row. A Server's
496
+ memory plan of a load (`ModelMemory`) is the `icon` variant with its figure,
497
+ `unknown` when the load can start now and `unlikely` when it cannot.
498
+ - `.hs-model-execution` — elapsed time and determinate/indeterminate progress.
499
+ - `.hs-server-log` — selectable bounded technical event viewer.
500
+ - `.hs-panel-start-heading` — the launcher's heading over the surfaces other apps
501
+ place in a tab ("From other apps").
502
+ - `.hs-launcher-address` — the launcher's address field, as wide as its rows.
503
+ - `.hs-panel-unavailable` — the sentence a tab shows when its app no longer places
504
+ the surface in a tab.
505
+ - `.hs-tab-dot` — the mark on a tab an agent drives.
506
+ - `.hs-panel-favicon` — a tab's own picture in the tab strip: a page's icon, or the mark a
507
+ view gave its tab.
508
+ - `.hs-browser-page-slot` — the place a browser's view keeps for its web page.
509
+ - `.hs-settings-plate` — the 52px plate beside an app's name on its settings page.
510
+ - `.hs-connector-unattached` — the words on a connector's row while no app has it attached.
511
+ - `.hs-skill-text` — a skill's own text on its settings page.
512
+ - `.hs-key-control` — a `KeyRecorder`'s controls, on the Keybindings page and an app's
513
+ hotkeys: `.hs-key-binding`, the press that holds its keys and starts the recorder
514
+ (`data-set` is `false` for keys not set), `.hs-key-record`, the recorder, and
515
+ `.hs-key-remove`, the remove mark; `.hs-key-clash` is the line that names a key another
516
+ shortcut holds.
517
+ - `.hs-provider-title` — a provider's name behind its mark; `.hs-provider-offer` and
518
+ `.hs-provider-offer-name`, a computer on the account the Providers page offers to add,
519
+ and its name.
520
+
521
+ ## Breaks
522
+
523
+ Removed or renamed classes, with what replaces them:
524
+
525
+ | Class | Now |
526
+ | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
527
+ | `hs-daemon-bar`, `hs-daemon-bar-text`, `hs-daemon-bar-action` | `hs-window-notice`, `hs-window-notice-text`, `hs-button` |
528
+ | `hs-confirm-button` | `hs-button` with `hs-confirm-cancel` or `hs-confirm-action` |
529
+ | `hs-appearance-row`, `hs-appearance-label`, `hs-appearance-value` | `hs-setrow` with `hs-range-value` |
530
+ | `hs-mono-label` | `hs-label`, or `hs-mono` for machine text |
531
+ | `hs-theme-author` | `hs-label` |
532
+ | `hs-gold-text` | `hs-link` |
533
+ | `hs-gold-glyph` | the solid kind of `hs-ladder-rung` |
534
+ | `hs-gold-action-button` | `hs-link` |
535
+ | `hs-utilbtn`, `hs-utility-button` | `hs-ladder-rung` |
536
+ | `hs-titlebar-center`, `hs-titlebar-divider`, `data-overlay` on `hs-titlebar` | `hs-rail-top`; nothing; `hs-lane` with `data-caption` |
537
+ | `hs-app-picker` | `hs-lane-crumb` |
538
+ | `hs-crow` | `hs-window-tiles` |
539
+ | `hs-sidebar-empty` | `hs-empty-view` |
540
+ | `hs-sidebar-footer`, `hs-sidebar-lift`, `data-slide` and `data-lifted` on `hs-app-block` | `hs-sidebar-rail-market`; nothing; nothing |
541
+ | `hs-artifact-card` | nothing |
542
+ | `hs-tool-row`, `hs-tool-line`, `hs-tool-details` | `hs-work-row`, `hs-work-line`, `hs-work-body` |
543
+ | `hs-work` | `hs-work-line`, `hs-work-toggle` |
544
+ | `hs-described-image` | `hs-user-tile` and `hs-user-caption` |
545
+ | `hs-chat-date` | `hs-thread-mark` |
546
+ | `hs-selection-controls` | nothing |
547
+ | `hs-chat-composer`, `hs-composer-input`, `hs-composer-toolbar`, `hs-composer-attach` | `hs-composer-main`, `hs-composer-editor`, `hs-composer-footer`, `hs-composer-tool` |
548
+ | `hs-composer-files`, `hs-composer-glimmer`, `hs-composer-disabled` | `hs-composer-shelf`; nothing; a disabled `hs-composer-send` |
549
+ | `hs-card-layer`, `hs-card-app` | `hs-composer-dock` and `hs-ask-float`; `hs-ask-app` |
550
+ | `hs-permission-card` | `hs-ask` |
551
+ | `hs-harness`, `hs-harness-layer`, `hs-harness-text`, `hs-context-meter`, `hs-context-bar` | `hs-ring` and its popover |
552
+ | `hs-side-nav`, `hs-mode-lane`, `data-mode` on `hs-window-wrap` | `hs-page`; nothing; nothing |
553
+ | `hs-settings-home`, `hs-settings-home-mark` | the lane's `hs-lane-crumb` |
554
+ | `hs-settings-crumb`, `hs-settings-crumb-link` | the lane's `hs-lane-crumb` |
555
+ | `hs-nav-footer`, `hs-nav-back`, `hs-nav-rail-back` | the tab's `hs-tab-close` |
556
+ | `hs-toolbar-button` | nothing |
557
+ | `hs-subagents`, `hs-subagent`, `hs-chat-chips`, `hs-suggestion` | `hs-drawer` |
558
+ | `hs-filechip` | `hs-shelf-file`, `hs-shelf-chip`, `hs-inline-chip` |
559
+ | `hs-live`, `hs-shimmer`, `hs-shimmer-hi` | `hs-shine` |
560
+ | `hs-model-label` | `hs-model-trigger-name` |
561
+ | `hs-app-state` | `StatusWord` |
562
+ | `hs-provider-field` | `hs-input` |
563
+ | `hs-colourway-name-input` | `hs-input` |
564
+ | `data-soon` on `hs-toggle-row` | nothing |
565
+ | `hs-market-lightbox`, `hs-market-lightbox-arrow`, `-close`, `-count` | `hs-lightbox` and its parts |
566
+ | `hs-pulse`, `hs-menu-section-sub` | nothing |
567
+ | `hs-browser-webview` | `hs-browser-page-slot` |
568
+ | `hs-browser-menu-popover`, `hs-browser-site-popover` | `hs-menu-position` (`MenuSurface`) |
569
+ | `hs-realm-slot`, `hs-realm-guest`, `hs-realm-views`, `hs-realm-view`, `hs-panel-app` | nothing: the window draws no app page in a realm |
570
+ | `hs-realm-dock`, `hs-realm-mark` | nothing |
571
+ | `hs-view-slot`, `hs-realm-chat` | nothing: no chat draws in an app's document |
572
+ | `hs-browser-pages`, `hs-browser-page` | `hs-tab-page` of a view's tab, `hs-web-page` of a web surface |
573
+ | `hs-panel-view-slot`, `hs-panel-action`, `hs-file-guest`, `hs-changed-show` | nothing: the window draws no Files, Diff, Terminal or browser tab of its own |
574
+ | `hs-app-bypass` | nothing |