Status: Accepted. Chosen on 11 October 2026 from six explored directions.
The SongCollect interface is a cool, bright workbench with the crisp shapes of a printed hymnal. Colours, backgrounds and type come from the Workbench direction: a white and grey-blue canvas, a vivid blue accent and pastel tints for grouping. Shapes come from the Hymnal direction: small square corners, double rules and hard offset shadows. The result should feel calm and clear, with a little warmth and character.
The application styles live in src/web/style.css. All values below are CSS custom properties defined on :root; use the tokens, never raw hex values, in component rules.
The documentation site (docs/sass/site.scss) follows the same style: the same palette, sans-serif type, 2px corners, double rule above page headings, a blue left bar on the active navigation item and a solid blue primary link with the hard offset shadow.
Principlesπ
- Colour carries meaning. Blue means action and selection. Use
--accentfor fills and large shapes, and--accent-textfor any blue text. Green means complete or saved. Amber means needs attention. Red means a problem. Never use a colour only decoratively when it means something elsewhere. - Square, not sharp. Every control, card, badge and input has the same 2px corner. Round shapes are reserved for avatars of people and the logo mark.
- Depth is flat and hard. Prefer a 1px border or a hard offset shadow over a soft blurred one. Only the selected item and the primary button lift off the page.
- Text first. The interface exists to find and read song information. Decoration never reduces contrast or crowds the content.
Colourπ
Neutralsπ
| Token | Value | Use |
|---|---|---|
--bg | #ffffff | Page and content background |
--panel | #f5f7fa | Detail panel, inputs at rest, subtle fills |
--line | #e4e7eb | Borders and dividers |
--ink | #1f2933 | Body text and headings |
--ink-soft | #323f4b | Secondary headings and list text |
--muted | #616e7c | Captions, labels, helper text (4.9:1 on white) |
Accent and statesπ
| Token | Value | Soft tint (-soft) | Use |
|---|---|---|---|
--accent | #1e6fe8 | #e8f1fd | Primary button, links, focus, selection |
--accent-text | #1a5fcf | n/a | Blue text and borders on white, --panel and --accent-soft (5.1:1 or better) |
--accent-dark | #0d3f91 | n/a | Button hover and offset shadow |
--success | #0b6e55 | #dff5ee | Saved, complete, green badges |
--warning | #8a5400 | #fdf1d3 | Needs review, amber badges |
--danger | #c62832 | #fde4e4 | Errors, destructive actions |
Pastel tints (--accent-soft, --success-soft, --warning-soft) are used for avatar backgrounds, badges and message bars. Text on a tint always uses the matching strong colour above; each pair meets WCAG AA (4.5:1).
Avatar tonesπ
Song avatars cycle through three tones so rows are easy to tell apart: blue, green and amber (soft background, strong letter). The tone is derived from the position in the list, so it carries no meaning and must not be explained or relied upon.
Typographyπ
- UI and body: Inter, falling back to the system sans-serif. 14px body, 1.5 line height.
- Headings: the same sans-serif, weight 500, tight tracking (
-0.02em). Page titleclamp(30px, 3.4vw, 44px), panel title 24px. - Section labels: 11px uppercase,
0.1emtracking, weight 600,--muted. Used for list headers and detail field names. - No decorative serif. The earlier Georgia headings are retired; the hymnal character now comes from shape, not type.
Shape and elevationπ
| Element | Value | Use |
|---|---|---|
Corner (--radius) | 2px | Buttons, inputs, badges, cards, panels |
| Double rule | 3px double var(--accent) | Top rule on the page heading block |
| Lift | 3px 3px 0 var(--accent-dark) | Primary button; selected card in mockups |
The avatar and logo mark are the only circles.
Componentsπ
Primary buttonπ
Solid --accent fill, white text, 2px radius, minimum height 44px, hard 3px 3px 0 --accent-dark shadow. On hover it moves 1px toward the shadow; on press the shadow collapses. Disabled buttons drop to 45% opacity and lose the shadow. One primary button per view.
Quiet buttonπ
Transparent with --accent text. Hover fills --accent-soft. Used for secondary and navigational actions (Cancel, Retry, Sign out, pagination).
Inputsπ
--bg fill, 1px --line border, 2px radius, minimum 44px tall. The focus ring is the global one below, plus an --accent border.
Song rowπ
Avatar (initial letter, 34px circle, tone as above), title in weight 500 with authors in --muted below, and songbook references on the right as badges. Hover fills --panel. The selected row has an --accent-soft fill and a 3px --accent bar on its left edge.
Badgeπ
Inline, 12px, 2px radius, 1px border. Songbook references and themes use the outlined blue badge; themes cycle to green and amber for variety only when more than one is shown. Badges contain text, never icons alone. Long text wraps inside the badge, which never exceeds its container.
Detail panelπ
--panel background with a 1px left border. Field names are section labels; values are body text. Themes and songbooks render as badges.
Tabsπ
Used for the lyric versions of a song. A role="tablist" row with a 1px --line rule beneath; tabs are text buttons with a 3px bottom bar. The active tab has an --accent bar and --accent-text; arrow keys, Home and End move between tabs. Below 760px the row scrolls horizontally instead of wrapping. A single version shows its name as a heading instead of tabs.
Lyricsπ
Each section shows its name as a section label, then its lines as 14px body text with preserved line breaks, at most 60ch wide. Sections are 20px apart with a 1px --line divider. The singing sequence is an ordered list of outlined blue badges joined by a muted β that screen readers skip; a repeated section is a repeated badge. The revision line uses the muted 12px style.
In the editor, each section is a card: --bg fill, 1px --line border, 2px radius, 12px padding. Its header holds the name input and quiet β, β and Remove buttons with descriptive labels; the card being edited shows a 3px --accent left bar. Sequence entries are chips in the outlined blue badge colours with quiet β, β and β buttons; reordering never needs drag and drop. Field problems appear as a danger-soft message below the field, linked with aria-describedby.
A search result matched through lyrics shows a green outlined badge, Lyrics: Deutsch, naming each matching language once.
Messagesπ
A full-width bar with a 2px radius, soft fill and strong text. Saved notices use the success pair, errors the danger pair. Messages keep their role (status or alert).
Header and footerπ
The header carries the logo mark (an outlined circle with a note), the product name in weight 500 and the audience label. Both bars use a 1px --line rule, never a shadow.
Accessibilityπ
- The focus ring is a 3px
--accentoutline with 2px offset on every interactive element, visible against every surface. - Colour is never the only signal: states also change text, the row bar or an icon.
- Motion is limited to 150ms colour and position transitions and is disabled under
prefers-reduced-motion. - Touch targets are at least 44px tall.
Responsive behaviourπ
Below 760px the workspace stacks: the collection first, then the detail panel. The detail panel is hidden until a song is selected. Paddings use 6vw; badges wrap.
Not part of this releaseπ
The planned final layout is specified in the target UI. The explorations also showed a left navigation tree, saved views, completeness tiles and a visibility toggle. These need product features that do not exist yet. They are not implemented; when the features arrive, reuse the components above rather than inventing new ones.
Reference mockupsπ
The chosen direction is 6-workbench-shapes1-colors6 in the design exploration (OUTBOX/songcollect-ui/mockups). The final implementation intentionally simplifies it to the screens the app has today.