diff --git a/resources/views/components/account-menu.blade.php b/resources/views/components/account-menu.blade.php
index 00c968a9..3719ed9b 100644
--- a/resources/views/components/account-menu.blade.php
+++ b/resources/views/components/account-menu.blade.php
@@ -38,10 +38,12 @@
type="button"
aria-label="{{ $label }}"
data-account-menu
- class="touch-target focus-ring inline-flex size-10 shrink-0 cursor-pointer items-center justify-center rounded-corner-full bg-primary-container type-label-lg text-on-primary-container"
+ class="state-layer touch-target focus-ring inline-flex size-10 shrink-0 cursor-pointer items-center justify-center rounded-corner-full bg-primary-container type-label-lg text-on-primary-container"
>
@if ($image)
-
+ {{-- Behind the state layer (`state-layer` paints its ::before at z-index -1), so an
+ avatar image still shows the hover and pressed states over it. --}}
+
@elseif (filled($initials))
{{ $initials }}
@else
diff --git a/tests/Feature/Components/AppBarTest.php b/tests/Feature/Components/AppBarTest.php
index cb3d9bdb..369d254e 100644
--- a/tests/Feature/Components/AppBarTest.php
+++ b/tests/Feature/Components/AppBarTest.php
@@ -146,8 +146,9 @@ it('opens an account menu from the initials of a name', function () {
expect($html)
->toContain('aria-label="Account"')
->toContain('data-account-menu')
- // The 40px avatar reaches 48px, and nothing clips the pseudo-target (N-01).
- ->toContain('touch-target')
+ // The 40px avatar reaches 48px, and nothing clips the pseudo-target (N-01); the trigger
+ // has a hover and a pressed state like every other trigger in the library (N-15).
+ ->toContain('state-layer touch-target focus-ring')
->not->toContain('overflow-hidden')
->toMatch('/>\s*AM\s*<\/button>/')
->toContain('anna@example.com')
@@ -155,6 +156,6 @@ it('opens an account menu from the initials of a name', function () {
->toContain('data-account-theme')
->toContain('Sign out')
->and((string) $this->blade(''))
- ->toContain('
')
+ ->toContain('
')
->not->toContain('data-account-theme');
});