InstrumentBar
The map's tools, in one place, with names. Search, layers, framing, sky conditions, night mode and the guide — a vertical rail under the nav pill on a desktop, a row under the pointing readout on a phone.
Before it, five of the map's ten capabilities were unlabelled glyphs in three different corners, and two of them opened panels in a corner other than the one the button was in. Every button here names itself on hover and on focus, takes the layout budget's full 44px target on every pointer, and opens its panel directly beneath itself.
Hover or tab through the buttons to see the labels. There are no tool panels on this page, so pressing one only lights the button; night mode is live and will turn this documentation red.
Icon weight is the state
Straight from src/design/icons/registry.ts:
regular is a control at rest, solid is the
one that is currently on. Both weights are inlined at build time, so the change is a
display flip and never a fetch — and it survives night mode,
where every tone collapses to ember and colour alone stops distinguishing anything.
One naming recipe, two rails
The name chip is primitives/_internal/RailLabel.astro, shared with
FloatingNav 8px above: two rails of icons
that look like one surface have to answer a hover the same way. It is a permanently-rendered span, so
it is the button's accessible name and a pointer user and a screen-reader user are told the
same word; it fades on opacity alone, because display:none would take that
name back out of the accessibility tree. No script, no per-button id, nothing to re-bind after a
navigation.
Placement follows the rail, not a breakpoint copied into the primitive: the bar declares
--rail-axis beside its own flex-direction, and a
style container query puts the chip beside a column and beneath a row — which is why this inline,
always-horizontal copy drops its labels downward even on a wide screen. A column rail is pinned to the
left edge, so its chips open rightward and cannot leave the viewport. On a coarse pointer they never
appear at all: a finger has no hover, and the label would stick after a tap.
One tool at a time
The bar owns the left column's single rule: at most one panel open. Anything on the page can ask, and only the bar answers.
import { openTool, closeTool } from '../design/compositions/tool-bus';
openTool('layers'); // window 'tool:open', CustomEvent<{ id: string }>
closeTool('layers'); // window 'tool:close', CustomEvent<{ id: string }> A panel declares itself with data-tool-id — which
<ToolPanel> does for it — and the bar hides and un-inerts it.
When opening one closes another, the bar dispatches tool:close for
the one it displaced, so a panel with side effects on the sky sees one event stream and
cannot be left drawing over a panel that is no longer there. It also writes
data-tool on <html>, which is how the
map knows to yield the compass on a narrow screen and how Escape knows the key belongs
to a panel rather than to the selection behind it.
Night mode is not a tool
It is a mode: a switch in the same rail with the same weight language, and no part in the exclusivity. Opening the layers panel must not turn red light off on someone standing in a field.
Shortcuts
F framing, ? the guide,
Esc closes whichever tool is open. ⌘K belongs
to SearchBar, because it has to work
while a field elsewhere on the page holds focus.