diff --git a/apps/differ/src/app.css b/apps/differ/src/app.css
index edb09ea33..47dedda79 100644
--- a/apps/differ/src/app.css
+++ b/apps/differ/src/app.css
@@ -30,8 +30,8 @@
--diff-range-border: #524d58;
--diff-comment-highlight: rgba(88, 166, 255, 0.5);
- --search-match-bg: rgba(250, 200, 50, 0.35);
- --search-current-match-bg: rgba(255, 150, 50, 0.5);
+ --search-match-accent: #f2c744;
+ --search-current-match-bg: rgba(242, 199, 68, 0.3);
--annotation-overlay-bg: rgba(0, 0, 0, 0.5);
--annotation-border: rgba(255, 255, 255, 0.1);
diff --git a/apps/staged/src/app.css b/apps/staged/src/app.css
index 9a69fb83d..15de5de59 100644
--- a/apps/staged/src/app.css
+++ b/apps/staged/src/app.css
@@ -92,8 +92,8 @@
--diff-comment-border: rgba(167, 139, 250, 0.56);
--diff-comment-accent: #a78bfa;
- --search-match-bg: rgba(250, 200, 50, 0.35);
- --search-current-match-bg: rgba(255, 150, 50, 0.5);
+ --search-match-accent: #f2c744;
+ --search-current-match-bg: rgba(242, 199, 68, 0.3);
--annotation-overlay-bg: rgba(0, 0, 0, 0.5);
--annotation-border: rgba(255, 255, 255, 0.1);
@@ -269,15 +269,41 @@ svg.lucide:not(.animate-spin),
transform: translateZ(0);
}
-/* ── In-content search highlights ── */
+/* ── Search match highlights ── */
+/* Longhands on purpose: WebKit before Safari 26.2 rejects a thickness inside
+ the `text-decoration` shorthand, and a rejected `var()` declaration drops
+ the whole underline, not just its thickness. */
+mark.search-match,
+mark.label-match {
+ background-color: transparent;
+ text-decoration-line: underline;
+ text-decoration-color: var(--search-match-accent);
+ text-decoration-skip-ink: none;
+}
+
+/* In-content find: notes and session chat. */
mark.search-match {
- background-color: rgba(255, 235, 59, 0.4);
- border-radius: 2px;
color: inherit;
+ text-decoration-thickness: 2px;
+ text-underline-offset: 3px;
}
+/* A match inside a one-line label: project search rows and the command
+ palette. No fill, the match in the primary text colour over a warm line,
+ which lifts it out of muted text. The offset keeps the line inside the
+ label's line box, which clips. */
+mark.label-match {
+ color: var(--text-primary);
+ text-decoration-thickness: 1.5px;
+ text-underline-offset: 1.5px;
+}
+
+/* The wash alone is faint in the light theme; the ring keeps the current
+ match obvious on every surface. */
mark.search-match-current {
- background-color: rgba(255, 152, 0, 0.6);
+ background-color: var(--search-current-match-bg);
+ border-radius: 2px;
+ box-shadow: 0 0 0 1px var(--search-match-accent);
}
/* ── Hashtag badges (shared across all badge contexts) ── */
diff --git a/apps/staged/src/lib/features/commandPalette/CommandPalette.component.test.ts b/apps/staged/src/lib/features/commandPalette/CommandPalette.component.test.ts
index f72886532..eefb2c00a 100644
--- a/apps/staged/src/lib/features/commandPalette/CommandPalette.component.test.ts
+++ b/apps/staged/src/lib/features/commandPalette/CommandPalette.component.test.ts
@@ -872,7 +872,7 @@ describe('CommandPalette filtering', () => {
await type('beta');
expect(optionNames()).toEqual(['Beta tools']);
- expect(options()[0].querySelector('.row-name mark')?.textContent).toBe('Beta');
+ expect(options()[0].querySelector('.row-name mark.label-match')?.textContent).toBe('Beta');
});
it('returns the highlight to the first result when the query changes', async () => {
@@ -934,11 +934,15 @@ describe('CommandPalette filtering', () => {
await type('payments');
expect(optionIds()).toEqual(['beta']);
expect(optionFor('beta').querySelector('.row-repo')?.textContent).toBe('org/payments');
- expect(optionFor('beta').querySelector('.row-repo mark')?.textContent).toBe('payments');
+ expect(optionFor('beta').querySelector('.row-repo mark.label-match')?.textContent).toBe(
+ 'payments'
+ );
await type('storefront');
expect(optionIds()).toEqual(['gamma']);
- expect(optionFor('gamma').querySelector('.row-alias mark')?.textContent).toBe('storefront');
+ expect(optionFor('gamma').querySelector('.row-alias mark.label-match')?.textContent).toBe(
+ 'storefront'
+ );
expect(optionFor('gamma').querySelector('.row-repo')?.textContent).toBe('org/web/apps/site');
});
});
diff --git a/apps/staged/src/lib/features/commandPalette/CommandPaletteRow.svelte b/apps/staged/src/lib/features/commandPalette/CommandPaletteRow.svelte
index 5618bae0c..7592177ce 100644
--- a/apps/staged/src/lib/features/commandPalette/CommandPaletteRow.svelte
+++ b/apps/staged/src/lib/features/commandPalette/CommandPaletteRow.svelte
@@ -62,7 +62,7 @@
{#snippet highlighted(segments: readonly HighlightSegment[])}
- {#each segments as segment}{#if segment.match}{segment.text}{segment.text}{:else}{segment.text}{/if}{/each}
{/snippet}
@@ -240,12 +240,11 @@
min-width: 0;
}
- .row-name mark,
- .row-alias mark,
- .row-repo mark {
- background-color: var(--search-match-bg);
- border-radius: 2px;
- color: inherit;
+ /* Matches use the global `label-match` rule, shared with ProjectMatchReason,
+ which draws the reason beside these. The pill's border sits right under
+ the text; pull the line up off it. */
+ .row-alias mark {
+ text-underline-offset: 0.5px;
}
.row-badges {
diff --git a/apps/staged/src/lib/features/projects/ProjectMatchReason.svelte b/apps/staged/src/lib/features/projects/ProjectMatchReason.svelte
index b68900a87..4eb5a2c4a 100644
--- a/apps/staged/src/lib/features/projects/ProjectMatchReason.svelte
+++ b/apps/staged/src/lib/features/projects/ProjectMatchReason.svelte
@@ -57,7 +57,7 @@
{KIND_NAMES[reason.kind]}:
{#each segments as segment}{#if segment.match}{segment.text}{#each segments as segment}{#if segment.match}{segment.text}{:else}{segment.text}{/if}{/each}
{#if reason.more > 0}
@@ -84,12 +84,6 @@
text-overflow: ellipsis;
}
- .match-label mark {
- background-color: var(--search-match-bg);
- border-radius: 2px;
- color: inherit;
- }
-
.match-more {
flex-shrink: 0;
color: var(--text-faint);
diff --git a/apps/staged/src/lib/theme.ts b/apps/staged/src/lib/theme.ts
index 34ca8f3bc..51c97a8da 100644
--- a/apps/staged/src/lib/theme.ts
+++ b/apps/staged/src/lib/theme.ts
@@ -70,7 +70,7 @@ export interface Theme {
// Search highlight colors
search: {
- matchBg: string; // Background for search matches
+ matchAccent: string; // Line under a search match
currentMatchBg: string; // Background for current/focused match
};
@@ -510,13 +510,11 @@ export function createAdaptiveTheme(
},
search: {
- // Search yellow derived from foreground warmth — mix fg toward warm tone
- matchBg: overlay(mix(syntaxFg, isDark ? '#fac832' : '#e8b000', 0.7), isDark ? 0.35 : 0.5),
- // Current match: warmer/more saturated variant of above
- currentMatchBg: overlay(
- mix(syntaxFg, isDark ? '#ff9632' : '#d07000', 0.7),
- isDark ? 0.5 : 0.6
- ),
+ // A match keeps its surface and gains a warm line beneath it. Solid, so
+ // it reads the same on plain, hovered and selected rows.
+ matchAccent: isDark ? '#f2c744' : '#a87400',
+ // Only the current match is filled, in a wash of the same amber.
+ currentMatchBg: overlay(isDark ? '#f2c744' : '#f2b600', isDark ? 0.3 : 0.35),
},
annotation: {
@@ -632,7 +630,7 @@ export function themeToVarMap(t: Theme): Record {
'--diff-comment-border': t.diff.commentBorder,
'--diff-comment-accent': t.diff.commentAccent,
- '--search-match-bg': t.search.matchBg,
+ '--search-match-accent': t.search.matchAccent,
'--search-current-match-bg': t.search.currentMatchBg,
'--annotation-overlay-bg': t.annotation.overlayBg,
diff --git a/packages/diff-viewer/src/lib/components/DiffViewer.svelte b/packages/diff-viewer/src/lib/components/DiffViewer.svelte
index a8c5928fa..4b61efb59 100644
--- a/packages/diff-viewer/src/lib/components/DiffViewer.svelte
+++ b/packages/diff-viewer/src/lib/components/DiffViewer.svelte
@@ -3352,23 +3352,24 @@
}
/* Search result highlighting */
- .search-match {
- background-color: rgba(250, 200, 50, 0.35);
- border-radius: 2px;
+ /* Longhands on purpose: WebKit before Safari 26.2 rejects a thickness inside
+ the shorthand and would drop the whole underline. The `em` offset keeps
+ the line inside the row at any `--code-font-size`. */
+ .search-match,
+ .search-current {
+ text-decoration-line: underline;
+ text-decoration-thickness: 2px;
+ text-decoration-color: var(--search-match-accent, #f2c744);
+ text-underline-offset: 0.2em;
+ text-decoration-skip-ink: none;
}
+ /* On a modified line the wash is nearly the same colour as the
+ changed-character tint it replaces; the ring is what keeps the current
+ match visible there. */
.search-current {
- background-color: rgba(255, 150, 50, 0.5);
+ background-color: var(--search-current-match-bg, rgba(242, 199, 68, 0.3));
border-radius: 2px;
- }
-
- @media (prefers-color-scheme: light) {
- .search-match {
- background-color: rgba(250, 200, 50, 0.5);
- }
-
- .search-current {
- background-color: rgba(255, 150, 50, 0.6);
- }
+ box-shadow: 0 0 0 1px var(--search-match-accent, #f2c744);
}