diff --git a/packages/ui/FORCED_COLORS_CHECKLIST.md b/packages/ui/FORCED_COLORS_CHECKLIST.md new file mode 100644 index 0000000..491b6d2 --- /dev/null +++ b/packages/ui/FORCED_COLORS_CHECKLIST.md @@ -0,0 +1,258 @@ +# Windows Forced-Colors Mode Verification Checklist + +This checklist helps verify that SO4's interface remains operable when Windows High Contrast Mode is active. Forced-colors mode replaces custom colors with system colors, which can break gradients, translucent elements, and custom focus treatments. + +## Setup + +### Enable Windows High Contrast Mode + +**Windows 10/11:** +1. Press `Left Alt + Left Shift + Print Screen` +2. Or: Settings → Accessibility → High Contrast → Turn on High Contrast + +**Browser Testing:** +- Test in Edge or Chrome (best support for forced-colors) +- Firefox also supports it but with some differences + +### Emulate in DevTools + +**Chrome/Edge:** +1. Open DevTools (F12) +2. Press `Ctrl+Shift+P` → "Rendering" +3. Scroll to "Emulate CSS media feature forced-colors" +4. Select "active" + +## Core Components Checklist + +### ✅ Buttons + +- [ ] Button text is readable against button background +- [ ] Button borders are visible +- [ ] Hover state shows clear visual change (highlight) +- [ ] Focus indicator is clearly visible (2px outline) +- [ ] Disabled buttons show grayed text +- [ ] Icon buttons remain identifiable +- [ ] All button variants (primary, outline, ghost, destructive) work + +**Test locations:** +- `/` - Hero CTA buttons +- `/trade` - Place order, Cancel buttons +- All forms and dialogs + +### ✅ Links + +- [ ] Links use system LinkText color +- [ ] Links are underlined +- [ ] Hover/focus shows highlight background +- [ ] Visited links remain distinguishable (if applicable) + +**Test locations:** +- Navigation menu +- Footer links +- Inline text links + +### ✅ Form Inputs + +- [ ] Input fields have visible borders +- [ ] Input text is readable +- [ ] Placeholder text is visible (GrayText) +- [ ] Focus outline is clearly visible +- [ ] Invalid state shows doubled border +- [ ] Disabled inputs show grayed text +- [ ] Labels are associated and readable + +**Test locations:** +- `/trade` - Order form inputs +- `/pools` - Liquidity form +- Search inputs + +### ✅ Checkboxes and Radio Buttons + +- [ ] Unchecked boxes have visible borders +- [ ] Checked boxes show system checkmark +- [ ] Radio buttons follow same pattern +- [ ] Labels are readable and associated +- [ ] Disabled state shows grayed + +**Test locations:** +- Settings panels +- Filter controls +- Terms acceptance checkboxes + +### ✅ Selects and Dropdowns + +- [ ] Dropdown trigger has visible border +- [ ] Dropdown arrow/icon is visible +- [ ] Dropdown menu has visible border +- [ ] Selected option is highlighted +- [ ] Hover state is distinguishable +- [ ] Disabled state shows grayed + +**Test locations:** +- Network selector +- Token pair selects +- Any combo boxes + +### ✅ Tabs + +- [ ] All tabs have visible borders or separators +- [ ] Active tab is clearly distinguished (underline or highlight) +- [ ] Inactive tabs remain readable +- [ ] Hover state shows visual change +- [ ] Focus indicator is visible + +**Test locations:** +- `/trade` - Order tabs (Limit, Market) +- Settings tabs (if applicable) + +### ✅ Dialogs and Modals + +- [ ] Dialog has visible border +- [ ] Dialog content is readable +- [ ] Close button is visible and operable +- [ ] Backdrop (if visible) does not obscure dialog +- [ ] Dialog title stands out + +**Test locations:** +- Connect wallet modal +- Confirmation dialogs +- Settings dialogs + +### ✅ Alerts and Notifications + +- [ ] Alert container has visible border +- [ ] Alert text is readable +- [ ] Alert icon is visible (uses currentColor) +- [ ] Severity is distinguishable by border/structure, not just color +- [ ] Dismiss button (if present) is visible + +**Test locations:** +- Error messages after failed transactions +- Success toasts +- Warning banners + +### ✅ Menus + +- [ ] Menu container has visible border +- [ ] Menu items are readable +- [ ] Hover/focus highlights menu item +- [ ] Selected menu item (if applicable) is distinguished +- [ ] Separators between menu sections are visible +- [ ] Disabled menu items show grayed text + +**Test locations:** +- User dropdown menu +- Context menus +- Navigation dropdown (if applicable) + +### ✅ Tables and Data Grids + +- [ ] Table borders are visible +- [ ] Header row is distinguishable +- [ ] Cell borders or separators are visible +- [ ] Row hover shows highlight +- [ ] Selected row is distinguished +- [ ] Sortable column headers show affordance + +**Test locations:** +- `/pools` - Liquidity table +- Order history tables +- Position tables + +### ✅ Icons and SVGs + +- [ ] All icons remain visible (use currentColor fill/stroke) +- [ ] Status icons are distinguishable by shape, not just color +- [ ] Icon buttons maintain icon visibility +- [ ] Loading spinners remain visible + +**Test locations:** +- Navigation icons +- Status indicators (success, error, pending) +- Social media icons + +### ✅ Focus Indicators + +- [ ] All interactive elements show focus outline +- [ ] Focus outline uses system Highlight color +- [ ] Focus outline has 2px width minimum +- [ ] Focus outline does not disappear against any background +- [ ] Tab order makes sense + +**Test:** +- Tab through every page +- Verify focus is always visible + +### ✅ Trading-Specific States + +- [ ] Long/Short/Liquidation states remain distinguishable +- [ ] Price up/down indicators use shape or text, not just color +- [ ] Order status (pending, filled, cancelled) is clear +- [ ] Chart elements remain visible (if forced-colors affects charts, consider canvas-based alternative) + +**Test locations:** +- `/trade` - Order book, recent trades +- Price change indicators +- Position PnL + +### ✅ Separators and Dividers + +- [ ] Horizontal rules (`
`) are visible +- [ ] Section dividers are visible +- [ ] Card borders are visible + +**Test locations:** +- Between major sections +- Within complex forms +- Card components + +## Additional Checks + +### No Reliance on Background Images + +- [ ] No critical information is conveyed via background-image +- [ ] Decorative gradients do not break layout +- [ ] CSS gradients used for borders have solid fallbacks + +### System Colors Used Correctly + +- [ ] No hardcoded colors in forced-colors overrides +- [ ] Use ButtonText, CanvasText, LinkText, etc. instead of #000 or #fff +- [ ] `forced-color-adjust: none` is only used where necessary (hover, focus states) + +### Documentation + +- [ ] All forced-colors overrides are documented in `globals.css` +- [ ] This checklist is up to date +- [ ] Team is aware of forced-colors testing requirement + +## Testing Workflow + +1. Enable forced-colors mode (see Setup above) +2. Visit each major page: `/`, `/trade`, `/pools`, `/earn`, `/referrals`, `/faucet` +3. Test all interactive elements on each page +4. Use keyboard navigation (Tab, Enter, Space, Arrows) +5. Check both light and dark forced-colors themes if your OS offers them +6. Document any issues found +7. Re-test after fixes + +## Known Limitations + +- **Charts:** Canvas-based charts (e.g., TradingView) may not fully support forced-colors. Ensure fallback controls remain operable. +- **Third-party widgets:** Wallet connectors and external embeds may not support forced-colors. Document these as known limitations. +- **Browser differences:** Edge has the best support. Firefox and Chrome may differ slightly. + +## Resources + +- [CSS Color Adjustment Module](https://drafts.csswg.org/css-color-adjust-1/#forced) +- [Windows High Contrast Mode](https://docs.microsoft.com/en-us/fluent-ui/web-components/design-system/high-contrast) +- [MDN: forced-colors](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors) + +## Issue Reporting + +When reporting forced-colors issues, include: +- OS and version (e.g., Windows 11 22H2) +- Browser and version +- High contrast theme in use (e.g., "High Contrast Black") +- Screenshot showing the problem +- Steps to reproduce diff --git a/packages/ui/src/styles/globals.css b/packages/ui/src/styles/globals.css index 1411ad0..14cdfff 100644 --- a/packages/ui/src/styles/globals.css +++ b/packages/ui/src/styles/globals.css @@ -348,4 +348,216 @@ line-height: 1.3; font-weight: 500; font-variant-numeric: tabular-nums slashed-zero; -} \ No newline at end of file +} + +/* + * Windows forced-colors mode support (DS-067) + * + * When Windows High Contrast Mode is active, CSS gradients, translucent + * borders, and custom colors are replaced with system colors. These overrides + * ensure core primitives remain operable and distinguishable. + * + * System color keywords: + * - ButtonText, ButtonFace, GrayText, Highlight, HighlightText + * - LinkText, CanvasText, Canvas, Field, FieldText + * - Mark, MarkText + * + * Reference: https://drafts.csswg.org/css-color-adjust-1/#forced + */ +@media (forced-colors: active) { + /* Base text and backgrounds */ + * { + background-color: Canvas !important; + color: CanvasText !important; + border-color: CanvasText !important; + } + + /* Buttons */ + button, + [role="button"], + [data-slot="button"] { + background-color: ButtonFace !important; + color: ButtonText !important; + border: 1px solid ButtonText !important; + } + + button:hover, + [role="button"]:hover, + button:focus-visible, + [role="button"]:focus-visible { + forced-color-adjust: none; + background-color: Highlight !important; + color: HighlightText !important; + outline: 2px solid Highlight !important; + outline-offset: 2px; + } + + button:disabled, + [role="button"]:disabled, + button[aria-disabled="true"], + [role="button"][aria-disabled="true"] { + color: GrayText !important; + border-color: GrayText !important; + } + + /* Links */ + a { + color: LinkText !important; + text-decoration: underline; + } + + a:hover, + a:focus-visible { + forced-color-adjust: none; + background-color: Highlight !important; + color: HighlightText !important; + outline: 2px solid Highlight !important; + } + + /* Form controls */ + input, + textarea, + select, + [data-slot="input"], + [data-slot="textarea"], + [data-slot="select"] { + background-color: Field !important; + color: FieldText !important; + border: 1px solid FieldText !important; + } + + input:focus, + textarea:focus, + select:focus { + forced-color-adjust: none; + outline: 2px solid Highlight !important; + outline-offset: 0; + } + + input:disabled, + textarea:disabled, + select:disabled { + color: GrayText !important; + border-color: GrayText !important; + } + + input[aria-invalid="true"], + textarea[aria-invalid="true"], + [data-slot="input"][aria-invalid="true"] { + border: 2px solid CanvasText !important; + outline: 1px solid CanvasText !important; + outline-offset: -3px; + } + + /* Checkboxes and radios */ + input[type="checkbox"], + input[type="radio"], + [role="checkbox"], + [role="radio"] { + forced-color-adjust: none; + appearance: auto; + background-color: Field !important; + border: 1px solid FieldText !important; + } + + input[type="checkbox"]:checked, + input[type="radio"]:checked, + [role="checkbox"][aria-checked="true"], + [role="radio"][aria-checked="true"] { + forced-color-adjust: none; + background-color: Highlight !important; + border-color: Highlight !important; + } + + /* Selected and highlighted states */ + [aria-selected="true"], + [data-selected="true"], + [aria-current]:not([aria-current="false"]) { + forced-color-adjust: none; + background-color: Highlight !important; + color: HighlightText !important; + border-color: Highlight !important; + } + + /* Tabs */ + [role="tab"][aria-selected="true"] { + forced-color-adjust: none; + background-color: Canvas !important; + color: CanvasText !important; + border-bottom: 3px solid CanvasText !important; + } + + /* Dialogs and overlays */ + [role="dialog"], + [role="alertdialog"], + [data-slot="dialog"], + [data-slot="sheet"] { + background-color: Canvas !important; + border: 2px solid CanvasText !important; + } + + /* Alerts */ + [role="alert"], + [role="status"], + [data-slot="alert"] { + border: 2px solid CanvasText !important; + } + + /* Menus */ + [role="menu"], + [role="menubar"], + [role="listbox"] { + background-color: Canvas !important; + border: 1px solid CanvasText !important; + } + + [role="menuitem"], + [role="option"] { + color: CanvasText !important; + } + + [role="menuitem"]:hover, + [role="menuitem"]:focus, + [role="option"]:hover, + [role="option"]:focus, + [role="menuitem"][data-highlighted], + [role="option"][data-highlighted] { + forced-color-adjust: none; + background-color: Highlight !important; + color: HighlightText !important; + } + + /* Focus indicators - always visible */ + *:focus-visible { + forced-color-adjust: none; + outline: 2px solid Highlight !important; + outline-offset: 2px; + } + + /* Icons and SVGs */ + svg { + forced-color-adjust: auto; + fill: currentColor; + stroke: currentColor; + } + + /* Ensure separators are visible */ + hr, + [role="separator"] { + border-color: CanvasText !important; + background-color: CanvasText !important; + } + + /* Remove background images and gradients */ + * { + background-image: none !important; + } + + /* Ensure tooltips are visible */ + [role="tooltip"] { + forced-color-adjust: none; + background-color: Canvas !important; + color: CanvasText !important; + border: 1px solid CanvasText !important; + } +}