fix(frontend): post-design-review — slab token split + badge contrast + modal backdrop + dark shadows
- Add fixed slab/slab-text/slab-muted tokens so utility strip and footer never invert to near-white in dark mode (root token split: ink is themed text, slab is fixed dark surface) - btn-ink uses fixed #111827 so confirm dialogs stay dark-on-dark readable - Toast error surface switched to slab; success uses text-white (not text-ink-on) - StatusBadge active and SimulationStatusBadge review_required/done use text-white instead of text-canvas/text-ink-on (prevents near-black text on colored pill in dark mode) - Modal backdrops (MitreMatrixModal, ConfirmDialog) switched to .modal-backdrop class (fixed rgba(0,0,0,0.6)) instead of bg-ink/60 which turned near-white - Card shadow lifted in dark mode via .dark .card-product override - MitreMatrixModal panel uses shadow-floating-dark in dark mode - UsersAdminPage form: items-start + explicit label-height spacer on button column for pixel-perfect baseline alignment (AC-17.3 structural fix) 92/92 tests passing, typecheck and lint clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,7 @@ export function ConfirmDialog({
|
||||
aria-labelledby="confirm-dialog-title"
|
||||
className="fixed inset-0 z-50 flex items-center justify-center"
|
||||
>
|
||||
<div className="absolute inset-0 bg-ink/40" onClick={onCancel} aria-hidden="true" />
|
||||
<div className="modal-backdrop absolute inset-0" onClick={onCancel} aria-hidden="true" />
|
||||
<div className="relative card-product shadow-floating max-w-sm w-full mx-md flex flex-col gap-md">
|
||||
<h2 id="confirm-dialog-title" className="text-[20px] font-medium text-ink">
|
||||
{title}
|
||||
|
||||
@@ -28,13 +28,13 @@ export function Layout(): JSX.Element {
|
||||
|
||||
return (
|
||||
<div className="min-h-full flex flex-col bg-canvas">
|
||||
{/* utility-strip — ink slab, fine print */}
|
||||
<div className="bg-ink text-white text-[14px] h-9 flex items-center">
|
||||
{/* utility-strip — fixed dark slab, never inverts */}
|
||||
<div className="bg-slab text-slab-text text-[14px] h-9 flex items-center">
|
||||
<div className="mx-auto w-full max-w-page px-xl flex items-center justify-between">
|
||||
<span className="font-medium tracking-[0.5px] uppercase">Mimic · Purple Team BAS</span>
|
||||
{user ? (
|
||||
<div className="flex items-center gap-md">
|
||||
<span className="text-[12px] uppercase tracking-[0.5px] text-steel">
|
||||
<span className="text-[12px] uppercase tracking-[0.5px] text-slab-muted">
|
||||
{user.role}
|
||||
</span>
|
||||
<span className="text-[14px]">{user.username}</span>
|
||||
@@ -42,7 +42,7 @@ export function Layout(): JSX.Element {
|
||||
type="button"
|
||||
onClick={cycleTheme}
|
||||
aria-label={`Theme: ${themeLabel(theme)} — click to cycle`}
|
||||
className="flex items-center gap-xxs text-[12px] text-steel hover:text-white transition-colors"
|
||||
className="flex items-center gap-xxs text-[12px] text-slab-muted hover:text-slab-text transition-colors"
|
||||
>
|
||||
<ThemeIcon theme={theme} />
|
||||
<span className="uppercase tracking-[0.5px]">{themeLabel(theme)}</span>
|
||||
@@ -101,9 +101,9 @@ export function Layout(): JSX.Element {
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* footer — ink slab close */}
|
||||
<footer className="bg-ink text-white">
|
||||
<div className="mx-auto w-full max-w-page px-xl py-xl text-[12px] text-steel">
|
||||
{/* footer — fixed dark slab, never inverts */}
|
||||
<footer className="bg-slab text-slab-text">
|
||||
<div className="mx-auto w-full max-w-page px-xl py-xl text-[12px] text-slab-muted">
|
||||
Mimic — Internal Purple Team tooling. Authorized engagements only.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -163,14 +163,14 @@ export function MitreMatrixModal({
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||
<div className="absolute inset-0 bg-ink/60" onClick={onCancel} aria-hidden="true" />
|
||||
<div className="modal-backdrop absolute inset-0" onClick={onCancel} aria-hidden="true" />
|
||||
|
||||
<div
|
||||
ref={containerRef}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="matrix-modal-title"
|
||||
className="relative bg-canvas rounded-xl shadow-floating max-w-[98vw] max-h-[80vh] overflow-hidden flex flex-col"
|
||||
className="relative bg-canvas rounded-xl shadow-floating dark:shadow-floating-dark max-w-[98vw] max-h-[80vh] overflow-hidden flex flex-col"
|
||||
style={{ width: '1400px' }}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
|
||||
@@ -7,12 +7,13 @@ const LABELS: Record<SimulationStatus, string> = {
|
||||
done: 'Done',
|
||||
};
|
||||
|
||||
// pending=fog, in_progress=primary-soft, review_required=bloom-coral, done=storm-deep
|
||||
// Fixed colors — badge backgrounds are decorative/semantic, not themeable.
|
||||
// text-white is hardcoded (not text-canvas) so dark mode doesn't invert it to near-black.
|
||||
const STYLES: Record<SimulationStatus, string> = {
|
||||
pending: 'bg-fog text-charcoal border border-hairline',
|
||||
in_progress: 'bg-primary-soft text-primary-deep',
|
||||
review_required: 'bg-bloom-coral text-canvas',
|
||||
done: 'bg-storm-deep text-canvas',
|
||||
review_required: 'bg-bloom-coral text-white',
|
||||
done: 'bg-storm-deep text-white',
|
||||
};
|
||||
|
||||
export function SimulationStatusBadge({ status }: { status: SimulationStatus }): JSX.Element {
|
||||
|
||||
@@ -10,7 +10,7 @@ const STYLES: Record<EngagementStatus, string> = {
|
||||
// Outlined ink for planned (neutral), filled primary for active (engagement live),
|
||||
// outlined steel for closed (muted). Stays within DESIGN.md palette.
|
||||
planned: 'bg-canvas text-ink border border-ink',
|
||||
active: 'bg-primary text-ink-on',
|
||||
active: 'bg-primary text-white',
|
||||
closed: 'bg-cloud text-graphite border border-hairline',
|
||||
};
|
||||
|
||||
|
||||
@@ -15,10 +15,11 @@ export function ToastViewport(): JSX.Element {
|
||||
{toasts.map((t) => {
|
||||
const isError = t.kind === 'error';
|
||||
const isSuccess = t.kind === 'success';
|
||||
// Fixed colors: toasts don't theme (error=dark slab, success=primary blue)
|
||||
const surface = isError
|
||||
? 'bg-ink text-ink-on'
|
||||
? 'bg-slab text-slab-text'
|
||||
: isSuccess
|
||||
? 'bg-primary text-ink-on'
|
||||
? 'bg-primary text-white'
|
||||
: 'bg-canvas text-ink border border-hairline';
|
||||
return (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user