From 7dca67444370c1cc067ac85b74795b35f5c59f73 Mon Sep 17 00:00:00 2001 From: Benson Date: Wed, 18 Mar 2026 13:34:45 +0700 Subject: [PATCH 01/12] refactor: rebrand verified color from green-600 to emerald-500 - Add SIGNAL_GREEN / SIGNAL_GREEN_DARK constants (emerald-500/400) - Deprecate SIGNAL_BLUE / SIGNAL_BLUE_DARK with backward-compat alias - Extend HighlightColor union with "green"; make "blue" a legacy alias - Update getBracketColor default from "blue" to "green" - Update CitationAnnotationOverlay fallback bracket to "green" - Align VerifiedCheck icon color to emerald-500/400 - Update VERIFIED_COLOR_DEFAULT and CSS custom properties (light + dark) to emerald-500 (#10b981) / emerald-400 (#34d399) Co-Authored-By: Claude Sonnet 4.6 --- src/drawing/citationDrawing.ts | 22 +++++++++++++++------- src/react/Citation.tsx | 4 ++-- src/react/CitationAnnotationOverlay.tsx | 2 +- src/react/constants.ts | 4 ++-- src/styles.css | 4 ++-- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/drawing/citationDrawing.ts b/src/drawing/citationDrawing.ts index 10a0c322..929eb065 100644 --- a/src/drawing/citationDrawing.ts +++ b/src/drawing/citationDrawing.ts @@ -15,11 +15,12 @@ import { safeSplit } from "../utils/regexSafety.js"; /** * Highlight color category for citation annotations. - * - 'blue': exact / full-phrase match + * - 'green': exact / full-phrase match (VERIFIED) * - 'amber': partial match (anchorText-only or value-only) * - 'red': not-found (AI claimed location overlay) + * - 'blue': legacy alias for 'green' — kept for backward compatibility */ -export type HighlightColor = "blue" | "amber" | "red"; +export type HighlightColor = "green" | "blue" | "amber" | "red"; // ============================================================================= // Color Constants @@ -28,9 +29,14 @@ export type HighlightColor = "blue" | "amber" | "red"; /** Border width for citation bracket outlines (px). */ export const CITATION_LINE_BORDER_WIDTH = 2; -/** Blue bracket color for exact/full-phrase matches. */ +/** Green bracket color for verified / exact-match citations (BRANDING.md VERIFIED, emerald-500). */ +export const SIGNAL_GREEN = "#10b981"; +/** Lighter green for dark-mode contexts (BRANDING.md VERIFIED luminous, emerald-400). */ +export const SIGNAL_GREEN_DARK = "#34d399"; + +/** @deprecated Use SIGNAL_GREEN. Kept for any external consumers still referencing blue brackets. */ export const SIGNAL_BLUE = "#005595"; -/** Lighter blue for dark-mode contexts. */ +/** @deprecated Use SIGNAL_GREEN_DARK. */ export const SIGNAL_BLUE_DARK = "#77bff6"; /** Amber bracket color for partial matches (Tailwind amber-400). */ @@ -88,12 +94,14 @@ export function getBracketWidth(height: number): number { /** * Returns the bracket stroke color for a given highlight category. - * Blue for exact matches, amber for partial matches, red for not-found. + * Green for verified/exact matches, amber for partial matches, red for not-found. + * "blue" is a legacy alias that resolves to the deprecated SIGNAL_BLUE value. */ -export function getBracketColor(highlightColor: HighlightColor = "blue"): string { +export function getBracketColor(highlightColor: HighlightColor = "green"): string { if (highlightColor === "amber") return SIGNAL_AMBER; if (highlightColor === "red") return SIGNAL_RED; - return SIGNAL_BLUE; + if (highlightColor === "blue") return SIGNAL_BLUE; // legacy + return SIGNAL_GREEN; } // ============================================================================= diff --git a/src/react/Citation.tsx b/src/react/Citation.tsx index 2f5bb124..aff60d1e 100644 --- a/src/react/Citation.tsx +++ b/src/react/Citation.tsx @@ -1491,11 +1491,11 @@ const PendingDot = () => ( /** * Green verified checkmark indicator. - * Uses green-600 color to match DOT_COLORS.green for visual consistency. + * Uses emerald-500/400 to match BRANDING.md VERIFIED status color and SIGNAL_GREEN. */ const VerifiedCheck = () => ( ); diff --git a/src/react/CitationAnnotationOverlay.tsx b/src/react/CitationAnnotationOverlay.tsx index 7aaddb14..0f4bbc59 100644 --- a/src/react/CitationAnnotationOverlay.tsx +++ b/src/react/CitationAnnotationOverlay.tsx @@ -144,7 +144,7 @@ export function CitationAnnotationOverlay({ if (!rect) return null; const bracketColor = getBracketColor( - highlightColor === "amber" ? "amber" : highlightColor === "red" ? "red" : "blue", + highlightColor === "amber" ? "amber" : highlightColor === "red" ? "red" : "green", ); // Compute pixel height for bracket width calculation diff --git a/src/react/constants.ts b/src/react/constants.ts index 78cf91f8..b9b07205 100644 --- a/src/react/constants.ts +++ b/src/react/constants.ts @@ -55,8 +55,8 @@ export const MISS_WAVY_UNDERLINE_STYLE: React.CSSProperties = { * Override via `--dc-verified` on `:root` or `.dark`, or use ``. */ export const VERIFIED_COLOR_VAR = "--dc-verified"; -/** Default verified indicator color */ -export const VERIFIED_COLOR_DEFAULT = "#16a34a"; +/** Default verified indicator color (emerald-500, BRANDING.md VERIFIED) */ +export const VERIFIED_COLOR_DEFAULT = "#10b981"; /** * CSS custom property name for partial match indicator color. diff --git a/src/styles.css b/src/styles.css index 05e0037b..02d405b4 100644 --- a/src/styles.css +++ b/src/styles.css @@ -30,7 +30,7 @@ --dc-ring: #3b82f6; /* focus ring */ /* Status accents */ - --dc-verified: #16a34a; /* verified / success */ + --dc-verified: #10b981; /* verified / success (emerald-500, BRANDING.md VERIFIED) */ --dc-partial: #f59e0b; /* partial match / warning */ --dc-destructive: #ef4444; /* not found / error */ --dc-pending: #a1a1aa; /* loading / unresolved (same as subtle-foreground by default) */ @@ -55,7 +55,7 @@ --dc-border: #3f3f46; --dc-ring: #3b82f6; - --dc-verified: #22c55e; + --dc-verified: #34d399; /* emerald-400 luminous, BRANDING.md VERIFIED dark mode */ --dc-partial: #fbbf24; --dc-destructive: #f87171; --dc-pending: #71717a; From 22b8ae44ef48c9a731b9a7048357771b06818335 Mon Sep 17 00:00:00 2001 From: Benson Date: Wed, 18 Mar 2026 13:34:50 +0700 Subject: [PATCH 02/12] fix: require ctrl for zoom gesture and use grabbing cursor while dragging - Pass requireCtrl: true to useZoomGesture in InlineExpandedImage so free scroll is not hijacked when the user isn't intending to zoom - Change cursor from "move" to "grabbing" during drag for better affordance consistency with pan interactions Co-Authored-By: Claude Sonnet 4.6 --- src/react/EvidenceTray.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/react/EvidenceTray.tsx b/src/react/EvidenceTray.tsx index e2c644bf..b64fabf9 100644 --- a/src/react/EvidenceTray.tsx +++ b/src/react/EvidenceTray.tsx @@ -1725,6 +1725,7 @@ export function InlineExpandedImage({ clampZoomRaw, clampZoom, gestureAnchorRef: expandedWheelAnchorRef, + requireCtrl: true, onZoomCommit: (z: number) => { setManualZoom(z); }, @@ -2022,7 +2023,7 @@ export function InlineExpandedImage({ ...(!annotationVtRect ? { viewTransitionName: DC_EVIDENCE_VT_NAME } : {}), ...(fill ? {} : { maxHeight: "min(600px, 80dvh)" }), overscrollBehavior: "none", - cursor: isDragging ? "move" : "zoom-out", + cursor: isDragging ? "grabbing" : "zoom-out", ...HIDE_SCROLLBAR_STYLE, }} onDragStart={e => e.preventDefault()} From e2ca227f13411e4f5b20340a58b3e0707fbe89e0 Mon Sep 17 00:00:00 2001 From: Benson Date: Wed, 18 Mar 2026 13:40:05 +0700 Subject: [PATCH 03/12] fix(test): update UrlCitationComponent test to expect emerald-500 class The verified color was rebranded from green-600 to emerald-500 in the component; update the test assertion to match. Co-Authored-By: Claude Sonnet 4.6 --- src/__tests__/UrlCitationComponent.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/__tests__/UrlCitationComponent.test.tsx b/src/__tests__/UrlCitationComponent.test.tsx index 04160f5d..6a82ccb0 100644 --- a/src/__tests__/UrlCitationComponent.test.tsx +++ b/src/__tests__/UrlCitationComponent.test.tsx @@ -50,8 +50,8 @@ describe("UrlCitationComponent", () => { const checkIcon = container.querySelector("svg"); expect(checkIcon).toBeInTheDocument(); - // The wrapper should have green color class - const statusWrapper = container.querySelector(".text-green-600"); + // The wrapper should have emerald color class (emerald-500 is the verified brand color) + const statusWrapper = container.querySelector(".text-emerald-500"); expect(statusWrapper).toBeInTheDocument(); }); From d67d327eae4d741c74065682921536d621b1c8c1 Mon Sep 17 00:00:00 2001 From: Benson Date: Wed, 18 Mar 2026 13:41:43 +0700 Subject: [PATCH 04/12] fix: align verified bracket and checkmark colors with --dc-verified token Previously the annotation brackets and VerifiedCheck icon used hardcoded emerald hex values, so host theme overrides to --dc-verified had no effect on them, causing color mismatch with the status dot and quote left border. - CitationAnnotationOverlay: green bracket case now uses var(--dc-verified, #10b981) so it tracks the CSS token - VerifiedCheck: swap hardcoded text-emerald-500/400 classes for VERIFIED_COLOR_STYLE (color: var(--dc-verified, #10b981)) - Update UrlCitationComponent test to assert on the CSS variable rather than the removed Tailwind class Co-Authored-By: Claude Sonnet 4.6 --- src/__tests__/UrlCitationComponent.test.tsx | 5 ++--- src/react/Citation.tsx | 7 ++++--- src/react/CitationAnnotationOverlay.tsx | 13 +++++++++---- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/__tests__/UrlCitationComponent.test.tsx b/src/__tests__/UrlCitationComponent.test.tsx index 6a82ccb0..907106d4 100644 --- a/src/__tests__/UrlCitationComponent.test.tsx +++ b/src/__tests__/UrlCitationComponent.test.tsx @@ -50,9 +50,8 @@ describe("UrlCitationComponent", () => { const checkIcon = container.querySelector("svg"); expect(checkIcon).toBeInTheDocument(); - // The wrapper should have emerald color class (emerald-500 is the verified brand color) - const statusWrapper = container.querySelector(".text-emerald-500"); - expect(statusWrapper).toBeInTheDocument(); + // The check icon uses the --dc-verified CSS custom property so host themes can override it + expect(checkIcon).toHaveStyle({ color: "var(--dc-verified, #10b981)" }); }); it("shows lock icon when blocked", () => { diff --git a/src/react/Citation.tsx b/src/react/Citation.tsx index aff60d1e..5623559e 100644 --- a/src/react/Citation.tsx +++ b/src/react/Citation.tsx @@ -25,6 +25,7 @@ import { SPINNER_TIMEOUT_MS, TAP_SLOP_PX, TOUCH_CLICK_DEBOUNCE_MS, + VERIFIED_COLOR_STYLE, } from "./constants.js"; import { DefaultPopoverContent, type PopoverViewState } from "./DefaultPopoverContent.js"; import { resolveEvidenceSrc, resolveExpandedImage } from "./EvidenceTray.js"; @@ -1490,12 +1491,12 @@ const PendingDot = () => ( ); /** - * Green verified checkmark indicator. - * Uses emerald-500/400 to match BRANDING.md VERIFIED status color and SIGNAL_GREEN. + * Verified checkmark indicator. + * Color tracks --dc-verified so it stays in sync with the status dot and quote border. */ const VerifiedCheck = () => ( ); diff --git a/src/react/CitationAnnotationOverlay.tsx b/src/react/CitationAnnotationOverlay.tsx index 0f4bbc59..2066387b 100644 --- a/src/react/CitationAnnotationOverlay.tsx +++ b/src/react/CitationAnnotationOverlay.tsx @@ -11,7 +11,7 @@ import { SPOTLIGHT_PADDING, } from "../drawing/citationDrawing.js"; import type { DeepTextItem } from "../types/boxes.js"; -import { HITBOX_EXTEND_8 } from "./constants.js"; +import { HITBOX_EXTEND_8, VERIFIED_COLOR_DEFAULT, VERIFIED_COLOR_VAR } from "./constants.js"; import { useTranslation } from "./i18n.js"; import { CloseIcon } from "./icons.js"; import { toPercentRect } from "./overlayGeometry.js"; @@ -143,9 +143,14 @@ export function CitationAnnotationOverlay({ // Bail out if geometry is invalid (zero dimensions, NaN, Infinity, etc.) if (!rect) return null; - const bracketColor = getBracketColor( - highlightColor === "amber" ? "amber" : highlightColor === "red" ? "red" : "green", - ); + // Use the CSS custom property for verified brackets so host theme overrides + // propagate here the same way they do for the status indicator and quote border. + const bracketColor = + highlightColor === "amber" + ? getBracketColor("amber") + : highlightColor === "red" + ? getBracketColor("red") + : `var(${VERIFIED_COLOR_VAR}, ${VERIFIED_COLOR_DEFAULT})`; // Compute pixel height for bracket width calculation const heightPx = phraseMatchDeepItem.height * renderScale.y; From 04361ac06dcdc875acd625a3a445438456ab4b33 Mon Sep 17 00:00:00 2001 From: Benson Date: Wed, 18 Mar 2026 13:44:23 +0700 Subject: [PATCH 05/12] fix: move style prop from CheckIcon to wrapper span to satisfy TypeScript CheckIcon only accepts className; color inherits to SVG via currentColor. Co-Authored-By: Claude Sonnet 4.6 --- src/react/Citation.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/react/Citation.tsx b/src/react/Citation.tsx index 5623559e..96f55827 100644 --- a/src/react/Citation.tsx +++ b/src/react/Citation.tsx @@ -1495,8 +1495,8 @@ const PendingDot = () => ( * Color tracks --dc-verified so it stays in sync with the status dot and quote border. */ const VerifiedCheck = () => ( -