Spaces:
Running
Running
| // First-visit case brief: a one-card overlay on the board that tells a new player | |
| // everything they need — who's dead/wronged, and what to do about it. Shown once per | |
| // case per browser; the full dossier stays one tap away. | |
| import { useState } from 'preact/hooks' | |
| import { useGame } from '../store' | |
| import { hasSeen, markSeen } from '../tips' | |
| import { Btn, Chip, Panel } from './components' | |
| export function CaseBriefOverlay() { | |
| const g = useGame() | |
| const c = g.case | |
| const key = `brief:${c.id}` | |
| const [show, setShow] = useState(() => !hasSeen(key)) | |
| if (!show) return null | |
| const done = () => { | |
| markSeen(key) | |
| setShow(false) | |
| window.dispatchEvent(new Event('cz-brief-done')) | |
| } | |
| return ( | |
| <div class="brief-veil" onClick={done}> | |
| <Panel variant="amber" className="brief-card col" style={{ gap: 12, padding: 18 }} onClick={(e: MouseEvent) => e.stopPropagation()}> | |
| <div class="row between" style={{ alignItems: 'center', gap: 8 }}> | |
| <span class="t-label" style={{ color: 'var(--amber-2)', letterSpacing: '.2em' }}>CASE {c.id}</span> | |
| <Chip variant="ox">{c.kindLabel || 'HOMICIDE'}</Chip> | |
| </div> | |
| <div class="col" style={{ gap: 4 }}> | |
| <span class="t-display" style={{ fontSize: 16, color: 'var(--bone-3)' }}>{c.victim.name}</span> | |
| <span class="t-label">{c.victimStatus || 'DECEASED'} · {c.scene}</span> | |
| </div> | |
| <p class="t-body" style={{ fontSize: 14, lineHeight: 1.5, color: 'var(--bone-2)', margin: 0 }}> | |
| One of them is lying. Question the suspects, present evidence, and make the accusation. | |
| </p> | |
| <div class="col" style={{ gap: 8 }}> | |
| <Btn variant="amber" onClick={done}>▸ Start investigating</Btn> | |
| <Btn variant="ghost" sm onClick={() => { markSeen(key); setShow(false); g.nav('briefing') }}>Read full case file ▸</Btn> | |
| </div> | |
| </Panel> | |
| </div> | |
| ) | |
| } | |