feat(ui): add security banner markup + styles (approved variant A)

HTML + CSS for the canary leak / ML block banner. Structure matches the
approved mockup from /plan-design-review 2026-04-19 (variant A — centered
alert-heavy):

  * Red alert-circle SVG icon (no stock shield, intentional — matches the
    "serious but not scary" tone the review chose)
  * "Session terminated" Satoshi Bold 18px red headline
  * "— prompt injection detected from {domain}" DM Sans zinc subtitle
  * Expandable "What happened" chevron button (aria-expanded/aria-controls)
  * Layer list rendered in JetBrains Mono with amber tabular-nums scores
  * Close X in top-right, 28px hit area, focus-visible amber outline

Enter animation: slide-down 8px + fade, 250ms, cubic-bezier(0.16,1,0.3,1) —
matches DESIGN.md motion spec. Respects `role="alert"` + `aria-live="assertive"`
so screen readers announce on appearance. Escape-to-dismiss hook is in the
JS follow-up commit.

Design tokens all via CSS variables (--error, --amber-400, --amber-500,
--zinc-*, --font-display, --font-mono, --radius-*) — already established in
the stylesheet. No new color constants introduced.

JS wiring lands in the next commit so this diff stays focused on
presentation layer only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-04-19 19:18:57 +08:00
parent f68fa4a9ee
commit a9f702a715
2 changed files with 158 additions and 0 deletions
+26
View File
@@ -14,6 +14,32 @@
</div>
</div>
<!-- Security event banner — fires on prompt injection detection.
Variant A from /plan-design-review 2026-04-19: centered alert-heavy,
big red error icon, mono layer scores in expandable details. -->
<div class="security-banner" id="security-banner" role="alert" aria-live="assertive" style="display:none">
<button class="security-banner-close" id="security-banner-close" aria-label="Dismiss">&times;</button>
<div class="security-banner-icon" aria-hidden="true">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="12"></line>
<line x1="12" y1="16" x2="12.01" y2="16"></line>
</svg>
</div>
<div class="security-banner-title" id="security-banner-title">Session terminated</div>
<div class="security-banner-subtitle" id="security-banner-subtitle">prompt injection detected</div>
<button class="security-banner-expand" id="security-banner-expand" aria-expanded="false" aria-controls="security-banner-details">
<span>What happened</span>
<svg class="security-banner-chevron" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
<div class="security-banner-details" id="security-banner-details" hidden>
<div class="security-banner-section-label">SECURITY LAYERS</div>
<div class="security-banner-layers" id="security-banner-layers"></div>
</div>
</div>
<!-- Browser tab bar -->
<div class="browser-tabs" id="browser-tabs" style="display:none"></div>