feat: Quiet Confidence UI redesign — teal brand, Geist typography#3
Merged
Conversation
…ography Complete visual overhaul of popup, options, warning modal, and blocked page following Gemini-reviewed "Quiet Confidence" design direction. ## Design system - Brand: warm phosphor green #00e599 → desaturated teal #1a9b8c (distinctive) - Danger: #ff3b5c → #dc2626 (more serious, less Tailwind-default) - Warn: #ffaa2c → #f59e0b - Background: 4-layer elevation stack (#0a0a0b → #141416 → #1c1c1f → #222226) - Text: hierarchy via weight+size, WCAG AA compliant (--text-dim raised to #5a5a60) - Borders: subtle 0.06 / hover 0.1 / strong 0.14 alphas ## Typography - Inter + Roboto Mono → Geist + Geist Mono (bundled locally, ~88KB) - Single family throughout, weight-driven hierarchy - Material Symbols retained for icons (bundled, loaded via chrome.runtime.getURL) ## Logo - Scan-based red raster PNG → clean vector SVG in teal - Same nested-hexagon silhouette (testudo shell metaphor preserved) - 30KB → 2.3KB, crisp at all sizes - extract-icon.mjs updated to handle pure vector SVG via sharp density ## Surfaces - Removed: scan lines, pulse rings, glow shadows, noise textures, radial gradients - Added: 3px danger strip on warning modal (semantic anchor), flat cards with subtle borders - Warning modal title: 15px uppercase mono → 22px/600 Geist (visibly heavier per Gemini) - Options sidebar: Linear/Raycast style with brand teal active indicator - Settings rows: iOS Settings-style grouped bordered lists ## Verification - 734 tests passing (359 extension + 375 core) - Build clean: 6 bundles in ~120ms - content.js 4.6KB → 5.8KB (Geist font injection strings) - injected.js 72KB → 81KB (forward-compat selector aliases in warning-styles) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Lykhoyda
added a commit
that referenced
this pull request
Apr 17, 2026
Two related hardening passes bundled because they share the safety surface: ## Extension — G1: EIP-7702 chainId=0 replay requires typed confirmation Previously chainId=0 delegations were flagged CRITICAL but users could still proceed via a plain "Proceed Anyway" button. Because the signature can be replayed on every EVM chain, this now requires the same friction as eth_sign. - types.ts: add replay-risk to WarningContext union - intent-builder.ts: add buildReplayRiskIntent (headline + all-networks impact) - decoder/index.ts: dispatch replay-risk context to new builder - ModalButtons.tsx: render EthSignConfirm for eth-sign-danger OR replay-risk - warningVM.ts: accept optional context on updateAnalysis for context switch - injected.tsx: set context=replay-risk when chainId=0, adjust error message - intent-builder.test.ts: 3 new tests covering replay-risk intent ## Core — stability + edge cases Found during codebase audit; closes gaps #1-#3 and #6. Parser input validation (parser.ts, types.ts): - Throw InvalidBytecodeError on non-hex chars or odd-length input - Accept 0X prefix - Add Instruction.truncated flag when PUSH data is cut short by EOF Detector hardening (detectors.ts): - detectUnlimitedApproval requires data.length === 32 (no more false positive on truncated PUSH32 of 0xFFs via .every() on short slice) Fetcher error typing (fetcher.ts): - Wrap getCode in try/catch, throw typed BytecodeFetchError with cause - Treat undefined RPC response same as 0x Analyzer hardening (analyzer.ts): - Classify errors into bytecode_fetch_failed / invalid_bytecode / Analysis failed threat tags - Proxy-chain cycle guard: pass _visitedAddresses through recursion; A to B to A returns proxy_cycle_detected instead of looping Public API exports added: BytecodeFetchError, InvalidBytecodeError. Fail-open behavior preserved per CLAUDE.md — core analyzes, extension decides. Tests: - Extension: 366 pass (3 new for replay-risk) - Core: 395 pass (22 new: parser edges, truncated PUSH32, fetcher mocked errors, cycle detection, error classification)
7 tasks
Lykhoyda
added a commit
that referenced
this pull request
Apr 20, 2026
…ing (#5) * docs: add S-16 API chainId sync as In Progress (urgent, blocks API deploy) Captures the client-side work needed to match testudo-api PR #5, which moves threat/safe/encounter routes under /api/v1/chains/:chainId/... Default to mainnet (chainId=1) when chainId is not yet resolved from eth_chainId, so pingApi and first-paint analysis don't block on RPC. Prerequisite for the larger 2.1 Multichain EVM Support work. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(core+injected): replay-risk typed confirm + core package stability Two related hardening passes bundled because they share the safety surface: ## Extension — G1: EIP-7702 chainId=0 replay requires typed confirmation Previously chainId=0 delegations were flagged CRITICAL but users could still proceed via a plain "Proceed Anyway" button. Because the signature can be replayed on every EVM chain, this now requires the same friction as eth_sign. - types.ts: add replay-risk to WarningContext union - intent-builder.ts: add buildReplayRiskIntent (headline + all-networks impact) - decoder/index.ts: dispatch replay-risk context to new builder - ModalButtons.tsx: render EthSignConfirm for eth-sign-danger OR replay-risk - warningVM.ts: accept optional context on updateAnalysis for context switch - injected.tsx: set context=replay-risk when chainId=0, adjust error message - intent-builder.test.ts: 3 new tests covering replay-risk intent ## Core — stability + edge cases Found during codebase audit; closes gaps #1-#3 and #6. Parser input validation (parser.ts, types.ts): - Throw InvalidBytecodeError on non-hex chars or odd-length input - Accept 0X prefix - Add Instruction.truncated flag when PUSH data is cut short by EOF Detector hardening (detectors.ts): - detectUnlimitedApproval requires data.length === 32 (no more false positive on truncated PUSH32 of 0xFFs via .every() on short slice) Fetcher error typing (fetcher.ts): - Wrap getCode in try/catch, throw typed BytecodeFetchError with cause - Treat undefined RPC response same as 0x Analyzer hardening (analyzer.ts): - Classify errors into bytecode_fetch_failed / invalid_bytecode / Analysis failed threat tags - Proxy-chain cycle guard: pass _visitedAddresses through recursion; A to B to A returns proxy_cycle_detected instead of looping Public API exports added: BytecodeFetchError, InvalidBytecodeError. Fail-open behavior preserved per CLAUDE.md — core analyzes, extension decides. Tests: - Extension: 366 pass (3 new for replay-risk) - Core: 395 pass (22 new: parser edges, truncated PUSH32, fetcher mocked errors, cycle detection, error classification) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Complete visual overhaul of the Testudo extension UI following Gemini-reviewed "Quiet Confidence" design direction. Addresses feedback that the previous "Cipher Terminal" style felt "dull" and not polished enough for a premium security tool.
Design system
#00e599phosphor green (flat)#1a9b8cdesaturated teal#ff3b5c#dc2626(more serious)#ffaa2c#f59e0b#0c0c14single surface#0a0a0b → #141416 → #1c1c1f → #222226#3e3e55(2.5:1 contrast, fails WCAG)#5a5a60(passes AA)Logo
Redesigned from scan-based red raster (30KB) to clean vector SVG in teal (2.3KB). Same nested-hexagon "testudo shell" silhouette preserved.
extract-icon.mjsupdated to handle pure vector SVG via sharp density rendering.Surfaces
Removed (felt "edgy"):
Added (felt "polished"):
Per-surface changes
Typography — single family
Replaced three-family system (Inter + Roboto Mono + Material Symbols) with single Geist family + Geist Mono + Material Symbols (icons only).
Total font bundle: ~540KB (Material Symbols is 451KB, Geist files are ~88KB combined).
Verification
Test plan
Design review trail
🤖 Generated with Claude Code