102 lines
4.1 KiB
Plaintext
102 lines
4.1 KiB
Plaintext
/**
|
|
* styles/tokens/_states.less
|
|
*
|
|
* Layer 2 — SP Participant State Tokens
|
|
*
|
|
* All 8 participant states + 1 pending state (9 total).
|
|
* Each state provides three CSS custom properties:
|
|
* --sp-state-{name}-text — foreground / icon colour
|
|
* --sp-state-{name}-border — ring / border colour
|
|
* --sp-state-{name}-bg — background tint colour
|
|
*
|
|
* SECOND-SIGNAL RULE (WCAG):
|
|
* Every state conveys meaning via THREE independent channels:
|
|
* colour + icon (Font Awesome codepoint) + shape (ring variant).
|
|
* States marked ⚠️ below have low contrast ratios and MUST NOT
|
|
* appear as text or small-pill foreground — icon + shape carry the signal.
|
|
*
|
|
* State precedence (VisibilityManager/RoleRenderer resolves; CSS never handles multi-state):
|
|
* pending > cam-lost > reconnecting > offline > never-connected > self-muted > hidden > ghost > active
|
|
*
|
|
* LESS state map — single source of truth for loop-generated component CSS.
|
|
*/
|
|
|
|
/* ─── State colour variables ─────────────────────────────────────────────── */
|
|
|
|
:root {
|
|
/* active — Intentional / positive */
|
|
/* ✅ WCAG AA safe */
|
|
--sp-state-active-text: #4a9e6b;
|
|
--sp-state-active-border: #4a9e6b;
|
|
--sp-state-active-bg: rgba(74, 158, 107, 0.12);
|
|
|
|
/* hidden — Intentional / deliberate (GM action) */
|
|
/* ⚠️ Low contrast (~3.75:1) — icon + dashed ring carry the signal */
|
|
--sp-state-hidden-text: #6b7280;
|
|
--sp-state-hidden-border: #6b7280;
|
|
--sp-state-hidden-bg: rgba(107, 114, 128, 0.10);
|
|
|
|
/* self-muted — Self / player's own choice */
|
|
/* ✅ WCAG AA safe */
|
|
--sp-state-self-muted-text: #8b92a5;
|
|
--sp-state-self-muted-border: #8b92a5;
|
|
--sp-state-self-muted-bg: rgba(139, 146, 165, 0.10);
|
|
|
|
/* offline — Technical / disconnected */
|
|
/* ⚠️ Low contrast (~2.4:1) — icon + no-ring shape carry the signal */
|
|
--sp-state-offline-text: #4b5563;
|
|
--sp-state-offline-border: #4b5563;
|
|
--sp-state-offline-bg: rgba(75, 85, 99, 0.08);
|
|
|
|
/* cam-lost — Technical / camera failure */
|
|
/* ✅ WCAG AA safe */
|
|
--sp-state-cam-lost-text: #9ca3af;
|
|
--sp-state-cam-lost-border: #9ca3af;
|
|
--sp-state-cam-lost-bg: rgba(156, 163, 175, 0.10);
|
|
|
|
/* reconnecting — Technical / in-progress */
|
|
/* ✅ WCAG AA safe */
|
|
--sp-state-reconnecting-text: #c8982a;
|
|
--sp-state-reconnecting-border: #c8982a;
|
|
--sp-state-reconnecting-bg: rgba(200, 152, 42, 0.12);
|
|
|
|
/* never-connected — Passive / never joined */
|
|
/* ⚠️ Low contrast (~1.76:1) — empty circle + no icon carries the signal */
|
|
--sp-state-never-connected-text: #374151;
|
|
--sp-state-never-connected-border: #374151;
|
|
--sp-state-never-connected-bg: rgba(55, 65, 81, 0.06);
|
|
|
|
/* ghost — Passive / placeholder slot */
|
|
/* ⚠️ Very low contrast (~1.24:1) — ghost icon + dotted ring, lowest opacity */
|
|
--sp-state-ghost-text: #1f2937;
|
|
--sp-state-ghost-border: #1f2937;
|
|
--sp-state-ghost-bg: rgba(31, 41, 55, 0.04);
|
|
|
|
/* pending — Optimistic UI in-flight (transient; never persisted) */
|
|
--sp-state-pending-text: #7a8390;
|
|
--sp-state-pending-border: #7a8390;
|
|
--sp-state-pending-bg: rgba(122, 131, 144, 0.10);
|
|
}
|
|
|
|
/* ─── Font Awesome icon codepoints (used in component CSS via content: "\f...") ── */
|
|
/*
|
|
active: '\f06e' (eye)
|
|
hidden: '\f070' (eye-slash)
|
|
self-muted: '\f131' (microphone-slash)
|
|
offline: '\f00d' (times / user-slash)
|
|
cam-lost: '\f03d' (video-slash / film)
|
|
reconnecting: '\f021' (sync/spinner)
|
|
never-connected: '\f068' (minus / em-dash)
|
|
ghost: '\f2be' (ghost / user-secret)
|
|
pending: '\f110' (spinner)
|
|
*/
|
|
|
|
/* ─── State ring shape variants (applied via sp-state-ring--* modifier) ──── */
|
|
/*
|
|
solid → active, self-muted
|
|
dashed → hidden, cam-lost
|
|
pulse → reconnecting, pending (animation in _motion.less)
|
|
dotted → ghost
|
|
none → offline, never-connected
|
|
*/
|