--- name: ping-mee Portal description: Calm, utility-style self-service portal for a homelab, in the spirit of the Microsoft 365 admin center. Fluent 2 web components; this DESIGN.md specifies the brand-layer delta and the portal's own components. status: final updated: 2026-10-15 sources: - _bmad-output/prds/prd-ping-mee-self-service-platform-2026-10-15/prd.md - _bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md colors: # Fluent 2 neutrals are inherited. Only the brand and the portal's semantic colours are listed. # Brand is portal-wide and Admin-changeable; this is the default (Fluent 2 default brand blue). [ASSUMPTION: verify against @fluentui/web-components 3.x at scaffold] brand: '#0F6CBD' on-brand: '#FFFFFF' brand-dark: '#479EF5' on-brand-dark: '#0A0A0A' top-bar-dark: '#0F2A43' background: '#FAFAFA' surface: '#FFFFFF' nav-surface: '#F5F5F5' text: '#242424' text-secondary: '#616161' line: '#E0E0E0' background-dark: '#1F1F1F' surface-dark: '#292929' nav-surface-dark: '#242424' text-dark: '#FFFFFF' text-secondary-dark: '#C8C8C8' line-dark: '#3D3D3D' severity-info: '#0F6CBD' severity-warning: '#F7630C' severity-outage: '#B10E1C' severity-outage-dark: '#FF99A4' success: '#107C10' success-dark: '#6CCB5F' pending-surface: '#FFF4CE' pending-text: '#5C4400' pending-surface-dark: '#4A3B00' pending-text-dark: '#FFE9A8' typography: # System font stack only: the security policy forbids external fonts. family: fontFamily: '"Segoe UI Variable", "Segoe UI", system-ui, sans-serif' page-title: fontSize: 24px fontWeight: '600' lineHeight: '1.25' page-title-phone: fontSize: 20px fontWeight: '600' lineHeight: '1.25' card-title: fontSize: 16px fontWeight: '600' body: fontSize: 14px fontWeight: '400' lineHeight: '1.45' label: fontSize: 14px fontWeight: '600' small: fontSize: 13px hint: fontSize: 12px mono-editor: fontFamily: 'Consolas, monospace' fontSize: 13px rounded: sm: 4px md: 6px lg: 8px pill: 10px full: 9999px spacing: card-padding: 16px 18px card-gap: 14px page-padding: 24px 28px page-padding-phone: 16px nav-width: 220px top-bar-height: 48px touch-target-min: 44px components: top-bar: background: '{colors.brand}' foreground: '{colors.on-brand}' height: '{spacing.top-bar-height}' top-bar-dark: background: '{colors.top-bar-dark}' foreground: '{colors.text-dark}' nav-item: foreground: '{colors.text}' radius: '{rounded.sm}' nav-item-active: background: '{colors.surface}' border: 'inset 3px left {colors.brand}' fontWeight: '600' card: background: '{colors.surface}' border: '1px solid {colors.line}' radius: '{rounded.lg}' padding: '{spacing.card-padding}' banner: radius: '{rounded.md}' border: '1px solid, left 5px, colour by severity' button-primary: background: '{colors.brand}' foreground: '{colors.on-brand}' radius: '{rounded.sm}' button-secondary: background: 'transparent' foreground: '{colors.text}' border: '1px solid' radius: '{rounded.sm}' chip-pending: background: '{colors.pending-surface}' foreground: '{colors.pending-text}' radius: '{rounded.pill}' input: border: '1px solid, bottom 2px' radius: '{rounded.sm}' avatar: radius: '{rounded.full}' --- ## Brand & Style A calm utility. The portal should feel like the Microsoft 365 admin center's settings pages: clean, plain and confident, one clear task per page, with nothing decorative. The people who use it are not technical, so the design earns trust through restraint and legibility, not through personality. It follows Fluent 2 so the controls behave the way these users already know from Microsoft products. Light and dark are equal citizens. The portal follows the system theme by default and the user can override it per device. The accent colour is portal-wide and set by the Admin. Mock-ups: `mockups/key-dashboard.html`, `mockups/key-password.html`, `mockups/key-picture-pending.html`, `mockups/key-announcement-editor.html`, `mockups/key-admin-appearance.html`, `mockups/key-admin-status.html`, `mockups/key-admin-audit.html`. The spine wins on conflict. ## Colors - **`{colors.brand}`** is the one accent: top bar, primary buttons, active-nav marker and focus emphasis. It is Admin-changeable (FR-22). In dark mode the lighter `{colors.brand-dark}` is used with `{colors.on-brand-dark}` text. - **Neutrals** (`background`, `surface`, `nav-surface`, `text`, `text-secondary`, `line`) carry almost everything; the dark variants have the `-dark` suffix. Cards sit on `{colors.surface}` above `{colors.background}`. - **Severity colours** colour only the left edge and icon of an announcement banner: `{colors.severity-info}`, `{colors.severity-warning}`, `{colors.severity-outage}`. Colour is never the only signal; each severity also has an icon and a word. - **Pending** uses `{colors.pending-surface}` and `{colors.pending-text}` for the "being updated" chip and nothing else. - **Success** (`{colors.success}`) marks healthy job status and saved confirmations. - **Contrast.** All text and control pairs meet WCAG 2.1 AA in both themes. The Admin colour check (EXPERIENCE.md, Admin Appearance) computes contrast for the chosen brand colour against `{colors.on-brand}` (light) and `{colors.on-brand-dark}` (dark) and warns when below 4.5:1. ## Typography One family, the system stack `{typography.family}`, because the security policy allows no external fonts. A small ramp: `{typography.page-title}` for the page heading (`{typography.page-title-phone}` on phones), `{typography.card-title}` for cards, `{typography.body}` for text, `{typography.label}` for field labels, `{typography.small}` and `{typography.hint}` for explanations. The announcement editor's source view, if shown, uses `{typography.mono-editor}`. Sentence case everywhere; no all-caps except the small group headings in the menu. ## Layout & Spacing Left menu (`{spacing.nav-width}`) plus a content area on desktop; the menu collapses behind a menu button on phones. Content is left-aligned in cards on a single column; two columns of cards only on the dashboard and the status page, stacked on phones. Page padding is `{spacing.page-padding}` (`{spacing.page-padding-phone}` on phones); cards are separated by `{spacing.card-gap}`. Lines of explanatory text stay below about 640 px wide. Touch targets are at least `{spacing.touch-target-min}` on phones. On phones, label/value rows stack and long values wrap, so nothing is cut off at the right edge. ## Elevation & Depth Flat. Depth comes from a 1 px `{colors.line}` border and the surface/background step, not from shadows. The only shadows are on the profile menu (a popover) and on dialogs. ## Shapes Small, even radii: `{rounded.sm}` for buttons and inputs, `{rounded.md}` for banners, `{rounded.lg}` for cards, `{rounded.pill}` for chips, `{rounded.full}` for avatars. ## Components | Component | Visual spec | |---|---| | Top bar | `{components.top-bar}`: portal name at left, profile picture at right (opens the profile menu). On phones a menu button replaces the left menu. Dark mode uses `{components.top-bar-dark}`. | | Left menu | Items `{components.nav-item}`; active item `{components.nav-item-active}`. Group headings "Veröffentlichen" and "Administration" appear only for Publishers and Admins, in small upper-case text. | | Card | `{components.card}`; title `{typography.card-title}`. | | Announcement banner | `{components.banner}`: left edge in the severity colour, icon, bold title, one or two lines of text. At most the active announcements, newest first. | | Pending chip | `{components.chip-pending}` with the text "Wird aktualisiert". | | Buttons | Primary `{components.button-primary}`; secondary `{components.button-secondary}`. One primary per card. | | Fields | `{components.input}`; label above, hint below in `{typography.hint}`; error text below in the outage colour with an icon. | | Profile menu | Popover from the avatar: name and username, theme (Hell, Dunkel, System), language (Deutsch, English), address form (Sie, Du; German only), sign-out. | | Rich text editor | Toolbar above a text area that shows the result: bold, italic, heading, list, link. Same border as inputs. | | Tables | Compact rows with `{colors.line}` separators, used for the audit log, job status and failed mail. | | Filter chips | Pill buttons; the selected chip uses `{colors.brand}`. | | Colour field (Admin) | Swatch, hex field, contrast table (light and dark), warning box. | ## Do's and Don'ts - **Do** keep one primary action per card and say what it will do and what happens next. - **Do** show state in words as well as colour. - **Do** keep pages short; split a long page before adding scrolling sections. - **Don't** add decoration, illustrations or animation beyond Fluent's own. - **Don't** use more than the one brand accent. - **Don't** hide a state in colour alone, or in hover. - **Don't** load fonts, icons or scripts from the network.