Skip to content

WCAG 2.2: contrast fixes and guaranteed focus rings across all themes - #17

Open
jeremiahbeasley wants to merge 8 commits into
usmannasir:mainfrom
jeremiahbeasley:wcag-contrast
Open

WCAG 2.2: contrast fixes and guaranteed focus rings across all themes#17
jeremiahbeasley wants to merge 8 commits into
usmannasir:mainfrom
jeremiahbeasley:wcag-contrast

Conversation

@jeremiahbeasley

Copy link
Copy Markdown

Summary

Contrast-audited every theme against the CyberPanel 2.4.x UI and fixed the failures — including the ones caused by variables a theme doesn't define, where the panel's stock value lands on the theme's backgrounds (e.g. dark themes inheriting the stock mid-gray secondary text on near-black backgrounds).

Changes

  • 13 failing contrast pairs fixed (WCAG 1.4.3 text 4.5:1, accent-as-link 4.5:1, focus 3:1). All adjustments are hue-preserving lightness moves, so each theme keeps its character; white button text is flipped dark where a theme's accent is a light mid-tone.
  • Every theme now declares a --focus-ring with ≥3:1 contrast against its own backgrounds (WCAG 1.4.11).
  • Removed 4 outline: 0/none !important focus suppressions (Ragnarock, HMM-Theme ×2, VJ-Theme-Dark-v2) that made keyboard focus invisible (WCAG 2.4.7). Modern browsers only show outlines on :focus-visible, so mouse users see no change.
  • tools/contrast_audit.py: the audit/fix tool, committed and re-runnable — python3 tools/contrast_audit.py reports, --fix repairs. It understands both the v2 token vocabulary and the legacy variable set, so future theme submissions can be checked in CI.

Current state: python3 tools/contrast_audit.py .0 failing pairs, 0 outline suppressions across all 22 themes.

Audited every theme with tools/contrast_audit.py against the 2.4.x panel
(both the v2 token vocabulary and the legacy variables as mapped by the
panel's theme bridge), including tokens a theme omits and therefore
inherits at stock values:

- 13 failing contrast pairs fixed (1.4.3 text 4.5:1, links-on-bg 4.5:1,
  focus 3:1): dark themes inheriting mid-gray secondary text / indigo
  accent on dark backgrounds, and white button text on light accents
  (flipped to dark text where the accent is mid-tone).
- Every theme now carries a --focus-ring with >=3:1 contrast against its
  own backgrounds (1.4.11).
- Removed 4 'outline: 0/none !important' focus suppressions (Ragnarock,
  HMM x2, VJ-Dark-v2) that killed keyboard focus visibility (2.4.7).

All adjustments are hue-preserving lightness moves; the audit/fix tool is
committed and re-runnable: python3 tools/contrast_audit.py [--fix]
…ity catalog

- DO-Inpired-flat-blue / flat-black rewritten for the 2.4 design-token
  system (their old-UI selectors no longer exist in the panel, so they
  had zero visible effect): light content, themed dark sidebar via the
  new sidebar tokens, original palette and credit preserved.
- Audit tool extended: sidebar-token pairs (sidebar-text/bg-sidebar,
  section header, hover) with proper var() fallback-chain modeling;
  failing sidebar pairs are fixed by declaring the sidebar token itself,
  never by mutating the theme accent. 8 further pairs fixed; audit is
  again clean across all themes.
- tools/build_catalog.py generates catalog.json classifying every theme
  as native / partial (bridged palette) / legacy (no effect on 2.4) so
  the panel can label its theme dropdown honestly.
Every theme except the archived legacy-VJ-* series (superseded by the
VJ-*-v2 themes) now fully restyles the 2.4 panel. Each port preserves the
original palette, character, and attribution, extracted from the old-UI
selector rules that no longer match anything:

- Barracuda Dark: charcoal + near-black chrome, cornflower accent
  (dark-on-blue buttons — white on cornflower is ~3:1)
- CF Inspired White: Cloudflare-style whites, pale-blue hover pills,
  navy ink; accent deepened in-hue to #3b6fd4 for 4.5:1 links
- CyberSpace Dark: deep blue-dark with teal/sky accents; alpha panel
  overlays composited to solids, remote background image dropped
- Gaussian Style: glassmorphism composited onto its indigo base,
  signature gold promoted to accent
- HMM NEXT: pink-tinted light theme, Outfit/Be Vietnam Pro typography
  kept, deep-blue brand accent
- Ragnarock: parchment content + navy sidebar, orange/gold/red accents
  tuned to pass 4.5:1
- blue-green / red-orange: accent reskins of the stock light UI with
  gradient identity kept as section/table bands
- l-dark / true-dark: near-black ladders mapped one-to-one, signature
  green accents
- dark-theme / soft-dark-theme: full-fidelity ports replacing the
  bridge approximation

All 18 non-archived themes pass tools/contrast_audit.py (0 failing
pairs); catalog.json now classifies them all as native.
The panel's dark-mode toggle flips any token a theme leaves unset between
the stock light and dark palettes, which broke contrast catastrophically
across modes (e.g. a light theme's #292929 text on the dark-mode #23252d
code background: 1.05:1).

- New --complete pass pins every mode-sensitive token from the theme's
  own palette (surfaces, text, borders, code/muted backgrounds, table
  head, accent hover, focus ring), so a theme is one coherent skin in
  both modes.
- Audit now models both modes: unset tokens resolve from the stock light
  OR dark ([data-theme=dark]) palette; --dark audits the dark toggle.
  New pairs: text on bg-muted/bg-code, table head, text-on-accent vs
  accent-hover.
- Archived legacy-* dirs excluded from audit scope (superseded by the
  *-v2 ports, no longer served by the panel catalog).

All 18 served themes: 0 failing pairs in light AND dark mode.
Architecture change per review feedback: instead of pinning one look,
each theme now carries an audited :root palette (default look) AND an
explicit [data-theme=dark] palette the moon toggle renders — dark themes
mirror themselves (stable no-op), light themes get designed dark
companions tinted with their own hue identity.

- Audit v2: resolves var() indirection (a var()-declared token was
  previously skipped, not checked — this hid Ragnarock's invisible
  navy-on-navy active menu item), strips !important, audits both modes,
  checks active-menu-item visibility (new sidebar-item-active-bg/text
  tokens in the panel).
- tools/consolidate.py: folds accumulated correction blocks into one
  clean :root + one dark block per theme, derives designed dark
  companions, solves all pairs in-memory.
- Hand fixes: VJ-Dark solid hovers + light hover text (translucent
  white-over-black hovers under mid-gray text), VJ-Green darker
  accent-hover so white button text passes on both states.

All 18 served themes: [v2+dark] OK, 0 failing pairs, both modes.
…ification

- Every theme now has a genuinely LIGHT :root palette and a genuinely
  DARK [data-theme=dark] palette (per review: the mode toggle must mean
  something for every theme). Originally-dark themes keep their original
  design as the dark palette and get a designed light companion — light
  content surfaces tinted with the theme hue, the dark sidebar kept as
  identity. Audit enforces polarity (content surfaces light in light
  mode, dark in dark mode) plus all contrast pairs in BOTH modes.
- Renamed mode-implying themes (each theme now ships both modes):
  dark-theme -> Graphite, soft-dark-theme -> Slate, l-dark-theme -> Onyx,
  true-dark-cyberpanel -> Evergreen, CyberSpace-Dark-By-Interpryce ->
  CyberSpace-By-Interpryce, VJ-Theme-Dark-v2 -> VJ-Theme-Mono-v2
  ('formerly named' notes kept in each file).
- tools/consolidate.py derives the companions and solves pairs in-memory;
  audit v2 resolves var() indirection and !important (a var()-declared
  token was previously skipped unchecked — this had hidden an invisible
  navy-on-navy active menu item).
- Visually verified: all 18 themes screenshotted in both modes with
  headless Chromium against the real panel CSS.

All 18 themes: 0 failing pairs, both modes, polarity clean.
Review feedback: keeping a theme's dark sidebar in light mode (as
'identity') contradicts true-mode semantics. All 11 light palettes that
carried a dark sidebar now use a hue-tinted light sidebar (dark text,
accent-colored section/active pills keep the identity). The audit's
polarity check now covers bg-sidebar in both modes, so this can't
regress. Verified with headless-Chromium screenshots of all 18 themes;
0 failing contrast pairs in both modes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant