fix(uxp-panel): use ::before pseudo-element to cover native button chrome

UXP's native button chrome overrides explicit `background` rules on
icon-only <button> elements -- appearance:none and background both lose.
Authored content (::before pseudo-elements) renders above native chrome,
so move all background/hover/active logic there. SVG icons and the
growing-count badge get z-index:1/2 to sit above the cover.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Zac Gaetano 2026-05-28 21:09:09 -04:00
parent dd438b597a
commit 08a0fb1b60

View file

@ -260,9 +260,10 @@ input[type="search"]::-webkit-search-cancel-button { display: none; }
width: 34px;
height: 34px;
border: none;
/* UXP renders native button chrome through `transparent`; an explicit
background matching the rail suppresses it (appearance:none alone did not). */
background: var(--bg-base);
/* Leave background transparent UXP native chrome cannot be overridden via
`background` on icon-only buttons. Cover it with a ::before pseudo-element
instead; authored content renders above native chrome. */
background: transparent;
appearance: none;
-webkit-appearance: none;
border-radius: 8px;
@ -271,17 +272,31 @@ input[type="search"]::-webkit-search-cancel-button { display: none; }
align-items: center;
justify-content: center;
cursor: pointer;
transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
transition: color var(--t-fast) var(--ease);
}
.rail-btn:hover { background: var(--bg-hover); color: var(--text-1); }
.rail-btn.active { background: var(--accent-subtle); color: var(--accent-bright); }
.rail-btn svg { width: 18px; height: 18px; }
/* Full-face cover painted above native chrome */
.rail-btn::before {
content: '';
position: absolute;
inset: 0;
border-radius: 8px;
background: var(--bg-base);
transition: background var(--t-fast) var(--ease);
pointer-events: none;
}
.rail-btn:hover { color: var(--text-1); }
.rail-btn:hover::before { background: var(--bg-hover); }
.rail-btn.active { color: var(--accent-bright); }
.rail-btn.active::before { background: var(--accent-subtle); }
/* SVG and badge sit above the ::before cover */
.rail-btn svg { position: relative; z-index: 1; width: 18px; height: 18px; }
.rail-btn--accent { color: var(--accent-bright); }
.rail-btn--accent:hover { background: var(--accent-subtle); }
.rail-btn--accent:hover::before { background: var(--accent-subtle); }
.rail-spacer { flex: 1; }
.rail-count {
position: absolute;
z-index: 2;
top: 0;
right: 0;
min-width: 15px;
@ -478,10 +493,10 @@ input[type="search"]::-webkit-search-cancel-button { display: none; }
width: 30px;
height: 30px;
flex-shrink: 0;
border: 1px solid transparent;
/* explicit background matching the dock/statusbar suppresses UXP's native
button chrome (appearance:none alone did not clear the grey fill). */
background: var(--bg-base);
border: none;
/* Same ::before strategy as .rail-btn authored pseudo-element covers
UXP's native button chrome which ignores explicit background rules. */
background: transparent;
appearance: none;
-webkit-appearance: none;
border-radius: 7px;
@ -490,15 +505,28 @@ input[type="search"]::-webkit-search-cancel-button { display: none; }
align-items: center;
justify-content: center;
cursor: pointer;
transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
transition: color var(--t-fast) var(--ease);
}
.iconbtn:hover { background: var(--bg-hover); color: var(--text-1); }
.iconbtn svg { width: 16px; height: 16px; }
.iconbtn::before {
content: '';
position: absolute;
inset: 0;
border-radius: 7px;
background: var(--bg-base);
transition: background var(--t-fast) var(--ease);
pointer-events: none;
}
.iconbtn:hover { color: var(--text-1); }
.iconbtn:hover::before { background: var(--bg-hover); }
/* SVG sits above the ::before cover */
.iconbtn svg { position: relative; z-index: 1; width: 16px; height: 16px; }
.iconbtn:disabled { opacity: 0.32; cursor: default; pointer-events: none; }
.iconbtn--sm { width: 24px; height: 24px; border-radius: 6px; color: var(--text-3); }
.iconbtn--sm::before { border-radius: 6px; }
.iconbtn--sm svg { width: 15px; height: 15px; }
.iconbtn--primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.iconbtn--primary:not(:disabled):hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.iconbtn--primary::before { background: var(--accent); }
.iconbtn--primary { color: #fff; }
.iconbtn--primary:not(:disabled):hover::before { background: var(--accent-hover); }
/* ── progress ───────────────────────────────────────────────────── */
.progress-row { display: flex; flex-direction: column; gap: 4px; padding: 8px 10px 0; flex-shrink: 0; }