## 1. CSS shimmer styles - [x] 1.1 Add `@keyframes shimmer` animation to `global.css` — a translucent gradient sweep (left-to-right) that works on the dark theme background (`--bg0`/`--bg1` palette). - [x] 1.2 Add `.img-shimmer-wrap` class to `global.css` — `position: relative; overflow: hidden;` container that inherits dimensions from its parent. Add a `::before` pseudo-element with the shimmer animation (full width/height, absolute positioned, translucent light gradient). - [x] 1.3 Add `.img-loading` class to `global.css` — sets `opacity: 0` on the `` element. Add transition: `opacity 250ms ease`. - [x] 1.4 Add `.img-error` class to `global.css` — stops the shimmer animation on the wrapper (`animation: none` on `::before`) so the placeholder displays as a static block. - [x] 1.5 Verify the existing `@media (prefers-reduced-motion: reduce)` rule in `global.css` already suppresses the shimmer `@keyframes` animation (it should — the global rule sets `animation-duration: 0.001ms !important`). ## 2. Card thumbnail shimmer - [x] 2.1 Update `StandardCard.astro` — wrap the existing `` in a `
`. Add class `img-loading` to the `` element. Keep the existing `.card-placeholder` fallback for cards with no image (no shimmer needed there). - [x] 2.2 Ensure the `.img-shimmer-wrap` inside `.card-media` inherits the correct dimensions (`width: 100%; height: 180px` on desktop, `200px` on mobile) without causing layout shift. ## 3. Blog featured image shimmer - [x] 3.1 Update `blog/post/[slug].astro` — wrap the featured `` in a `
` with matching inline styles (`width: 100%; max-height: 420px; border-radius: 16px; overflow: hidden;`). Add class `img-loading` to the ``. - [x] 3.2 Update `blog/page/[slug].astro` — same shimmer wrapper treatment as blog posts. ## 4. Image load/error script - [x] 4.1 Add an inline `