Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
677956e
feat(ui): standardize accessibility, contrast, and spacing
MaxRink May 16, 2026
188a015
fix: address accessibility review follow-ups
MaxRink Jun 7, 2026
0bc1699
fix(ui): restore debug session expiry styling
MaxRink Jun 9, 2026
2165e33
fix(ui): honor debug session renew duration
MaxRink Jun 10, 2026
52f091f
fix(ci): upload frontend coverage from frontend dir
MaxRink Jun 10, 2026
7fe4be1
fix(ui): format debug session browser
MaxRink Jun 10, 2026
ecd0147
fix(ui): address accessibility review nits
MaxRink Jun 10, 2026
dc8a3c1
fix(ui): address toggle and card review nits
MaxRink Jun 10, 2026
c79afeb
fix(ui): keep theme toggles out of scale nav
MaxRink Jun 10, 2026
edf3478
fix(ui): address session card review findings
MaxRink Jun 10, 2026
86b96bb
fix(ui): remove unused debug session form actions css
MaxRink Jun 16, 2026
57be100
fix: remove duplicate dark neutral token
MaxRink Jun 19, 2026
3fd1299
fix(ui): harden debug renew duration handling
MaxRink Jun 20, 2026
394f036
fix: align theme toggle aria state
MaxRink Jun 20, 2026
594038a
fix(ui): align toggle state and icon toolbar sizing
MaxRink Jun 21, 2026
d97360b
docs(ui): align scale theme deviations
MaxRink Jun 23, 2026
d823064
fix(ui): harden high contrast and neutral mobile nav
MaxRink Jun 23, 2026
8ef91a8
fix(ui): address high contrast review nits
MaxRink Jun 23, 2026
53554cc
style(ui): satisfy frontend prettier checks
MaxRink Jun 23, 2026
e083ddb
fix(ui): use navigation semantics for mobile fallback
MaxRink Jun 23, 2026
15d13c2
fix(ui): resolve telekom mobile navigation landmarks
MaxRink Jun 23, 2026
095a494
fix(ui): close telekom accessibility gaps
MaxRink Jun 23, 2026
44bdade
fix(ui): keep not-found CTA high contrast compliant
MaxRink Jun 23, 2026
11c2e7c
fix(ui): address high contrast review feedback
MaxRink Jun 23, 2026
5431b8a
fix(ui): keep scale mobile flyout state authoritative
MaxRink Jun 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,11 @@ jobs:
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: frontend/coverage/coverage-final.json
directory: frontend
files: coverage/coverage-final.json
flags: frontend
fail_ci_if_error: false
handle_no_reports_found: true

helm-lint:
name: Helm Chart Lint
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- **Frontend: restored persisted theme selection in the app header**: The accessibility remediation now keeps both theme and high-contrast controls available, persists manual light/dark selection, preserves the forced dark canvas while high-contrast mode is enabled, and avoids duplicate modal form-control IDs in debug session cards.
- **Orphaned session cleanup now restricted to terminal states**: `markCleanupExpiredSession` previously deleted orphaned `BreakglassSession` objects in any non-Pending state, including active `Approved` and `WaitingForScheduledTime` sessions that had no `RetainedUntil` set. The predicate is now an explicit allowlist of terminal states (`Expired`, `IdleExpired`, `Rejected`, `Withdrawn`, `ApprovalTimeout`) — active sessions are never deleted by the orphan cleanup path.

### Changed
Expand Down
4 changes: 4 additions & 0 deletions frontend/SCALE_DEVIATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ and re-declares the variable on `:root`.
| Element | Scale Default | Our Override | Reason |
|---------|---------------|--------------|--------|
| `scale-button::part(variant-primary)` | `#f61488` (Scale computed) | `#e20074` (design token) | Scale's internal rendering produces a lighter #f61488 which only achieves 3.9:1 contrast against white text (fails AA). Pinning to the design-token value #e20074 yields 4.68:1 (AA compliant) while preserving the Telekom brand colour. |
| `[data-high-contrast="true"] scale-button::part(variant-primary)` | Brand colour | Black on light high-contrast, white on dark high-contrast | High-contrast mode prioritizes maximum foreground/background contrast over brand colour while preserving the primary-button affordance. |
| `[data-high-contrast="true"] scale-button[variant="primary"] > *`, plus default-primary `scale-button:not([variant]) > *` | Inherited page text colour | White on light high-contrast, black on dark high-contrast | Custom slotted labels are outside Scale's shadow part styling, so they must explicitly match the high-contrast primary-button foreground. |

---

Expand Down Expand Up @@ -154,6 +156,8 @@ propagated.
|----------|---------------|--------------|--------|
| `--spacing-y` | Scale default | `var(--space-lg)` = `16px` | Consistent internal spacing with the rest of our UI. |
| `::part(body)` layout | Block | `flex` column with `gap: var(--space-md)` | Ensures body content is evenly spaced without margin hacks. |
| `::part(header)` separator | No app-level separator | Standard border plus bottom spacing | Keeps modal titles visually connected to the body while matching card and form section boundaries. |
| `.modal-actions`, `.dialog-actions`, `.form-actions` | Per-component ad hoc alignment | Wrapped right-aligned action bar, stacked on narrow screens | Keeps action placement consistent across modals and forms and prevents button overflow on mobile. |

---

Expand Down
29 changes: 14 additions & 15 deletions frontend/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ Built on `--scl-spacing-*` primitives (2 · 4 · 8 · 12 · 16 · 24 · 32 · 40
|-------|---------|-------|-----|
| `--space-2xs` | `--scl-spacing-2` | 2 px | hairline gaps |
| `--space-xs` | `--scl-spacing-4` | 4 px | tight internal padding |
| `--space-sm` | `--scl-spacing-12` | 12 px | chip padding, small gaps |
| `--space-md` | `--scl-spacing-16` | 16 px | default internal gaps |
| `--space-lg` | `--scl-spacing-24` | 24 px | section gaps |
| `--space-xl` | `--scl-spacing-32` | 32 px | large gaps, card padding |
| `--space-2xl` | `--scl-spacing-48` | 48 px | section separation |
| `--space-3xl` | `--scl-spacing-64` | 64 px | page-level gaps |
| `--space-sm` | `--scl-spacing-8` | 8 px | chip padding, small gaps |
| `--space-md` | `--scl-spacing-12` | 12 px | default internal gaps |
| `--space-lg` | `--scl-spacing-16` | 16 px | section gaps |
| `--space-xl` | `--scl-spacing-24` | 24 px | large gaps, card padding |
| `--space-2xl` | `--scl-spacing-32` | 32 px | section separation |
| `--space-3xl` | `--scl-spacing-48` | 48 px | page-level gaps |

#### Contextual aliases

Expand Down Expand Up @@ -153,17 +153,16 @@ The neutral Scale package (`scale-components-neutral`) uses purple `#5300ff` as

## 3. Themes

Theme switching is controlled by HTML attributes and system media queries. Scale's own theme switching (`[data-mode]`) is **not** used; the app manages its own `[data-theme]` attribute.
Theme switching is controlled by HTML attributes and system media queries. The app manages its own `[data-theme]` attribute and intentionally mirrors the same value to Scale's `[data-mode]` attribute so Scale shadow-DOM tokens resolve to the matching palette.

| Theme | Activation |
|-------|-----------|
| Light (default) | `:root` (no attribute) |
| Dark | `[data-theme="dark"]` on `<html>` |
| High-contrast light | `[data-high-contrast="true"]` on `<html>` |
| High-contrast dark | `[data-high-contrast="true"][data-theme="dark"]` on `<html>` |
| Light (default) | `:root` or `[data-theme="light"][data-mode="light"]` on `<html>` |
| Dark | `[data-theme="dark"][data-mode="dark"]` on `<html>` |
| High-contrast | `[data-high-contrast="true"][data-theme="dark"][data-mode="dark"]` on `<html>` |
| Windows forced-colors | `@media (forced-colors: active)` — automatic, no JS required |

All four theme combinations have full token coverage. The forced-colors layer remaps every surface, border, chip, and accent token to CSS system color keywords (`Canvas`, `CanvasText`, `ButtonText`, `Highlight`, `GrayText`, `LinkText`) so the OS palette takes over without layout breakage.
The UI exposes light, dark, and high-contrast modes. High contrast intentionally forces a dark canvas so Scale shadow-DOM tokens and app-level text/background tokens resolve to the same contrast model. The forced-colors layer remaps every surface, border, chip, and accent token to CSS system color keywords (`Canvas`, `CanvasText`, `ButtonText`, `Highlight`, `GrayText`, `LinkText`) so the OS palette takes over without layout breakage.

---

Expand All @@ -174,15 +173,15 @@ Full details and contrast ratios are in [`SCALE_DEVIATIONS.md`](SCALE_DEVIATIONS
| # | What | Why |
|---|------|-----|
| 1 | `--telekom-color-text-and-icon-additional` overridden with `!important` | Scale default (`#595959`) fails WCAG AAA 7 : 1 on white |
| 2 | Primary button background pinned to `#e20074` | Scale's computed `#f61488` fails WCAG AA on white text |
| 2 | Primary button background pinned to `#e20074`, with black/white high-contrast overrides for both shadow-DOM parts and custom slotted labels | Scale's computed `#f61488` fails WCAG AA on white text; high-contrast buttons use maximum-contrast foreground/background pairs |
| 3 | Active nav link uses `#8e004a` (light) / `#e20074` (dark) | Scale's `#e20074` fails AA on the nav active-surface background |
| 4 | Chip/tag text colours darkened (light) or lightened (dark) | Scale functional colours target AA; we need AAA on tinted backgrounds |
| 5 | Ghost button text in dark: `#93a8ff` | Scale default fails AAA on `#1c1c1e` |
| 6 | Dropdown label forced via `!important` | Inherited opacity-based colour can fall below 7 : 1 on subtle surfaces |
| 7 | `scale-tag` variants overridden via `--background`/`--color` + `::part(base)` | Double approach needed for Scale shadow DOM version compatibility |
| 8 | `scale-card` gets explicit border + `border-radius: var(--radius-lg)` | Card boundary needed for low-vision users; shadow alone insufficient in light mode |
| 9 | `scale-button` uses `--radius-pill` | Design decision: all buttons are fully rounded |
| 10 | `scale-modal` body uses `flex` + `gap` | Consistent internal spacing without margin hacks |
| 10 | `scale-modal` body/header spacing and modal/form action bars are standardized | Consistent internal spacing and action alignment without margin hacks |
| 11 | Forced-colors layer | Scale does not handle `forced-colors` explicitly |
| 12 | 44 × 44 px touch targets in `[data-high-contrast]` | WCAG SC 2.5.5 AAA; Scale does not enforce this |
| 13 | Neutral/OSS theme keeps purple primary — intentionally unbranded | N/A |
Expand Down Expand Up @@ -529,7 +528,7 @@ All `border: 1px dashed` styles in base.css and EmptyState.vue updated to `borde

#### Neutral header fallback

CSS `:not(:defined)` rules provide a fully functional header, nav, and app shell layout when Scale Telekom components aren't registered (neutral/OSS package). Includes sticky positioning, primary-colour accent border, dark mode support, and mobile responsiveness.
CSS `:not(:defined)` rules provide a functional header, app shell layout, and desktop/mobile navigation when Scale Telekom components aren't registered (neutral/OSS package). Includes sticky positioning, primary-colour accent border, dark mode support, a constrained mobile fallback menu, and overflow protection below the mobile breakpoint.

#### Decorative gradient removed

Expand Down
Loading
Loading