Color system and branded palettes
1) Why formalize color
Color is not a set of "good shades," but a manageable system for:- brand awareness and visual consistency,
- readability and availability (WCAG),
- scaling interfaces (themes, platforms, locales),
- predictable A/B experiments (contrast, CTR, errors).
2) System foundations: models and metrics
OKLCH (recommended): perceptually uniform, it is convenient to control the lightness' L'and saturation' C'while maintaining the shade' H '.
Lab/LCH: also fit; OKLCH is more stable in perception.
sRGB: finite display space; totals are always validated in sRGB and WCAG.
Contrast (WCAG 2. 2): base text ≥ 4. 5:1, large ≥ 3:1; critical notifications - aim for AAA (7:1) where possible.
3) Layers of the system: from brand to semantics
1. Brand core: 1-2 branded shades (+ supporting accent).
2. Interface semantics: roles ('primary', 'secondary', 'success', 'warning', 'danger', 'info', 'neutral').
3. Tone scales: lightness steps (e.g. 25/50/100...900).
4. Темы: `light` / `dark` (+ high-contrast, AMOLED).
5. States: 'default/hover/active/focus/disabled'.
6. Context: surfaces ('bg/base', 'bg/subtle', 'bg/elevated') and text ('fg/primary', 'fg/secondary', 'fg/muted').
7. Data visualization: separate discrete and continuous palettes.
4) Brand core: choices and restraints
Select Hue and define the working lightness for the brand in light and dark themes (often 'L≈0. 60–0. 70 'for filling buttons in light and' L≈0. 70–0. 80 'for text/icons in dark).
Limit chrome 'C': high 'C' is beautiful on banners, but breaks readability in UI - keep 2 versions: "marketing" (rich) and "grocery" (more restrained).
Fix the variables: main ('brand/primary'), alternative ('brand/alt') and neutral support ('neutral').
5) Tone scales
The goal is to obtain uniform lightness steps with controlled saturation:- For OKLCH, move the'L'steps (e.g. 0. 98→0. 90→0. 80→…→0. 18), and 'C' slightly reduce to the edges of the scale to avoid "dirt" in light and "turbidity" in dark.
- Fix the checkpoints: '50/100/300/500 (key )/700/900'.
- At each step, check the contrast of the pair with the base background and with the expected text color.
Example of brand/primary scale (OKLCH, approximate)
brand.primary.50 = oklch(0.98 0.03 230)
brand.primary.100 = oklch(0.94 0.05 230)
brand.primary.300 = oklch(0.86 0.08 230)
brand.primary.500 = oklch(0.74 0.10 230) # ключевой тон brand.primary.700 = oklch(0.56 0.09 230)
brand.primary.900 = oklch(0.32 0.07 230)
6) Semantic roles and mapping
Separate brand and semantics: "success" does not have to be brand green.
role.primary.bg -> brand.primary.500 role.primary.text -> fg.on-primary # ≥ 4.5:1 к role.primary.bg role.success.bg -> green.500 role.warning.bg -> amber.500 role.danger.bg -> red.500 role.info.bg -> blue.500 role.neutral.bg -> gray.200/700 (light/dark)
The'on- 'texts are calculated automatically (see § 10).
7) Light/dark themes and surfaces
Define the base scale for surfaces and text:
light:
bg/base = oklch(0.98 0.01 260)
bg/subtle = oklch(0.96 0.01 260)
bg/elevated = oklch(0.93 0.01 260)
fg/primary = oklch(0.18 0.03 260) # ≈7:1 к bg/base fg/secondary = oklch(0.32 0.03 260) # ≥4.5:1 border = oklch(0.80 0.02 260)
dark:
bg/base = oklch(0.16 0.01 260)
bg/subtle = oklch(0.20 0.01 260)
bg/elevated = oklch(0.24 0.01 260)
fg/primary = oklch(0.90 0.02 260)
fg/secondary = oklch(0.78 0.02 260)
border = oklch(0.34 0.02 260)
Maintain equal contrast goals in both themes; avoid "blinding" white on pure black - raise the'L'background to ~ 0. 16.
8) States and interactivity
For each role, set the states to controlled 'Δ L' and 'Δ C':
button/primary:
default.bg = brand.primary.500 hover.bg = brand.primary.500 with +ΔC(0.01) -ΔL(0.02)
active.bg = brand.primary.700 focus.ring = brand.primary.300 # контраст кольца ≥ 3:1 к окружению disabled.bg= neutral.200 (light) / neutral.700 (dark)
text.on = auto-contrast(default.bg) # ≥ 4.5:1
9) Liability and WCAG
The basic text and icons in the controls are ≥ 4. 5:1.
Key system notifications (KYC/AML, 18 +, payment errors) - aim at AAA (7:1).
Field states and boundaries - at least 3:1.
Distinguish links not only by color (underscore/focus-style).
10) Auto-fit contrast text ('on-')
Logic: when selecting the fill of the component, calculate 'on-color':1. According to OKLCH, determine the predlag. text'L _ on'so that' (L_text vs L_bg) ≥ 4. 5:1`.
2. If chromium is high, lower'C _ text'to 0. 01–0. 03.
3. For a dark theme, raise 'L _ on' another 0. 02–0. 04 to offset the glare.
Pseudo token:
fg.on(colorX) = auto(colorX, targetContrast=4.5)
11) Data visualization
Categorical palettes: 8-12 colors resistant to color blindness (avoid red-green pairs without alternative signs).
Continuous: from 'bg/elevated' to accent with contrast control of signatures.
Add patterns/markers for discernibility without color.
12) International context (cultural associations)
Consider local connotations (e.g. red - danger/attention; gold - win/prize).
For iGaming: Avoid success/danger conflicts with branded accents in one screen; iconography and signature are more important than "brightness."
13) Integration into the design system
13. 1 Naming tokens
color.{theme}.{role surface brand}.{state step}
примеры color.light.brand.primary.500 color.dark.role.success.bg color.light.surface.bg.base color.light.fg.on-primary
13. 2 Tokens (JSON/Style Dictionary)
json
{
"color": {
"light": {
"surface": { "bg": { "base": "oklch(0.98 0.01 260)"} },
"brand": { "primary": { "500": "oklch(0.74 0.10 230)" } },
"role": { "primary": { "bg": "{color.light.brand.primary.500}" },
"danger": { "bg": "oklch(0.62 0.12 25)" } },
"fg": { "primary": "oklch(0.18 0.03 260)",
"on-primary": "auto({color.light.role.primary.bg},4.5)" }
}
}
}
13. 3 CSS variables (theme layer)
css
:root[data-theme="light"] {
--bg-base: oklch(0.98 0.01 260);
--brand-primary-500: oklch(0.74 0.10 230);
--fg-primary: oklch(0.18 0.03 260);
--on-primary: color-contrast(var(--brand-primary-500)); / автоподбор /
}
[data-theme="dark"] {
--bg-base: oklch(0.16 0.01 260);
--brand-primary-500: oklch(0.74 0.10 230);
--fg-primary: oklch(0.90 0.02 260);
--on-primary: color-contrast(var(--brand-primary-500));
}
13. 4 Figma/documentation
Components use only tokens, direct HEX/SRGB are prohibited by linters.
In the library - page "Contrast matrix": table 'fg × bg' with actual coefficients.
14) Quality control processes
In design: contrast check on artboards (both modes), separate presets for color blindness.
In code: unit helpers compute contrast and fall in violations; visual snapshots for critical screens.
In CI/CD: checking all pairs of tokens and states, report with component, theme and actual value.
15) The specifics of iGaming
Promos and tournaments: Use the overlay and 'C' constraint on the backgrounds to prevent the text from 'sinking'.
Responsible notifications (limits, 18 +, risks) - sincerely AAA.
Metrics/tables: Distinguish between numbers and signs of changes (↑/↓) by shape and contrast, not just color.
16) Implementation checklist
- Brand shades and their tonal scales (OKLCH) are defined.
- Roles, states, and surfaces are set for the two themes.
- Auto-generation 'on-' with target contrast.
- 'fg × bg' matrix and WCAG tests in CI.
- Individual palettes for dataviz (with color blindness support).
- Linter styles prohibit "raw" colors.
- Exceptions and Reasons page in the guideline.
17) Anti-patterns
Mix brand emphasis with success/error in one UX signal.
Rely only on saturation for hierarchy.
Do not synchronize light/dark (contrast "left" in one of the themes).
Hard HEX without tokens → uncontrolled interface drift.
Brief summary
Build a palette from top to bottom: brand core → semantic roles → tone scales → themes → states. Work in OKLCH, pin tokens, automate'on- 'and WCAG checks. Separately, enter the palettes for dataviz. This will give brand consistency, readability and product scalability.