Spec
Intent
When something fires, an operator needs the four facts in under a second: how bad, what now, who owns it, how long it's been bleeding. Anything else is a distraction.
Acceptance Criteria
[ ] Severity colour bar on leading edge
[ ] Status pill (OPEN / TRIAGE / RESOLVED)
[ ] Owner avatar + name
[ ] Time-to-resolve clock, monotonic
Constraints
Looks legible on a wall display from 2m
≤ 4 lines of body text
Respects prefers-reduced-motion
// incident-ticket.astro copy
---
import type { CompendiumMeta } from '../../../data/types';
export const meta: CompendiumMeta = {
id: 45,
slug: 'incident-ticket',
name: 'Incident Ticket',
category: 'governance-risk',
subcategory: 'audits-and-logs',
pillar: 'go',
description: 'A condensed incident card — severity, status, owner, time-to-resolve — for the NOC wall.',
spec: `## Intent
When something fires, an operator needs the four facts in under a second: how bad, what now, who owns it, how long it's been bleeding. Anything else is a distraction.
## Acceptance Criteria
- [ ] Severity colour bar on leading edge
- [ ] Status pill (OPEN / TRIAGE / RESOLVED)
- [ ] Owner avatar + name
- [ ] Time-to-resolve clock, monotonic
## Constraints
- Looks legible on a wall display from 2m
- ≤ 4 lines of body text
- Respects prefers-reduced-motion`,
tags: ['card', 'badge', 'animated', 'reduced-motion', 'real-content', 'dark-mode-tested'],
status: 'stable',
health: { ics: 86, a11y: 'aa', themed: true, animated: true },
};
const ticket = {
id: 'INC-1842',
title: 'Agent-7 exceeded autonomy ceiling on SPEC-204',
severity: 'SEV-1',
status: 'TRIAGE',
owner: 'The Governor',
ownerInit: 'TZ',
age: '00:14:32',
sevTone: 'bg-danger',
statusTone: 'bg-attention',
};
---
<div data-this-component class="w-full bg-paper text-black border-4 border-black relative flex overflow-hidden" style="box-shadow: 4px 4px 0 0 var(--color-ink);">
<div class:list={['w-2', ticket.sevTone]} aria-hidden="true"></div>
<div class="flex-1 p-3 min-w-0">
<div class="flex items-baseline gap-2 flex-wrap">
<span class:list={['px-1.5 py-0.5 border-2 border-black text-white font-black text-[10px] uppercase tracking-widest', ticket.sevTone]}>{ticket.severity}</span>
<span class:list={['px-1.5 py-0.5 border-2 border-black text-white font-black text-[10px] uppercase tracking-widest', ticket.statusTone]}>{ticket.status}</span>
<span class="font-mono text-[10px] uppercase tracking-widest opacity-70 ms-auto tabular-nums">{ticket.id}</span>
</div>
<p class="mt-2 font-black text-sm leading-tight">{ticket.title}</p>
<div class="mt-3 flex items-center gap-2 pt-2 border-t-2 border-black">
<div class="w-7 h-7 border-2 border-black bg-co flex items-center justify-center shrink-0">
<span class="font-black text-[10px] text-black">{ticket.ownerInit}</span>
</div>
<div class="min-w-0 flex-1">
<p class="font-mono text-[10px] uppercase tracking-widest opacity-70 leading-none">Owner</p>
<p class="font-black text-[11px] leading-tight truncate">{ticket.owner}</p>
</div>
<div class="text-end shrink-0">
<p class="font-mono text-[10px] uppercase tracking-widest opacity-70 leading-none">TTR</p>
<p class="font-black text-sm leading-tight inc-clock tabular-nums">{ticket.age}</p>
</div>
</div>
</div>
</div>
<style>
[data-this-component] .inc-clock {
animation: inc-blink 2000ms steps(2) infinite;
}
@keyframes inc-blink {
50% { opacity: 0.55; }
}
@media (prefers-reduced-motion: reduce) {
[data-this-component] .inc-clock {
animation: none;
}
}
</style>