/** * 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 */