Merge pull request 'лендинг: 32 нарушения контраста WCAG AA — затемнены токены, поставлен сторож' (#3277) from fix/mera-public-contrast into main
Some checks failed
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 18s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m18s
Deploy Trade-In / test (push) Successful in 4m20s
Deploy Trade-In / build-backend (push) Successful in 1m8s
Deploy Trade-In / deploy (push) Has been cancelled
Some checks failed
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 18s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m18s
Deploy Trade-In / test (push) Successful in 4m20s
Deploy Trade-In / build-backend (push) Successful in 1m8s
Deploy Trade-In / deploy (push) Has been cancelled
This commit is contained in:
commit
53a1b9ba89
3 changed files with 201 additions and 23 deletions
|
|
@ -0,0 +1,152 @@
|
||||||
|
/**
|
||||||
|
* contrast-tokens — контраст WCAG 2.1 AA прямо на ЗНАЧЕНИЯХ токенов `b2c`,
|
||||||
|
* без браузера и без axe.
|
||||||
|
*
|
||||||
|
* Зачем. 30.08.2026 axe нашёл на публичном лэндинге 32 узла `color-contrast`
|
||||||
|
* (все severity=serious), и все они — следствие одного и того же: пара
|
||||||
|
* «цвет × фон» подбиралась глазами, а число в комментарии писалось по памяти.
|
||||||
|
* Шапка `b2c-tokens.ts` утверждала «onAccent на accentDeep — 4.6:1», реальный
|
||||||
|
* замер — 4.41, то есть главная кнопка призыва не проходила AA, а
|
||||||
|
* документация уверяла, что проходит. Браузерный аудит ловит это раз в
|
||||||
|
* квартал; здесь то же самое считается на каждом прогоне тестов.
|
||||||
|
*
|
||||||
|
* Проверяются ОБА фона страницы: светлый (`pageBg`/`surface`/`surfaceSoft`) и
|
||||||
|
* тёмная плашка (`surfaceDark`). Половина из 32 нарушений была именно светлым
|
||||||
|
* токеном, положенным на тёмную плашку, — на ней шкала перевёрнута.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { join } from "node:path";
|
||||||
|
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { b2c } from "../b2c-tokens";
|
||||||
|
|
||||||
|
/** Относительная яркость по WCAG 2.1 (§ relative luminance). */
|
||||||
|
function luminance(hex: string): number {
|
||||||
|
const h = hex.replace("#", "");
|
||||||
|
const channels = [0, 2, 4]
|
||||||
|
.map((i) => parseInt(h.slice(i, i + 2), 16) / 255)
|
||||||
|
.map((v) => (v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4));
|
||||||
|
return (
|
||||||
|
0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Контраст пары цветов по WCAG 2.1 (§ contrast ratio). */
|
||||||
|
export function contrast(fg: string, bg: string): number {
|
||||||
|
const a = luminance(fg);
|
||||||
|
const b = luminance(bg);
|
||||||
|
return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Норма AA для обычного текста. Крупный (≥24px / ≥18.66px bold) — 3.0. */
|
||||||
|
const AA_NORMAL = 4.5;
|
||||||
|
|
||||||
|
/** Светлые фоны лэндинга. Худший из них — `surfaceSoft`, он темнее `pageBg`. */
|
||||||
|
const LIGHT_BACKGROUNDS: ReadonlyArray<readonly [string, string]> = [
|
||||||
|
["surface", b2c.surface],
|
||||||
|
["pageBg", b2c.pageBg],
|
||||||
|
["surfaceSoft", b2c.surfaceSoft],
|
||||||
|
];
|
||||||
|
|
||||||
|
describe("контраст токенов b2c", () => {
|
||||||
|
it("формула считает эталонные пары верно", () => {
|
||||||
|
// Реперы: чёрное на белом — 21:1, цвет сам на себе — 1:1.
|
||||||
|
expect(contrast("#000000", "#FFFFFF")).toBeCloseTo(21, 1);
|
||||||
|
expect(contrast("#0E8496", "#0E8496")).toBeCloseTo(1, 5);
|
||||||
|
// Прежнее значение accentDeep — то самое 4.41, из-за которого кнопка
|
||||||
|
// призыва попала в отчёт axe. Если формула сломается, репер покажет это.
|
||||||
|
expect(contrast("#FFFFFF", "#0E8496")).toBeCloseTo(4.41, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("текстовые токены проходят AA на всех светлых фонах", () => {
|
||||||
|
const textTokens: ReadonlyArray<readonly [string, string]> = [
|
||||||
|
["ink", b2c.ink],
|
||||||
|
["muted", b2c.muted],
|
||||||
|
["accentText", b2c.accentText],
|
||||||
|
["success", b2c.success],
|
||||||
|
["danger", b2c.danger],
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [fgName, fg] of textTokens) {
|
||||||
|
for (const [bgName, bg] of LIGHT_BACKGROUNDS) {
|
||||||
|
expect(
|
||||||
|
contrast(fg, bg),
|
||||||
|
`${fgName} на ${bgName}`,
|
||||||
|
).toBeGreaterThanOrEqual(AA_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("белый текст на заливке кнопки проходит AA", () => {
|
||||||
|
// .heroSubmitBtn, .hdrCta, .gameBtnAccent — сплошная заливка accentDeep.
|
||||||
|
expect(contrast(b2c.onAccent, b2c.accentDeep)).toBeGreaterThanOrEqual(
|
||||||
|
AA_NORMAL,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("на тёмной плашке текст красится mutedDark/accent, а не muted/accentText", () => {
|
||||||
|
// Что ГОДИТСЯ на surfaceDark.
|
||||||
|
expect(contrast(b2c.mutedDark, b2c.surfaceDark)).toBeGreaterThanOrEqual(
|
||||||
|
AA_NORMAL,
|
||||||
|
);
|
||||||
|
expect(contrast(b2c.accent, b2c.surfaceDark)).toBeGreaterThanOrEqual(
|
||||||
|
AA_NORMAL,
|
||||||
|
);
|
||||||
|
expect(contrast(b2c.onAccent, b2c.surfaceDark)).toBeGreaterThanOrEqual(
|
||||||
|
AA_NORMAL,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Что НЕ годится — это и были метки тикера (2.85 и 2.7). Ассерт держит
|
||||||
|
// правило «на тёмном берём светлый конец шкалы»: если кто-то осветлит
|
||||||
|
// muted до проходного на плашке, он сломает его же на светлом фоне, и
|
||||||
|
// предыдущий тест покраснеет.
|
||||||
|
expect(contrast(b2c.muted, b2c.surfaceDark)).toBeLessThan(AA_NORMAL);
|
||||||
|
expect(contrast(b2c.accentText, b2c.surfaceDark)).toBeLessThan(AA_NORMAL);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("accent не используется как текст на светлом: он и не может", () => {
|
||||||
|
// Ради этого в палитре и живёт отдельный accentText. Ассерт фиксирует
|
||||||
|
// причину, чтобы «упростить до одного акцента» нельзя было молча.
|
||||||
|
expect(contrast(b2c.accent, b2c.surface)).toBeLessThan(AA_NORMAL);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тест выше защищает ЗНАЧЕНИЯ токенов — но не поймал бы `color: #9fb0b4`,
|
||||||
|
* вписанный в CSS мимо палитры. Именно так и появились .artSoon (2.24),
|
||||||
|
* .gameScale, .repPaidFine, .artFootnote: сырой hex не проходит ни через
|
||||||
|
* какой аудит, потому что его никто не считает токеном.
|
||||||
|
*
|
||||||
|
* ponytail: список разрешённых — снимок, а не расчёт: по CSS нельзя узнать,
|
||||||
|
* на какой подложке лежит правило (#ffffff годится на плашке и провален на
|
||||||
|
* карточке). Когда фон станет выводим (напр. все тёмные секции получат
|
||||||
|
* общий класс), эту тройку можно заменить настоящим расчётом.
|
||||||
|
*/
|
||||||
|
it("в CSS лэндинга нет новых сырых hex-цветов текста", () => {
|
||||||
|
const css = readFileSync(
|
||||||
|
join(__dirname, "..", "landing-v3.module.css"),
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
const found = [
|
||||||
|
...css.matchAll(/(?:color|fill):\s*(#[0-9a-fA-F]{3,8})\b/g),
|
||||||
|
].map((m) => m[1].toLowerCase());
|
||||||
|
|
||||||
|
const allowed = new Set([
|
||||||
|
"#ffffff", // текст на surfaceDark-плашках, 17:1
|
||||||
|
"#3fd1a6", // .tickerGain на плашке, 9.1:1
|
||||||
|
"#3a4a4f", // .gameVerdict на светлой карточке, 9.2:1
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect([...new Set(found)].filter((h) => !allowed.has(h))).toEqual([]);
|
||||||
|
// Сам сканер проверен: он обязан находить hex вообще.
|
||||||
|
expect(found.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("декоративные линии различимы как границы (норма 3.0 не для них)", () => {
|
||||||
|
// Границы — не текст, AA к ним не применяется; проверяем лишь, что они
|
||||||
|
// вообще отличаются от своей подложки, иначе рамка невидима.
|
||||||
|
expect(contrast(b2c.line, b2c.surface)).toBeGreaterThan(1.2);
|
||||||
|
expect(contrast(b2c.lineDark, b2c.surfaceDark)).toBeGreaterThan(1.2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -22,10 +22,30 @@
|
||||||
* старом theme.ts было для #2e8bff);
|
* старом theme.ts было для #2e8bff);
|
||||||
* - `accentText` (#0B6B79) — тот же оттенок, затемнённый до **5.8:1** на
|
* - `accentText` (#0B6B79) — тот же оттенок, затемнённый до **5.8:1** на
|
||||||
* фоне страницы; им красится текст ссылок и акцентные подписи;
|
* фоне страницы; им красится текст ссылок и акцентные подписи;
|
||||||
* - `onAccent` (#FFFFFF) на заливке `accentDeep` (#0E8496) — 4.6:1, годится
|
* - `onAccent` (#FFFFFF) на заливке `accentDeep` (#0C7B8B) — 4.97:1, годится
|
||||||
* для текста кнопок.
|
* для текста кнопок.
|
||||||
* Визуально разница между #16A9BC и #0B6B79 в тонкой ссылке незаметна, а
|
* Визуально разница между #16A9BC и #0B6B79 в тонкой ссылке незаметна, а
|
||||||
* читаемость меняется принципиально.
|
* читаемость меняется принципиально.
|
||||||
|
*
|
||||||
|
* ПРАВКА 30.08.2026 (axe: 32 узла `color-contrast`, все serious). Прежние
|
||||||
|
* значения считались «по ощущению», и четыре из них не добирали до 4.5 — а
|
||||||
|
* подписанное в этой шапке «4.6:1» для `accentDeep` #0E8496 было просто
|
||||||
|
* неверным замером: реально **4.41**. Затемнены до запаса ≥4.8 на худшем
|
||||||
|
* светлом фоне (`surfaceSoft` #EAF5F7 — он темнее `pageBg`):
|
||||||
|
* accentDeep #0E8496 → #0C7B8B (белый текст 4.41 → 4.97)
|
||||||
|
* muted #667579 → #5B686C (на pageBg 4.45 → 5.36)
|
||||||
|
* success #1B8A5A → #177A50 (на pageBg 4.04 → 4.96)
|
||||||
|
* danger #C0442E → #B33D28 (на surfaceSoft 4.60 → 5.23)
|
||||||
|
*
|
||||||
|
* ТЁМНАЯ ПЛАШКА (`surfaceDark` #121A1D) — второй «фон-тема» этой страницы, и
|
||||||
|
* правила там ПЕРЕВЁРНУТЫ: `muted` там 2.7:1, `accentText` — 2.85:1. На тёмном
|
||||||
|
* текст красится `mutedDark` (6.2:1) и `accent` (6.24:1), т.е. светлым концом
|
||||||
|
* шкалы. Отсюда: перед тем как взять токен для текста, смотри, на ЧЁМ он
|
||||||
|
* лежит — половина из 32 нарушений была именно светлым токеном на тёмной
|
||||||
|
* плашке.
|
||||||
|
*
|
||||||
|
* Числа проверяются тестом `__tests__/contrast-tokens.test.ts` — он считает
|
||||||
|
* яркость по формуле WCAG прямо на значениях отсюда, без браузера.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const b2c = {
|
export const b2c = {
|
||||||
|
|
@ -41,7 +61,7 @@ export const b2c = {
|
||||||
/** Основной текст. */
|
/** Основной текст. */
|
||||||
ink: "#121A1D",
|
ink: "#121A1D",
|
||||||
/** Вторичный текст, подписи. */
|
/** Вторичный текст, подписи. */
|
||||||
muted: "#667579",
|
muted: "#5B686C",
|
||||||
|
|
||||||
/** Границы, разделители. */
|
/** Границы, разделители. */
|
||||||
line: "#CBD7DA",
|
line: "#CBD7DA",
|
||||||
|
|
@ -73,16 +93,16 @@ export const b2c = {
|
||||||
/** Акцент — заливки/обводки/декор. НЕ для текста, см. шапку. */
|
/** Акцент — заливки/обводки/декор. НЕ для текста, см. шапку. */
|
||||||
accent: "#16A9BC",
|
accent: "#16A9BC",
|
||||||
/** Акцент для заливки кнопок (под белым текстом). */
|
/** Акцент для заливки кнопок (под белым текстом). */
|
||||||
accentDeep: "#0E8496",
|
accentDeep: "#0C7B8B",
|
||||||
/** Акцент для ТЕКСТА — затемнён до AA. */
|
/** Акцент для ТЕКСТА — затемнён до AA. */
|
||||||
accentText: "#0B6B79",
|
accentText: "#0B6B79",
|
||||||
/** Текст на акцентной заливке. */
|
/** Текст на акцентной заливке. */
|
||||||
onAccent: "#FFFFFF",
|
onAccent: "#FFFFFF",
|
||||||
|
|
||||||
/** Положительная дельта («выше средней цены»). */
|
/** Положительная дельта («выше средней цены»). */
|
||||||
success: "#1B8A5A",
|
success: "#177A50",
|
||||||
/** Отрицательная дельта, предупреждения. */
|
/** Отрицательная дельта, предупреждения. */
|
||||||
danger: "#C0442E",
|
danger: "#B33D28",
|
||||||
|
|
||||||
font: {
|
font: {
|
||||||
sans: "var(--font-manrope), 'Manrope', system-ui, sans-serif",
|
sans: "var(--font-manrope), 'Manrope', system-ui, sans-serif",
|
||||||
|
|
|
||||||
|
|
@ -635,8 +635,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroSubmitBtn {
|
.heroSubmitBtn {
|
||||||
/* accentDeep, не accent: белый текст на #16A9BC даёт ~2.8:1 (провал AA),
|
/* accentDeep, не accent: белый текст на #16A9BC даёт 2.82:1 (провал AA), на
|
||||||
на accentDeep — см. обоснование в b2c-tokens.ts. Затемнение на hover —
|
accentDeep — 4.97:1 после затемнения токена 30.08 (до него было 4.41, и
|
||||||
|
axe считал главную кнопку призыва нарушением). См. b2c-tokens.ts.
|
||||||
|
Затемнение на hover —
|
||||||
через filter, чтобы не заводить ещё один цветовой литерал (тот же приём,
|
через filter, чтобы не заводить ещё один цветовой литерал (тот же приём,
|
||||||
что в .hdrCta выше). */
|
что в .hdrCta выше). */
|
||||||
background: var(--b2c-accent-deep);
|
background: var(--b2c-accent-deep);
|
||||||
|
|
@ -1438,7 +1440,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
padding: 0 30px;
|
padding: 0 30px;
|
||||||
border-right: 1px solid #2c3a3f;
|
border-right: 1px solid var(--b2c-line-dark);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.tickerObj {
|
.tickerObj {
|
||||||
|
|
@ -1451,23 +1453,27 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
/* Лента лежит на `surface-dark`, поэтому светлые токены здесь МЕНЯЮТСЯ
|
||||||
|
МЕСТАМИ со светлой темой: `muted` даёт на плашке 2.7:1, `accent-text` —
|
||||||
|
2.85:1 (замер axe 30.08: обе метки в списке из 32 нарушений). На тёмном
|
||||||
|
читаются `muted-dark` (6.2:1) и сам `accent` (6.24:1). */
|
||||||
.tickerLabelMuted {
|
.tickerLabelMuted {
|
||||||
font-family: var(--b2c-font-mono);
|
font-family: var(--b2c-font-mono);
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
letter-spacing: 0.12em;
|
letter-spacing: 0.12em;
|
||||||
color: var(--b2c-muted);
|
color: var(--b2c-muted-dark);
|
||||||
}
|
}
|
||||||
.tickerLabelAccent {
|
.tickerLabelAccent {
|
||||||
composes: tickerLabelMuted;
|
composes: tickerLabelMuted;
|
||||||
color: var(--b2c-accent-text);
|
color: var(--b2c-accent);
|
||||||
}
|
}
|
||||||
.tickerSaid {
|
.tickerSaid {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted-dark);
|
||||||
}
|
}
|
||||||
.tickerArrow {
|
.tickerArrow {
|
||||||
color: #2c3a3f;
|
color: var(--b2c-muted-dark);
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
.tickerFact {
|
.tickerFact {
|
||||||
|
|
@ -1478,7 +1484,7 @@
|
||||||
.tickerErr {
|
.tickerErr {
|
||||||
font-family: var(--b2c-font-mono);
|
font-family: var(--b2c-font-mono);
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted-dark);
|
||||||
}
|
}
|
||||||
.tickerGain {
|
.tickerGain {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -1654,7 +1660,7 @@
|
||||||
.gameMeta {
|
.gameMeta {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted-dark);
|
||||||
}
|
}
|
||||||
.gameTags {
|
.gameTags {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -1665,7 +1671,7 @@
|
||||||
.gameTag {
|
.gameTag {
|
||||||
font-family: var(--b2c-font-mono);
|
font-family: var(--b2c-font-mono);
|
||||||
font-size: 10.5px;
|
font-size: 10.5px;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted-dark);
|
||||||
border: 1px solid var(--b2c-line-dark);
|
border: 1px solid var(--b2c-line-dark);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
|
|
@ -1739,7 +1745,7 @@
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
font-family: var(--b2c-font-mono);
|
font-family: var(--b2c-font-mono);
|
||||||
font-size: 10.5px;
|
font-size: 10.5px;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted);
|
||||||
}
|
}
|
||||||
.gameBtnAccent {
|
.gameBtnAccent {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
@ -1809,7 +1815,7 @@
|
||||||
}
|
}
|
||||||
.gameRowLabelMuted {
|
.gameRowLabelMuted {
|
||||||
composes: gameRowLabel;
|
composes: gameRowLabel;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted-dark);
|
||||||
}
|
}
|
||||||
.gameRowValue {
|
.gameRowValue {
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
|
|
@ -1936,7 +1942,7 @@
|
||||||
}
|
}
|
||||||
.pathBodyDark {
|
.pathBodyDark {
|
||||||
composes: pathBody;
|
composes: pathBody;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted-dark);
|
||||||
}
|
}
|
||||||
.pathBtnLight {
|
.pathBtnLight {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
@ -2368,7 +2374,7 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Раздел статей и хаб документов (макет 29.08) ------------------------- */
|
/* --- Раздел статей и хаб документов (макет 29.08) ------------------------- */
|
||||||
|
|
@ -2422,7 +2428,7 @@
|
||||||
font-family: var(--b2c-font-mono);
|
font-family: var(--b2c-font-mono);
|
||||||
font-size: 9.5px;
|
font-size: 9.5px;
|
||||||
letter-spacing: 0.16em;
|
letter-spacing: 0.16em;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted);
|
||||||
}
|
}
|
||||||
.artToc {
|
.artToc {
|
||||||
margin-bottom: clamp(24px, 3vw, 32px);
|
margin-bottom: clamp(24px, 3vw, 32px);
|
||||||
|
|
@ -2463,7 +2469,7 @@
|
||||||
margin: 0 0 16px;
|
margin: 0 0 16px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
color: #2c3a3f;
|
color: var(--b2c-line-dark);
|
||||||
text-wrap: pretty;
|
text-wrap: pretty;
|
||||||
}
|
}
|
||||||
.artH2 {
|
.artH2 {
|
||||||
|
|
@ -2565,7 +2571,7 @@
|
||||||
font-family: var(--b2c-font-mono);
|
font-family: var(--b2c-font-mono);
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted);
|
||||||
}
|
}
|
||||||
.artTiles {
|
.artTiles {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
@ -2614,7 +2620,7 @@
|
||||||
margin: 0 0 20px;
|
margin: 0 0 20px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
color: #9fb0b4;
|
color: var(--b2c-muted-dark);
|
||||||
max-width: 520px;
|
max-width: 520px;
|
||||||
}
|
}
|
||||||
.artCta .gameBtnAccent {
|
.artCta .gameBtnAccent {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue