Accessibility
On this page
Every corporate and product surface ships against WCAG 2.2 AA. The palette is tuned so AAA is cheap on navy-900 surfaces; critical-alert contexts (destructive actions, mission-blocking errors, hostile-contact indicators in running text) are expected to clear AAA.
A surface fails review if any of these eight pillars is wrong:
Contrast - the real numbers
All values computed per the WCAG 2.x relative-luminance formula against FDT’s actual token values.
Thresholds.
| Threshold | Minimum ratio | Applies to |
|---|---|---|
| AA body | 4.5:1 | text under 18pt regular or 14pt bold |
| AA large | 3:1 | text at or above 18pt regular or 14pt bold · UI components |
| AAA body | 7:1 | preferred for running text on navy-900 |
Text pairings.
| Foreground | Background | Ratio | AA body | AA large | Verdict |
|---|---|---|---|---|---|
fog-100 (#E8EEF7) |
navy-900 |
16.0:1 | ✓ | ✓ | AAA |
fog-100 |
navy-800 |
14.7:1 | ✓ | ✓ | AAA |
fog-200 (#C5D1E2) |
navy-900 |
12.1:1 | ✓ | ✓ | AAA |
fog-200 |
navy-800 |
11.1:1 | ✓ | ✓ | AAA |
steel-300 (#8A9BB4) |
navy-900 |
6.5:1 | ✓ | ✓ | AA |
steel-300 |
navy-800 |
6.0:1 | ✓ | ✓ | AA |
steel-400 (#5A6D8A) |
navy-900 |
3.5:1 | ✗ | ✓ | UI only |
steel-400 |
navy-800 |
3.3:1 | ✗ | ✓ | UI only |
electric-500 (#1D6EF5) |
navy-900 |
4.1:1 | ✗ | ✓ | large/UI only |
electric-500 |
navy-800 |
3.8:1 | ✗ | ✓ | large/UI only |
electric-400 (#4A8DFF) |
navy-900 |
5.8:1 | ✓ | ✓ | AA |
electric-400 |
navy-800 |
5.3:1 | ✓ | ✓ | AA |
electric-300 (#7BA9FF) |
navy-900 |
7.9:1 | ✓ | ✓ | AAA |
hostile (#E0322C) |
navy-900 |
4.2:1 | ✗ | ✓ | large/UI only |
hostile-400 (#EE5050) |
navy-900 |
5.3:1 | ✓ | ✓ | AA |
neutral (#2FA85A) |
navy-900 |
6.3:1 | ✓ | ✓ | AA |
caution (#F2B535) |
navy-900 |
10.4:1 | ✓ | ✓ | AAA |
Three rules the table implies:
electric-500andhostileare fills, not text. They pass only the large-text and UI thresholds. Inline emphasis, links inside paragraphs, and error messages useelectric-400andhostile-400- the body-safe variants.steel-400is metadata only. Labels, axis ticks, timestamps - fine. Paragraphs and captions - usesteel-300or lighter.- Button label colors are locked per variant. See the button table below.
Button labels - locked per variant. The label color is determined by the fill; this is the only way buttons clear WCAG with the system’s fill values.
| Variant | Fill | Label | Contrast | Rule |
|---|---|---|---|---|
brand / primary |
electric-500 |
white | 4.6:1 | weight ≥600, size ≥14px |
danger |
hostile |
white | 4.5:1 | weight ≥600, size ≥14px |
success |
neutral |
navy-900 |
6.3:1 | dark label always · white on green fails at 3.0:1 |
warning |
caution |
navy-900 |
10.4:1 | dark label always · white on amber fails at 1.8:1 |
neutral (secondary) |
navy-700 |
fog-100 |
11.2:1 | standard dark-button treatment |
WebAwesome ships white labels as the default on all semantic variants.
fdt-theme.cssmust overridesuccessandwarning- the default ships inaccessible buttons.
Focus
Every interactive element has a visible focus state. The treatment is two-layer:
- 2px solid
electric-500border - bound to--wa-focus-ringso native and component focus match. --fdt-glow-smhalo - additive atmosphere, not a replacement for the solid border.- Uses
:focus-visible, not:focus- keyboard users get the treatment, mouse users don’t see flashing. - Never removed, only restyled.
The 2px border alone clears the 3:1 UI-contrast threshold against every navy surface. The glow is decorative reinforcement; the border is load-bearing.
Keyboard navigation
Every component is keyboard-operable. WebAwesome covers its own primitives (tab order, arrow-key navigation within groups, escape-to-dismiss on overlays). FDT-specific components must match:
- Program cards, sector cards, feature tiles - wrap in
<a>or<button>for native focus behavior. - Decision prompt (QRF) - fixed tab order, left button first.
- Map HUD corner panels - tab-reachable; inner content follows DOM order.
- Radar scope tracks - up/down cycles through active tracks, enter acquires.
Reduced motion
All motion respects prefers-reduced-motion: reduce. When active:
- Radar sweep - freezes at current position, no rotation.
- Live pulse - stops; opacity holds at 100%.
- Panel slides - become instant crossfades (150ms opacity only).
- Acquire brackets - snap to position without bloom or settle.
- Glow scale - remains. Glows are atmosphere, not motion.
Color-blind differentiation
Red/green is the most commonly conflated pair (deuteranopia ≈ 6% of males, protanopia ≈ 2%). FDT’s hostile and neutral sit on exactly that axis. The system defends with shape + text + color, never color alone.
- APP-6D symbology carries shape as the primary signal. Friendly = rounded rectangle (blue). Hostile = diamond (red). Neutral = square (green). Unknown = quatrefoil (yellow). A deuteranope can’t distinguish red from green by hue but distinguishes a diamond from a square instantly. Load-bearing for tactical contexts.
- Status pills always carry text.
CONTESTED(hostile) andSECURED(neutral) are spelled out - removing the label is a bug. - Resource meter icons. Each resource pairs color with glyph:
INTEL(eye, blue),MORALE(heart, amber),LOGISTICS(box, green),ESCALATION(triangle-exclaim, red). Color reinforces; it never stands alone. - Classification and program-status badges already carry text.
- Data visualizations distinguish series by position, pattern (solid / dashed / dotted), and color - in that order. A line chart with only color differentiation is incomplete.
Testing requirement. Every screen that uses hostile and neutral together is validated through a deuteranopia simulator (Chrome DevTools → Rendering → Emulate vision deficiency) before ship. If the screen becomes ambiguous, the shape or label layer has failed.
Forced colors (Windows High Contrast Mode)
Government and military workstations commonly enforce forced-colors themes. The system respects forced-colors: active and falls back to system colors:
@media (forced-colors: active) {
/* Surfaces become CanvasText/Canvas */
.wa-button, .fdt-program-card {
border: 1px solid ButtonText;
background: ButtonFace;
color: ButtonText;
}
/* Focus uses the system Highlight color */
:focus-visible {
outline: 2px solid Highlight;
outline-offset: 2px;
}
/* Accent fills become LinkText or Highlight */
.fdt-accent-fill {
background: Highlight;
color: HighlightText;
}
/* APP-6D symbols retain shape; fill becomes CanvasText */
.fdt-symbol {
forced-color-adjust: auto;
}
/* Glow is decorative - drop entirely */
[class*="fdt-glow"] {
box-shadow: none;
}
/* Semantic colors replaced by text labels + shape; affiliation color is stripped */
}
Rules.
- Never
background-coloralone - pair with border, icon, or text. - Never
border-coloralone for focus - useoutline(forced-colors respects it). forced-color-adjust: noneis reserved for elements where brand identity is essential and the four major Windows schemes (Black, White, Aquatic, Dusk) have all been verified.- APP-6D symbols keep
forced-color-adjust: auto- shape survives, color replaces with system text color.
Screen readers
- APP-6D symbols carry
role="img"witharia-labeldescribing type and affiliation:"friendly infantry battalion","hostile armored company". - Mono track IDs (
UNK-003) usearia-labelthat spells out the reading:"unknown zero zero three". - Classification badges include the classification name in accessible text.
- Radar tracks announce state via
aria-live="polite"(acquisitions, new contacts) oraria-live="assertive"(incoming threats). - Sector cards announce status transitions (
CONTESTED→SECURED) viaaria-live. - Decision-prompt buttons use
aria-labelthat includes the consequence, not just the verb - e.g.aria-label="Conserve - hold current ammunition, accept reduced engagement capability".
Touch targets
- Default: minimum 44×44px for any standalone tap target on mobile or tablet.
- Dense operator UI may tighten to 36×36px, but only inside clustered controls (resource meters, sub-unit badges) where the user is explicitly in operator mode with a known small pointer or stylus.
- Spacing between targets: at least 8px regardless of size.
Internationalization - NATO language support
Three locales aligned with NATO’s official working languages and the alliance’s largest continental member. All Latin-script LTR.
| Locale | Code | Constituency |
|---|---|---|
| English | en |
NATO official · authoring language · voice tuned to this register |
| French | fr |
NATO official · French MoD and partner commands |
| German | de |
Bundeswehr and allied Central European customers |
Practical consequences.
- Text expansion. German can run ~35% longer than English; French sits between. All text-bearing components flex on content - no fixed widths on buttons, labels, badges, or tags. Strings are externalized to the i18n catalog; no text is baked into images.
- Number and date formats. EN uses
1,234.56and2026-04-23. DE and FR use1.234,56withDD.MM.YYYYorDD/MM/YYYY. Formatters usewa-format-numberandwa-format-date, driven by the documentlang. Tactical contexts stay on ISO 8601 regardless of locale. - Military conventions stay locale-independent. 24-hour Zulu, MGRS, metric, NATO phonetic, APP-6D - alliance-wide, not linguistic.
- Fonts. Inter, Barlow Condensed, JetBrains Mono cover the extended Latin set - umlauts,
ß, French diacritics. No extra subsets needed. - Directional iconography. LTR across all three locales.
Not in scope: other Romance locales (Spanish, Italian, Portuguese), Nordic locales (Danish, Swedish, Norwegian, Finnish, Icelandic), Dutch, Cyrillic, Greek, RTL (Arabic, Hebrew), CJK. Each triggers a V2 cycle - font-stack changes, layout review, copy re-authoring.