diff --git a/src/lib/components/pksx/StorageSlot.svelte b/src/lib/components/pksx/StorageSlot.svelte index f852126b..99065b11 100644 --- a/src/lib/components/pksx/StorageSlot.svelte +++ b/src/lib/components/pksx/StorageSlot.svelte @@ -127,6 +127,7 @@ background: var(--slot-fill); box-shadow: var(--shadow-sm); color: var(--ink); + outline: none; overflow: visible; transition: transform 120ms ease, @@ -172,7 +173,7 @@ .slot.focused { transform: translateY(-1px); box-shadow: - 0 0 0 2px var(--rust), + inset 0 0 0 2px var(--rust), inset 0 0 0 1px color-mix(in srgb, white, transparent 38%), var(--shadow); } @@ -188,7 +189,7 @@ border-style: solid; border-color: var(--rust); box-shadow: - 0 0 0 2px var(--rust), + inset 0 0 0 2px var(--rust), var(--shadow); } @@ -199,20 +200,20 @@ .slot.destination-valid { box-shadow: - 0 0 0 2px color-mix(in srgb, var(--ok), transparent 22%), + inset 0 0 0 2px color-mix(in srgb, var(--ok), transparent 22%), var(--shadow-sm); } .slot.destination-source { box-shadow: - 0 0 0 2px color-mix(in srgb, var(--gold), transparent 20%), + inset 0 0 0 2px color-mix(in srgb, var(--gold), transparent 20%), var(--shadow-sm); } .slot.destination-invalid.focused { opacity: 0.72; box-shadow: - 0 0 0 2px color-mix(in srgb, var(--err), transparent 18%), + inset 0 0 0 2px color-mix(in srgb, var(--err), transparent 18%), var(--shadow); } diff --git a/src/routes/box-shell.e2e.ts b/src/routes/box-shell.e2e.ts index faba67dc..e2dcef40 100644 --- a/src/routes/box-shell.e2e.ts +++ b/src/routes/box-shell.e2e.ts @@ -1076,6 +1076,29 @@ test('keyboard navigation moves deterministically across the box grid', async ({ await expect(page.locator('#collection-control-pane-pokemon-storage')).toBeFocused(); }); +test('the active Slot uses one focus ring painted inside its bounds', async ({ page }) => { + await openEmptySaves(page); + const slot = page.locator('#box-0-slot-0'); + + await page.evaluate(() => { + document.documentElement.dataset.inputModality = 'controller'; + }); + await slot.focus(); + await expect(slot).toBeFocused(); + await expect(slot).toHaveClass(/focused/); + + const focusPaint = await slot.evaluate((element) => { + const styles = getComputedStyle(element); + return { + firstShadow: styles.boxShadow.split(/,(?![^(]*\))/)[0], + outlineStyle: styles.outlineStyle + }; + }); + + expect(focusPaint).toMatchObject({ outlineStyle: 'none' }); + expect(focusPaint.firstShadow).toContain('inset'); +}); + test('compact box controls and keyboard shortcuts update the active box label', async ({ page }) => { diff --git a/src/routes/layout.css b/src/routes/layout.css index dead66c6..c36cf4db 100644 --- a/src/routes/layout.css +++ b/src/routes/layout.css @@ -254,7 +254,7 @@ strong { font-weight: 650; } -html[data-input-modality='controller'] body :focus { +html[data-input-modality='controller'] body :focus:not([data-pksx-control-category='slot']) { outline: 3px solid var(--pksx-color-accent-ring) !important; outline-offset: 3px !important; }