GH GambleHub

Interface Theme Toggle

1) Principles

1. System> skin. The theme is not just a background inversion, but a set of tokens (color, background, contrast, shadows, states, illustrations, graphs).
2. System-first. By default - System ('prefers-color-scheme') with the ability to manually select Light/Dark/High-Contrast.
3. Default contrast. Target - WCAG AA, for small text/important labels - AAA.
4. No outbreaks. We apply the theme before rendering (inline script), and make the transitions carefully.
5. Brand stability. The accents and semantics of the statuses are preserved in all topics.

2) Modes and scenarios

Light - day scripts/payment forms/long read.
Dark - evening/low light/live matches; reduces glare.
System - follow the OS/browser ('prefers-color-scheme').
High-Contrast - increased contrast and minimized jewelry (incl. Reduce motion).
Seasonal/Promo (optional) - over the basic theme for the tournament/event (does not break tokens).

3) Token architecture

We store semantic tokens, not direct colors:
css
:root {
/ semantics/
--bg:    hsl(0 0% 99%);
--bg-elev:  hsl(0 0% 100%);
--fg:    hsl(220 15% 15%);
--muted:   hsl(220 10% 45%);
--accent: hsl (260 95% 60%) ;/brand accent/
--success:  hsl(152 55% 40%);
--warning:  hsl(36 85% 45%);
--danger:  hsl(0 75% 50%);
--border:  hsl(220 10% 90%);
--focus:   hsl(260 95% 60% /.6);
--shadow:  0 6px 24px hsl(220 20% 10% /.08);

/ typography/radii/
--radius: 12px;
--lh: 1. 4;
}
:root[data-theme="dark"]{
--bg:   hsl(220 18% 10%);
--bg-elev: hsl(220 18% 14%);
--fg:   hsl(0 0% 96%);
--muted:  hsl(220 10% 70%);
--accent: hsl (260 95% 65%) ;/slightly lighter in the dark/
--border: hsl(220 14% 22%);
--shadow: 0 8px 28px hsl(220 50% 2% /.6);
}
:root[data-theme="hc"]{
/ high-contrast: simple pairs, high Lc/
--bg: #000; --bg-elev:#000; --fg:#fff; --muted:#fff;
--accent:#00E; --success:#0F0; --warning:#FF0; --danger:#F00;
--border:#fff; --focus:#0FF;
}

Rule: Components use only semantic tokens.

4) Detector and save selection

html
<script>
(function(){
const saved = localStorage. getItem('theme'); // 'light'    'dark'    'hc'    'system'    null const sys = window. matchMedia('(prefers-color-scheme: dark)'). matches? 'dark': 'light';
const theme = saved && saved!=='system'? saved: sys;
document. documentElement. setAttribute('data-theme', theme);
})();
</script>
UI switch: 'Light/Dark/System/High-Contrast'. If you select'System ', do not store a specific color, only a flag. Listen to OS changes:
js matchMedia('(prefers-color-scheme: dark)'). addEventListener('change', e=>{
if(localStorage. getItem('theme')==='system'){
document. documentElement. setAttribute('data-theme', e. matches? 'dark': 'light');
}
});

5) Smooth transitions without FOUC

Apply the theme before loading the CSS (inline script).

Theme animations are short and only 'color/background/border-color' (120-200 ms), but not in the first render:
css
@media (prefers-reduced-motion: no-preference){
html. theme-ready { transition: color. 18s, background-color. 18s, border-color. 18s; }
}

After mounting the application, add' class =" theme-ready"'.

6) Components and states

Text/icons: contrast ≥ AA; secondary text not lower than 4. 5:1 (easily "fades" in the dark).
Fields/cards: background '--bg-elev', border '--border', shadow '--shadow'.
CTA: background '--accent', contrast text ('# fff' or calculated).

States (hover/focus/active/disabled): Change the brightness/alpha, not "shine the rainbow."

Graphics/sparklines: separate palettes for light/dark; grid/axes are low contrast but readable.

7) Images/Media/Logos

Monochrome icons - through 'currentColor' (adjust to the text).
Don't invert brand logos; Prepare two versions (light/dark).
Posters/screenshots: easy overlay in dark (8-12%) for readability of texts.
SVG: avoid "hard" fills, use var 'var (--fg) '/' var (--accent)'.

8) Affordability

High contrast: separate preset' data-theme =" hc"'.
Focus rings: always visible ('outline: 2px solid var (--focus); outline-offset: 2px`).
Don't rely on colour. Icon/text/pattern for statuses.
Fonts: 'font-variant-numeric: tabular-nums;' for sums/factors.
RTL: the theme does not break mirroring (we use logical properties).

9) Performance

Colors - CSS custom properties at the root → instant reuse without component renaming.
Avoid "repainting" images with 'invert ()' filters on large containers.
Lazy substitution of heavy illustrations for the theme (if necessary).
Do not store large palettes in JS - the theme is controlled by the class/attribute.

10) The specifics of iGaming

Live factors at night: "soft" contrast (AAA for numbers), highlighting the change in the factor is unobtrusive, without flickering.
Responsible play: Reminders and prompts are readable in both themes; without "poisonous" flowers at night.
Box office: fields/signatures/errors without tiring glowing accents; success/error are stable on the topic.
Tournament "skins": only as superficial accent-override, do not break basic tokens.

11) Snippets UI

Switch (HTML/JS):
html
<label class="theme-switch">
<span> Topic </span>
<select id="theme">
<option value = "system "> System </option>
<option value = "light "> Bright </option>
<option value = "dark "> Dark </option>
<option value = "hc"> High contrast </option>
</select>
</label>
<script>
const sel = document. getElementById('theme');
sel. value = localStorage. getItem('theme')          'system';
sel. addEventListener('change', e=>{
const v = e. target. value;
localStorage. setItem('theme', v);
if(v==='system'){
const sys = matchMedia('(prefers-color-scheme: dark)'). matches? 'dark':'light';
document. documentElement. setAttribute('data-theme', sys);
} else {
document. documentElement. setAttribute('data-theme', v);
}
});
</script>
Component presets:
css
.btn{height:44px; padding:0 16px; border-radius:var(--radius); display:inline-flex; align-items:center; gap:8px}
.btn--primary{background:var(--accent); color:#fff}
.card{background:var(--bg-elev); border:1px solid var(--border); box-shadow:var(--shadow); border-radius:var(--radius)}
.text-muted{color:var(--muted)}
React hook (persist + system):
tsx import { useEffect, useState } from 'react';
type Theme = 'light'    'dark'    'hc'    'system';
export function useTheme(){
const [theme, setTheme] = useState<Theme>(()=>localStorage. getItem('theme') as Theme          'system');
useEffect(()=>{
const apply = (t:Theme)=>{
const v = t==='system'? (matchMedia('(prefers-color-scheme: dark)'). matches? 'dark':'light'): t;
document. documentElement. setAttribute('data-theme', v);
};
apply(theme);
const mql = matchMedia('(prefers-color-scheme: dark)');
const on = ()=> theme==='system' && apply('system');
mql. addEventListener('change', on);
return ()=> mql. removeEventListener('change', on);
},[theme]);
useEffect(()=> localStorage. setItem('theme', theme),[theme]);
return { theme, setTheme };
}

12) Metrics

Theme adoption rate: share of users on Dark/System/HC.
FOUC rate: proportion with visible "white burst" at start (<1%).
Contrast defects: the number of contrast bugs by release.
Error visibility: clicks/repetitions due to "invisible" errors in different topics.
Energy impact (mobile): comparison of session time in the dark vs lait (indirect metric).

13) Anti-patterns

Invert all 'filter: invert (1)' - breaks the brand and meanings.
Change colors directly in components without tokens.
Hide focus rings in a dark theme.
Text is too dark on a dark background (or light on a light background).
Long transition to the whole page (slowdowns).
"Exclusive" status colors in one topic that are not in another.

14) QA checklist

Contrast and readability

  • All AA ≥ texts; critical labels/small text ≥ AAA.
  • Errors/success/warnings are not only discernible in color.

Behavior

  • System respects' prefers-color-scheme'and responds to OS changes.
  • No FOUC (theme applies before rendering).
  • Switching the theme does not reset the page state.

Components

  • Cards/forms/tables use only tokens.
  • Graphics have palettes for both themes.
  • Logos/icons are correctly visible in both themes.

A11y

  • Visible focus-ring; High-Contrast mode is available.
  • Consider'prefers-reduced-motion '.

Performance

  • Transition ≤ 200 ms; without global reflows.
  • No heavy filters/blends on containers.

15) Documentation in the design system

Theme tokens: palettes, contrasts, state (hover/focus/active/disabled).
Guides: How to add a new brendo accent without regressing contrast.
Charts/Media: predefined palettes for light/dark.
Patterns: System-first, High-Contrast, smooth switching without FOUC.
Do/Don't: filter inversion, inline colors, invisible errors/focus.

Brief Summary

The working theme switch is semantic tokens + System-first + flickering start. Capture contrast, centralize colors, respect 'prefers-color-scheme' and reduce-motion, store user choice and avoid heavy effects. Then UI remains readable and recognizable in any setting - from a night live match to a day box office and tournament screens.

Contact

Get in Touch

Reach out with any questions or support needs.We are always ready to help!

Start Integration

Email is required. Telegram or WhatsApp — optional.

Your Name optional
Email optional
Subject optional
Message optional
Telegram optional
@
If you include Telegram — we will reply there as well, in addition to Email.
WhatsApp optional
Format: +country code and number (e.g., +380XXXXXXXXX).

By clicking this button, you agree to data processing.