[P2] Forced-colors (high-contrast) mode hides the tissue bars, tank gauge fill, reserve marker and NDL meter #116

Open
opened 2026-10-31 19:47:41 +00:00 by pedro · 0 comments
Owner

Priority: P2
Type: bug
Source: full codebase review requested 2026-10-31 (independently reproduced against 2cac7cf)

Location: src/style.css:385-410, src/ui/TissueBars.tsx:46-54, src/ui/TankPressureGauge.tsx:38-75, src/style.css:640-650, src/style.css:1298-1322, src/style.css:1858-1870

Problem and evidence

The stylesheet has no @media (forced-colors: active) rules and never sets forced-color-adjust. A grep of src/ and docs/ for "forced" finds nothing. These graphics are drawn only with background colours:

  • the tissue .bar, which gets its colour from the inline background in TissueBars.tsx. Its parent .tissue-bar button has background:none; border:0.
  • .tank-gauge-fill
  • .tank-reserve-marker
  • .ndl-meter > div and its track

The selected compartment is shown only by opacity plus box-shadow. In forced-colors mode the browser replaces background-color with Canvas and removes box-shadow. So the 16 compartment bars and their button outlines disappear, and so does the selection cue. Every cylinder gauge looks like an empty outlined rectangle at any pressure, with no reserve marker. The NDL meter is invisible. The numbers still show, but the main tissue visualisation stops working for users who rely on Windows High Contrast or other forced-colours modes.

I served the HEAD build (/tmp/divesim-review-dist-SqbiNx) on a private port and loaded it in Playwright Chromium twice, once with forcedColors:'none' and once with forcedColors:'active'. In the forced run, matchMedia('(forced-colors: active)') returned true. Computed styles, normal vs forced:

  • .tissue-bar .bar background: rgb(67,207,189) normal, rgb(255,255,255) forced. Its box-shadow rgb(197,248,239) 0 0 0 1px became none. The bar is still 26.9px tall but painted the page colour. The parent .tissue-bar has transparent background and border: none.
  • .tank-gauge-fill background: rgb(67,207,189) normal, rgb(255,255,255) forced. The track .tank-gauge is also white; only its 1px black border survives.
  • .tank-reserve-marker background: rgb(255,223,0) normal, rgb(255,255,255) forced, with its box-shadow removed.
  • .ndl-meter > div and .ndl-meter are both rgb(255,255,255) in forced mode, so the meter is invisible.

The forced-mode screenshot shows the Cylinder 1 gauge at 3000.0 psi (full) drawn as an empty outlined bar.

Suggested correction

Add a @media (forced-colors: active) block:

  • Give .tissue-bar a 1px solid ButtonBorder border.
  • Give .bar, .tank-gauge-fill, .ndl-meter > div and .tank-reserve-marker forced-color-adjust: none with a system colour: background: Highlight for the fills and CanvasText for the reserve marker. Alternatively, draw them with borders or outlines, which survive forced colours.
  • Mark .tissue-bar.selected / [aria-pressed=true] with an outline: 2px solid Highlight instead of the box-shadow.
  • Give the legend swatches, .tank-gauge and .ndl-meter tracks a CanvasText or ButtonBorder border.
  • Optionally keep the reserve, empty and exceeded states distinct with Mark or LinkText, or with patterns.

Acceptance criteria

Run Playwright Chromium with forcedColors:'active' and check:

  • The computed background (or border/outline) of .tissue-bar .bar, .tank-gauge-fill, .tank-reserve-marker and .ndl-meter > div differs from the Canvas colour of their container.
  • Each .tissue-bar has a visible border.
  • The selected compartment has a visible outline.
  • A full-cylinder screenshot shows a filled gauge with a visible reserve marker.

Also add a regression test: either an e2e test asserting those computed styles under forced colours, or a CSS test asserting that the forced-colors media block exists and covers these selectors. Normal-mode rendering must not change. pnpm verify passes.

Scope: maintenance of the educational simulator. Preserve historical R1 acceptance and operational-validation limits.

Priority: P2 Type: bug Source: full codebase review requested 2026-10-31 (independently reproduced against `2cac7cf`) Location: `src/style.css:385-410`, `src/ui/TissueBars.tsx:46-54`, `src/ui/TankPressureGauge.tsx:38-75`, `src/style.css:640-650`, `src/style.css:1298-1322`, `src/style.css:1858-1870` Problem and evidence The stylesheet has no `@media (forced-colors: active)` rules and never sets `forced-color-adjust`. A grep of src/ and docs/ for "forced" finds nothing. These graphics are drawn only with background colours: - the tissue `.bar`, which gets its colour from the inline `background` in TissueBars.tsx. Its parent `.tissue-bar` button has `background:none; border:0`. - `.tank-gauge-fill` - `.tank-reserve-marker` - `.ndl-meter > div` and its track The selected compartment is shown only by opacity plus `box-shadow`. In forced-colors mode the browser replaces background-color with Canvas and removes box-shadow. So the 16 compartment bars and their button outlines disappear, and so does the selection cue. Every cylinder gauge looks like an empty outlined rectangle at any pressure, with no reserve marker. The NDL meter is invisible. The numbers still show, but the main tissue visualisation stops working for users who rely on Windows High Contrast or other forced-colours modes. I served the HEAD build (/tmp/divesim-review-dist-SqbiNx) on a private port and loaded it in Playwright Chromium twice, once with `forcedColors:'none'` and once with `forcedColors:'active'`. In the forced run, matchMedia('(forced-colors: active)') returned true. Computed styles, normal vs forced: - `.tissue-bar .bar` background: rgb(67,207,189) normal, rgb(255,255,255) forced. Its box-shadow `rgb(197,248,239) 0 0 0 1px` became `none`. The bar is still 26.9px tall but painted the page colour. The parent `.tissue-bar` has transparent background and `border: none`. - `.tank-gauge-fill` background: rgb(67,207,189) normal, rgb(255,255,255) forced. The track `.tank-gauge` is also white; only its 1px black border survives. - `.tank-reserve-marker` background: rgb(255,223,0) normal, rgb(255,255,255) forced, with its box-shadow removed. - `.ndl-meter > div` and `.ndl-meter` are both rgb(255,255,255) in forced mode, so the meter is invisible. The forced-mode screenshot shows the Cylinder 1 gauge at 3000.0 psi (full) drawn as an empty outlined bar. Suggested correction Add a `@media (forced-colors: active)` block: - Give `.tissue-bar` a `1px solid ButtonBorder` border. - Give `.bar`, `.tank-gauge-fill`, `.ndl-meter > div` and `.tank-reserve-marker` `forced-color-adjust: none` with a system colour: `background: Highlight` for the fills and `CanvasText` for the reserve marker. Alternatively, draw them with borders or outlines, which survive forced colours. - Mark `.tissue-bar.selected` / `[aria-pressed=true]` with an `outline: 2px solid Highlight` instead of the box-shadow. - Give the legend swatches, `.tank-gauge` and `.ndl-meter` tracks a `CanvasText` or `ButtonBorder` border. - Optionally keep the reserve, empty and exceeded states distinct with `Mark` or `LinkText`, or with patterns. Acceptance criteria Run Playwright Chromium with `forcedColors:'active'` and check: - The computed background (or border/outline) of `.tissue-bar .bar`, `.tank-gauge-fill`, `.tank-reserve-marker` and `.ndl-meter > div` differs from the Canvas colour of their container. - Each `.tissue-bar` has a visible border. - The selected compartment has a visible outline. - A full-cylinder screenshot shows a filled gauge with a visible reserve marker. Also add a regression test: either an e2e test asserting those computed styles under forced colours, or a CSS test asserting that the forced-colors media block exists and covers these selectors. Normal-mode rendering must not change. pnpm verify passes. Scope: maintenance of the educational simulator. Preserve historical R1 acceptance and operational-validation limits.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: pedro/DiveSim#116
No description provided.