Hi Kegan,
Fantastic first solution!
Your HTML is just about perfect I would say. The only thing I would recommend is to include height and width attributes on the img element. This tells the browser how much space to give the image even before it loads, which helps to prevent layout shift. You can see this in action if you throttle your network speed in dev tools and reload the page.
If you wanted to include the attribution section you have commented out, I'd also put that into a footer element for semantic purposes.
In your CSS I like that you've included comments to explain your decision-making. For your body tag you've used the place-content shorthand. This saves one line of space but, unlike justify-content and align-items, it is not supported in pre-chromium versions of Edge and not at all in IE, so you may want to avoid using it if those old browsers are still prevalent among your users.
You probably didn't need the grid on your qr-card__content. All you're gaining from it is the gap property, which in this case could be a single margin on either the h1 or p tag instead. I can understand why you'd use grid here though, as if you add more content to the card it would keep things simple.
Your page overflows on widths lower than 337px (with default font sizes) because you haven't set a max-width for the image. You can calculate what that needs to be using the viewport width and your --card-padding variable.
My only other comment would be that rather than base your card size off the image width, could you base the image width off the desired card size instead? Either way works fine, it just feels like the image width variable is a bit arbitrary, while a targeted total size for the card seems more logical to me.
All in all, a very professional job and much better than mine :P
Keep it up!