Skip to content

Commit af8ec12

Browse files
committed
fix(frontend): WCAG AAA contrast fixes, token consistency, and a11y test improvements
- Fix AAA contrast failures across light/dark/high-contrast modes: - Override Scale's hsla text color with solid !important values - Darken primary button, nav links, chip/tag text for 7:1 ratio - Add dark mode overrides for ghost buttons and active nav links - Fix reason panel label colors on colored backgrounds - Tokenize hardcoded border-radius (999px → var(--radius-pill)) across ActionButton, ApprovalModalContent, BreakglassCard, NotFoundView, SessionBrowser, and base.css global scale-button rules - Tokenize hardcoded spacing in SessionErrorView (px/rem → design tokens) - Tokenize TimelineGrid highlight radius (8px → var(--radius-md)) - Add missing .tag-icon CSS class in PendingApprovalsView - Improve a11y.spec.ts: use .disableRules() for Scale shadow DOM issues instead of unreliable element exclusions
1 parent 4b1f1c5 commit af8ec12

File tree

12 files changed

+112
-43
lines changed

12 files changed

+112
-43
lines changed

frontend/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/assets/base.css

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
background-color: var(--surface-primary);
2121
color-scheme: light;
2222

23+
/* AAA-compliant overrides for Telekom tokens that miss 7:1 on subtle backgrounds.
24+
* Scale sets this to hsla(0,0%,0%,0.65) ≈ #595959 on :root in its own stylesheet,
25+
* which loads after ours. !important is required to ensure our solid override wins. */
26+
--telekom-color-text-and-icon-additional: #4a4a4a !important;
27+
2328
/* ============================================
2429
* SEMANTIC SPACING ALIASES
2530
* Maps Scale spacing tokens to semantic names
@@ -78,27 +83,30 @@
7883
--accent-info: var(--telekom-color-functional-informational-standard, #2238df);
7984
--accent-critical: var(--telekom-color-functional-danger-standard, #e82010);
8085

81-
/* Chip/Tag colors - using Telekom additional colors */
86+
/* Chip/Tag colors - using Telekom-derived colors
87+
* Original Telekom magenta (#e20074) fails WCAG AAA (3.89:1 on light bg).
88+
* --chip-text uses a darkened magenta that keeps the brand hue but meets
89+
* the 7:1 AAA contrast requirement on the tinted chip background. */
8290
--chip-bg: color-mix(in srgb, var(--telekom-color-primary-standard) 7%, transparent);
8391
--chip-border: color-mix(in srgb, var(--telekom-color-primary-standard) 15%, transparent);
84-
--chip-text: var(--telekom-color-text-and-icon-primary-standard);
92+
--chip-text: #8e004a;
8593

86-
/* Semantic tone chips using Telekom functional subtle colors */
94+
/* Semantic tone chips — text colors darkened from Telekom defaults to meet AAA 7:1 */
8795
--tone-chip-info-bg: var(--telekom-color-functional-informational-subtle, #d3d7f9);
8896
--tone-chip-info-border: color-mix(in srgb, var(--telekom-color-functional-informational-standard) 35%, transparent);
89-
--tone-chip-info-text: var(--telekom-color-text-and-icon-on-subtle-blue, #2238df);
97+
--tone-chip-info-text: #0d1570;
9098

9199
--tone-chip-success-bg: var(--telekom-color-functional-success-subtle, #ccf0e1);
92100
--tone-chip-success-border: color-mix(in srgb, var(--telekom-color-functional-success-standard) 40%, transparent);
93-
--tone-chip-success-text: var(--telekom-color-text-and-icon-on-subtle-green, #005c39);
101+
--tone-chip-success-text: #004d30;
94102

95103
--tone-chip-warning-bg: var(--telekom-color-functional-warning-subtle, #fee2d0);
96104
--tone-chip-warning-border: color-mix(in srgb, var(--telekom-color-functional-warning-standard) 50%, transparent);
97-
--tone-chip-warning-text: var(--telekom-color-text-and-icon-on-subtle-orange, #8f4400);
105+
--tone-chip-warning-text: #6b3300;
98106

99107
--tone-chip-danger-bg: var(--telekom-color-functional-danger-subtle, #fad2cf);
100108
--tone-chip-danger-border: color-mix(in srgb, var(--telekom-color-functional-danger-standard) 55%, transparent);
101-
--tone-chip-danger-text: var(--telekom-color-text-and-icon-on-subtle-red, #c30a03);
109+
--tone-chip-danger-text: #8a0700;
102110

103111
--tone-chip-neutral-bg: var(--telekom-color-ui-subtle, #efeff0);
104112
--tone-chip-neutral-border: var(--telekom-color-ui-border-standard);
@@ -113,6 +121,8 @@
113121
:root[data-theme="dark"] {
114122
color-scheme: dark;
115123

124+
--telekom-color-text-and-icon-additional: #c0c0c0 !important;
125+
116126
/* Surface colors for dark mode */
117127
--surface-primary: var(--telekom-color-background-canvas, #000000);
118128
--surface-elevated: var(--telekom-color-background-surface-subtle, #242426);
@@ -123,10 +133,10 @@
123133
--border-strong: var(--telekom-color-ui-border-standard);
124134
--shadow-card: var(--telekom-shadow-raised-standard);
125135

126-
/* Chip colors adjusted for dark mode */
136+
/* Chip colors adjusted for dark mode — lightened magenta for AAA on dark bg */
127137
--chip-bg: color-mix(in srgb, var(--telekom-color-primary-standard) 15%, transparent);
128138
--chip-border: color-mix(in srgb, var(--telekom-color-primary-standard) 35%, transparent);
129-
--chip-text: var(--telekom-color-text-and-icon-primary-standard);
139+
--chip-text: #ff8cc8;
130140

131141
/* Semantic tone chips - dark mode uses subtle backgrounds
132142
* Text colors are lightened vs Scale defaults to meet WCAG AAA (7:1)
@@ -160,7 +170,7 @@
160170
:root[data-high-contrast="true"] {
161171
/* Force maximum text contrast */
162172
--telekom-color-text-and-icon-standard: #000000;
163-
--telekom-color-text-and-icon-additional: #1a1a1a;
173+
--telekom-color-text-and-icon-additional: #1a1a1a !important;
164174
--telekom-color-text-and-icon-disabled: #595959;
165175

166176
/* Solid surfaces — no translucency */
@@ -178,14 +188,17 @@
178188
--tone-chip-danger-text: #8a0700;
179189
--tone-chip-neutral-text: #000000;
180190

191+
--chip-text: #730040;
192+
--chip-bg: color-mix(in srgb, #730040 10%, transparent);
193+
181194
/* Stronger focus indicator */
182195
--focus-outline: #000000;
183196
}
184197

185198
/* High contrast + dark mode combination */
186199
:root[data-high-contrast="true"][data-theme="dark"] {
187200
--telekom-color-text-and-icon-standard: #ffffff;
188-
--telekom-color-text-and-icon-additional: #e0e0e0;
201+
--telekom-color-text-and-icon-additional: #e0e0e0 !important;
189202
--telekom-color-text-and-icon-disabled: #a0a0a0;
190203

191204
--surface-card-subtle: var(--telekom-color-background-surface-subtle, #242426);
@@ -200,6 +213,9 @@
200213
--tone-chip-danger-text: #ff8a7a;
201214
--tone-chip-neutral-text: #ffffff;
202215

216+
--chip-text: #ffa4cc;
217+
--chip-bg: color-mix(in srgb, #ffa4cc 12%, transparent);
218+
203219
--focus-outline: #ffffff;
204220
}
205221

@@ -216,14 +232,43 @@ scale-card {
216232

217233
/* Consistent button styling across all variants - use pill radius */
218234
scale-button {
219-
--radius: 999px;
220-
--button-radius: 999px;
235+
--radius: var(--radius-pill);
236+
--button-radius: var(--radius-pill);
221237
}
222238

223239
/* Fallback for shadow DOM button parts */
224240
scale-button::part(button),
225241
scale-button::part(base) {
226-
border-radius: 999px !important;
242+
border-radius: var(--radius-pill) !important;
243+
}
244+
245+
/* AAA contrast: darken primary button bg so white text reaches 7:1 */
246+
scale-button::part(variant-primary) {
247+
background-color: #a8005b !important;
248+
border-color: #a8005b !important;
249+
}
250+
251+
/* AAA contrast: darken active nav link from Telekom magenta */
252+
scale-telekom-nav-item a[aria-current="true"],
253+
[role="menuitem"][aria-current="true"] {
254+
color: #8e004a !important;
255+
}
256+
257+
/* Dark mode: lighten active nav link for dark header background (#151517) */
258+
:root[data-theme="dark"] scale-telekom-nav-item a[aria-current="true"],
259+
:root[data-theme="dark"] [role="menuitem"][aria-current="true"] {
260+
color: #ff8cc8 !important;
261+
}
262+
263+
/* AAA contrast: Scale combobox label inside subtle surface */
264+
scale-dropdown::part(label),
265+
scale-dropdown::part(combobox-label) {
266+
color: var(--telekom-color-text-and-icon-additional) !important;
267+
}
268+
269+
/* AAA contrast: lighten ghost button text in dark mode for 7:1 on dark bg */
270+
:root[data-theme="dark"] scale-button::part(variant-ghost) {
271+
color: #93a8ff !important;
227272
}
228273

229274
/* ============================================

frontend/src/components/ApprovalModalContent.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ function handleNoteChange(ev: Event) {
186186
gap: var(--space-2xs);
187187
margin-top: var(--space-sm);
188188
padding: var(--space-xs) var(--space-sm);
189-
border-radius: 999px;
189+
border-radius: var(--radius-pill);
190190
font-weight: 600;
191191
text-transform: uppercase;
192192
font-size: 0.85rem;
@@ -237,12 +237,12 @@ function handleNoteChange(ev: Event) {
237237
238238
/* Ensure all buttons have pill shape */
239239
.modal-actions :deep(scale-button) {
240-
--radius: 999px;
240+
--radius: var(--radius-pill);
241241
}
242242
243243
.modal-actions :deep(scale-button)::part(button),
244244
.modal-actions :deep(scale-button)::part(base) {
245-
border-radius: 999px !important;
245+
border-radius: var(--radius-pill) !important;
246246
}
247247
248248
.modal-actions > * {

frontend/src/components/BreakglassCard.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,7 @@ function drop() {
774774
775775
.timeline-callout .session-id {
776776
font-size: 0.8rem;
777-
color: var(--telekom-color-text-and-icon-additional);
777+
color: inherit;
778778
word-break: break-all;
779779
margin-top: var(--space-2xs);
780780
}
@@ -803,7 +803,7 @@ function drop() {
803803
}
804804
805805
.breakglass-card__requirement {
806-
color: var(--telekom-color-functional-danger-standard);
806+
color: var(--tone-chip-danger-text);
807807
font-weight: 600;
808808
}
809809
@@ -880,12 +880,12 @@ function drop() {
880880
881881
/* Ensure all buttons have pill shape */
882882
.modal-actions :deep(scale-button) {
883-
--radius: 999px;
883+
--radius: var(--radius-pill);
884884
}
885885
886886
.modal-actions :deep(scale-button)::part(button),
887887
.modal-actions :deep(scale-button)::part(base) {
888-
border-radius: 999px !important;
888+
border-radius: var(--radius-pill) !important;
889889
}
890890
891891
:deep(input::placeholder),

frontend/src/components/common/ActionButton.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,13 @@ function handleClick(event: Event) {
7878
<style scoped>
7979
.action-button {
8080
min-width: 6rem;
81-
--radius: 999px;
81+
--radius: var(--radius-pill);
8282
}
8383
8484
/* Ensure pill shape for all button variants including danger */
8585
.action-button::part(button),
8686
.action-button::part(base) {
87-
border-radius: 999px !important;
87+
border-radius: var(--radius-pill) !important;
8888
}
8989
9090
.action-button--loading {

frontend/src/components/common/ReasonPanel.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,16 @@ const hasReason = computed(() => Boolean(props.reason?.trim()));
9494
background: var(--telekom-color-functional-success-subtle);
9595
}
9696
97+
.reason-panel--approval .reason-panel__label {
98+
color: var(--tone-chip-success-text);
99+
}
100+
97101
.reason-panel--rejection {
98102
border-left: var(--telekom-line-weight-bold, 4px) solid var(--telekom-color-functional-danger-standard);
99103
background: var(--telekom-color-functional-danger-subtle);
100104
}
105+
106+
.reason-panel--rejection .reason-panel__label {
107+
color: var(--tone-chip-danger-text);
108+
}
101109
</style>

frontend/src/components/common/TimelineGrid.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ function formatValue(value: string | Date | number | null | undefined): string {
132132
border: 1px solid var(--tone-chip-info-border);
133133
border-left: 3px solid var(--telekom-color-functional-informational-standard);
134134
padding: 0.5rem;
135-
border-radius: 8px;
135+
border-radius: var(--radius-md);
136136
margin: -0.5rem;
137137
}
138138

frontend/src/views/NotFoundView.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
.not-found__cta {
4242
display: inline-block;
4343
padding: var(--space-sm) var(--space-lg);
44-
border-radius: 999px;
44+
border-radius: var(--radius-pill);
4545
background: var(--accent-telekom);
4646
color: var(--telekom-color-text-and-icon-white-standard, #fff);
4747
font-weight: 600;

frontend/src/views/PendingApprovalsView.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@
109109
{{ session.metadata.name }}
110110
</scale-tag>
111111
<scale-tag v-if="session.spec?.scheduledStartTime" variant="warning">
112-
<scale-icon-content-calendar size="14" decorative style="margin-right: 4px; vertical-align: middle" />
112+
<scale-icon-content-calendar size="14" decorative class="tag-icon" />
113113
Scheduled
114114
</scale-tag>
115115
<scale-tag v-if="session.approvalReason?.mandatory" variant="danger">
116-
<scale-icon-action-edit size="14" decorative style="margin-right: 4px; vertical-align: middle" />
116+
<scale-icon-action-edit size="14" decorative class="tag-icon" />
117117
Note required
118118
</scale-tag>
119119
</template>
@@ -616,6 +616,11 @@ onMounted(fetchPendingApprovals);
616616
617617
/* tone-chip classes are defined globally in base.css */
618618
619+
.tag-icon {
620+
margin-right: var(--space-xs);
621+
vertical-align: middle;
622+
}
623+
619624
.mono-tag {
620625
font-family: var(--telekom-typography-font-family-mono, monospace);
621626
font-size: 0.8em;

frontend/src/views/SessionBrowser.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ header p {
711711
712712
.state-pill {
713713
border: 1px solid var(--session-border);
714-
border-radius: 999px;
714+
border-radius: var(--radius-pill);
715715
padding: var(--space-2xs) var(--space-sm);
716716
display: inline-flex;
717717
gap: var(--space-2xs);

0 commit comments

Comments
 (0)