PowerXXXX layout and style guide
Status: the design system of the PowerXXXX products. It is implemented in PowerSolver (wizard, Results, Compare); the other products adopt it with the checklist in §11. Every value below is the one in the code: powersolver-wizard/css/theme.css (tokens and the shared components of §8: forms, buttons, cards, tables, alerts, badges, tabs, dialogs — every page loads it, so no page can miss the theme), js/theme.js (theme choice), index.html (shell and logo). Page-specific files only add layout.
Rule zero: a component never contains a raw colour, font or size. It uses a token (var(--ps-…)). A new need is a new token in theme.css, defined for both themes.
1. Themes
Two dark themes with the same layout, components and behaviour; only the palette changes. The user picks one in the sidebar; the choice applies to every page at once and never changes data or settings.
| Theme A — Midnight + Violet | Theme B — Charcoal + Amber | |
|---|---|---|
Id (<html data-theme>) | violet (default) | amber |
| Character | premium, calm | professional, warm |
| Logo | violet mark (§4) | amber mark (§4) |
1.1 Palettes (from the reference design)
| Role | Violet | Amber |
|---|---|---|
| Background | #0B0D14 | #111111 |
| Surface (cards, panels) | #151826 | #1B1B1B |
| Selected surface / deep tint | #2A2540 | #2A2A2A (selected: #2E2617) |
| Accent | #8B6CFF | #F2B84B |
| Soft accent (light tint, links) | #C7B8FF | #F9E3B2 |
| Text | #F5F6FA | #F7F7F5 |
2. Colour tokens
Use the semantic token, never the palette value.
2.1 Surfaces, borders, text
| Token | Use | Violet | Amber |
|---|---|---|---|
--ps-bg | page background, inputs, sidebar | #0B0D14 | #111111 |
--ps-surface | cards, panels, dialogs | #151826 | #1B1B1B |
--ps-surface-raised | hover, table heads, chips | #1C2032 | #222222 |
--ps-surface-selected | selected card, active nav item | #2A2540 | #2E2617 |
--ps-border | dividers, card edges | #272B3E | #2A2A2A |
--ps-border-strong | emphasised edges, outline buttons | #3A3F57 | #3D3D3D |
--ps-border-input | edges of form fields (3:1) | #666C8F | #707070 |
--ps-text | main text, headings | #F5F6FA | #F7F7F5 |
--ps-text-secondary | labels, secondary text | #C9CCDA | #D2D2CD |
--ps-text-muted | hints, captions, placeholders | #9EA3B8 | #A5A59F |
--ps-glow | soft accent light at the top of the page | violet 10 % | amber 7 % |
Page background: background: var(--ps-glow), var(--ps-bg);
2.2 Accent and states
| Token | Use | Violet | Amber |
|---|---|---|---|
--ps-accent | primary buttons, active step, selected border, focus | #8B6CFF | #F2B84B |
--ps-accent-hover | hover of accent elements | #9D84FF | #F5C66A |
--ps-accent-active | pressed | #7A5AF0 | #E0A332 |
--ps-accent-soft | links, code, light accent text | #C7B8FF | #F9E3B2 |
--ps-accent-text | accent-coloured text or icons (4.5:1) | #9D84FF | #F2B84B |
--ps-on-accent | text on an accent background | #0B0D14 | #111111 |
--ps-accent-rgb | for tints: rgba(var(--ps-accent-rgb), a) | 139,108,255 | 242,184,75 |
--ps-accent-subtle | 12 % tint: hover rows, info alerts | ||
--ps-accent-muted | 24 % tint: chips, badges | ||
--ps-focus-ring | box-shadow of focused fields and cards | 3 px, 35 % accent | |
--ps-disabled-bg / --ps-disabled-text / --ps-disabled-opacity | disabled controls | raised surface / muted text / 0.55 |
Text on the accent is dark (--ps-on-accent) in both themes, never white.
2.3 Status colours
The same in both themes, except warning in Amber (the yellow would read as the accent).
| Token | Meaning | Violet | Amber |
|---|---|---|---|
--ps-success (-rgb) | valid, done, "ready to use" | #34D399 | #34D399 |
--ps-warning (-rgb) | "worth a look" | #FBBF24 | #FB923C |
--ps-danger (-rgb) | blocking, broken rule, delete | #F87171 | #F87171 |
--ps-info (-rgb) | neutral information | #7DD3FC | #7DD3FC |
Alerts and badges use a 12 % tint of the status colour as background, a 40 % edge, normal text, and the status colour for the icon: background: rgba(var(--ps-danger-rgb), 0.12).
2.4 Data colours
Categories in plans and charts (16 hues) and priorities keep a fixed palette, independent of the theme: they encode data. Use them only for data, never for interface elements.
3. Typography
| Token | Value |
|---|---|
--ps-font | Plus Jakarta Sans, then system sans-serif |
--ps-font-mono | system monospace (code, JSON, scores) |
--ps-weight-regular / -medium / -semibold / -bold | 400 / 500 / 600 / 700 |
--ps-text-xs / -sm / -md / -lg / -xl / -2xl | 0.75 / 0.875 / 1 / 1.25 / 1.75 / 2.25 rem |
Load: https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap
| Element | Size | Weight |
|---|---|---|
| Page title | --ps-text-xl | Bold |
Section heading (h5/h6) | 1–1.1 rem | SemiBold |
| Body, forms | --ps-text-sm–--ps-text-md | Regular |
| Labels, buttons, nav | 0.85–0.9 rem | Medium (buttons on accent: SemiBold) |
| Captions, section titles in the sidebar | --ps-text-xs, UPPERCASE, letter-spacing 0.8 px | Medium |
4. Logo
Each theme has its own mark (from the reference design), next to the product name in Plus Jakarta Sans SemiBold.
| Theme | Mark | File |
|---|---|---|
| Violet | isometric "P": four slanted faces (top band, right side, middle band, stem) separated by thin gaps | logo-violet.svg |
| Amber | faceted "P": flat top bar, cut corners, slanted lower bar, stem | logo-amber.svg |
- Colour:
--ps-logo-main(the theme accent), on the dark background only. No gradient, no outline, no shadow. - Proportions: view box 29 × 39; never stretch. Sizes: 27 × 36 px in the sidebar, 50 × 67 px on the sign-in page, favicon from the same file.
- Clear space: at least half the mark's width on every side.
- In a page: one inline
<symbol>per mark, both referenced, the theme shows one:<svg class="ps-logo"><use class="ps-logo--violet" href="#ps-logo-violet"/><use class="ps-logo--amber" href="#ps-logo-amber"/></svg> - Other PowerXXXX products use the same marks and principles (faceted letter, accent colour, name beside it); their own letter shape is a branding decision still to take.
5. Spacing, radii, shadows, motion
| Token | Value | Use |
|---|---|---|
--ps-space-1 … -6 | 0.25 / 0.5 / 0.75 / 1 / 1.5 / 2 rem | 4 px grid: gaps, paddings |
--ps-radius-sm | 6 px | inputs, small buttons, badges |
--ps-radius-md | 10 px | buttons, nav items, alerts |
--ps-radius-lg | 14 px | cards, dialogs |
--ps-radius-pill | 999 px | pills, progress bars, step underline |
--ps-shadow-sm / -md / -lg | dark, neutral | raised controls / sticky bars / dialogs |
--ps-transition | 150 ms ease | colour and border changes only (no movement) |
prefers-reduced-motion: reduce turns transitions and animations off.
6. Icons
Bootstrap Icons 1.11, outline style, in the text colour (--ps-text-secondary; --ps-text when selected; --ps-accent-text for an active navigation item). No coloured or filled icons except status icons in alerts. Sizes: 1 rem in buttons and navigation, 1.75 rem on choice cards.
7. Application layout
┌──────────────┬───────────────────────────────────────────────┐
│ Sidebar │ Header: page title context │
│ 280 px ├───────────────────────────────────────────────┤
│ logo + name │ Step bar (wizards) │
│ navigation ├───────────────────────────────────────────────┤
│ file actions │ Content (cards, forms, tables) │
│ │ │
│ resources ├───────────────────────────────────────────────┤
│ theme switch │ Footer: Previous · Next (sticky) │
│ language │ │
│ user │ │
└──────────────┴───────────────────────────────────────────────┘
- Sidebar:
--ps-bg, right border--ps-border, padding 1.5 rem, gap 1 rem. Order from top: brand, navigation, file actions, resources, then at the bottom theme switch, language, user. No run button: a run starts from the wizard's last step. Below 768 px it shrinks to 60 px: icons only, labels hidden visually (still read by screen readers). - Content: the pages of the product (an
<iframe>in PowerSolver); header and footer--ps-bgwith a--ps-borderline; the footer is sticky with--ps-shadow-md. - Grids: Bootstrap 5.3 columns; choice cards 4 per row (
col-lg-3), 3 (col-md-4), 1 on phones. - No horizontal scroll at any width down to 375 px.
8. Components
8.1 Buttons
| Kind | Rest | Hover | Pressed | Disabled |
|---|---|---|---|---|
Primary (.btn-primary) | accent, dark text | --ps-accent-hover | --ps-accent-active | raised surface, muted text |
| Outline primary | soft-accent text, 60 % accent edge | filled accent | accent-active | muted |
Secondary (.btn-outline-secondary) | secondary text, strong border | raised surface | selected surface | muted |
| Danger outline | danger text and 50 % edge | filled danger | ||
Success (.btn-success, e.g. Plan it) | success, dark text |
Radius --ps-radius-md, weight Medium (primary SemiBold). One primary button per area.
8.2 Navigation (sidebar)
| State | Look |
|---|---|
| Rest | transparent, --ps-text-secondary |
| Hover | --ps-surface, --ps-text |
| Active page | --ps-surface-selected, --ps-border-strong edge, --ps-text, icon --ps-accent-text |
| Destructive (Reset) | danger text, 30 % danger edge; hover 10 % danger tint |
8.3 Step bar (wizards)
Numbered circles 28 px, label beside. Upcoming: transparent circle, --ps-border-strong edge, muted label. Current: filled accent circle with dark number, label --ps-text SemiBold, 3 px accent underline. Done: filled accent circle like the current one (no underline). Unavailable: 55 % opacity. Below 768 px only the circles show.
8.4 Choice cards (e.g. type of plan)
Surface, 1 px --ps-border-strong edge, radius --ps-radius-lg, outline icon top-left then the label, left-aligned. Hover: 60 % accent edge, raised surface. Selected: --ps-surface-selected, accent edge, ✓ in the top-right corner in accent. Focusable (tabindex="0"), Enter or Space selects, aria-pressed says which is selected.
8.5 Cards and panels
--ps-surface, --ps-border, radius --ps-radius-lg; header --ps-surface-raised. Figure cards: label in muted text, number 2 rem Bold, caption muted.
8.6 Forms
Fields: --ps-bg background, --ps-border-input edge, radius --ps-radius-sm, text --ps-text, placeholder muted. Focus: accent edge + --ps-focus-ring. Error: danger edge and message in danger. Disabled: disabled tokens. Labels Medium in --ps-text-secondary. Checkboxes: accent when checked.
8.7 Alerts, badges, verdicts
Tinted background of the status colour (§2.3), radius --ps-radius-md, text in --ps-text. Badges: solid status colour with dark text, or accent tint with soft-accent text. A verdict pill ("Ready to use") is a success-tinted pill with a dot.
8.8 Tables, tabs, lists, menus
Tables transparent, --ps-border rows, hover --ps-accent-subtle, head --ps-surface-raised. Tabs: secondary text, active tab --ps-text with an accent underline. Dropdowns and list groups: raised surface, selected = selected surface.
8.9 Dialogs, progress, notifications
Dialogs: --ps-surface, strong edge, radius --ps-radius-lg, --ps-shadow-lg, backdrop black 60 %. Progress bars: raised track, accent bar, pill radius. Spinners: accent. Banners after an import: success tint with Import again as a small outline button.
8.10 Theme switch
A two-option radio group in the sidebar ("Theme: ● Violet ● Amber"), the selected option on the selected surface. Arrow keys move the choice; only the selected option is in the Tab order. Mounted with PSTheme.mount(container).
9. Accessibility (WCAG 2.1 AA)
| Check | Required | Both themes |
|---|---|---|
| Text on any surface (text, secondary, muted) | 4.5:1 | ≥ 5.8:1 |
Accent-coloured text (--ps-accent-text) | 4.5:1 | ≥ 4.9:1 |
| Dark text on accent buttons | 4.5:1 | ≥ 5.2:1 |
Form field edges (--ps-border-input) | 3:1 | ≥ 3.1:1 |
| Focus | visible | 2 px accent outline or focus ring |
Every control is reachable with the keyboard; hidden labels are hidden visually (clip), never with display: none when they name a control; icons that carry no meaning have aria-hidden="true".
10. Theme mechanics
<html data-theme="violet|amber">, set byjs/theme.jsloaded in<head>before the first paint.- The choice is kept per browser under
localStorage["ppt_theme"](likeppt_language); pages in iframes follow at once, other tabs through thestorageevent. - API:
PSTheme.get(),PSTheme.set('amber'),PSTheme.apply(theme),PSTheme.mount(container). - Canvas charts cannot read CSS: read a token at draw time,
getComputedStyle(document.documentElement).getPropertyValue('--ps-text-muted'). - Files shared with a product that has not adopted the themes write
var(--ps-x, <old colour>)orcolor-mix(in srgb, var(--ps-x, <old colour>) 20%, transparent): themed here, unchanged there. - Theme switch labels are translated (
theme.label,theme.violet,theme.amberin each locale).
11. Adopting the system in another PowerXXXX product
- Copy
css/theme.cssandjs/theme.jsunchanged; load the font, thentheme.cssafter the product's own CSS, andtheme.jsin<head>. - Add the logo symbols and the brand block (§4) to the shell; product name next to the mark.
- Map the product's existing colour variables onto the
--ps-*tokens as aliases (astheme.cssdoes for--wizard-*), so existing styles follow at once. - Replace the remaining raw colours component by component (the token tables above); gradients become the solid accent.
- Mount the theme switch above the language switcher; add the three
theme.*texts to every locale. - Check both themes on every screen, the contrast table (§9), keyboard use and a 375 px width.