Theming done
Some checks failed
ci / site (push) Has been cancelled
publish-image / publish (push) Has been cancelled

This commit is contained in:
2026-02-10 20:10:06 -05:00
parent 6cb4d55241
commit 70710239c7
19 changed files with 1260 additions and 42 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-10

View File

@@ -0,0 +1,106 @@
## Context
The site currently uses a single dark theme defined via CSS variables in `site/public/styles/global.css` (e.g., `--bg0`, `--bg1`, `--fg`, `--muted`, `--stroke`, `--accent`). There is no existing theme selection mechanism (no `data-theme` attribute, no persisted preference).
The site shell uses a sticky `.site-header` and a per-page `.subnav` row (when present). A theme switcher notch must be fixed-positioned such that it does not overlap the header and leaves enough space for the subnav region.
## Goals / Non-Goals
**Goals:**
- Provide three themes: `dark`, `light`, `high-contrast`.
- Allow switching themes via a floating notch on the right side of the screen positioned below the primary nav bar and not overlapping the subnav area.
- Make switching feel premium:
- hover animation on the notch
- smooth theme transitions (without an abrupt flash)
- Ensure accessibility:
- keyboard operable
- visible focus
- respects `prefers-reduced-motion`
- high contrast theme is meaningfully higher contrast, not just a color swap
- Persist the user's selection across page loads.
**Non-Goals:**
- Rebuild the entire visual system or rewrite all CSS to a design-token framework.
- PWA theming (manifest/theme-color) beyond what is required to implement UI themes.
- Adding user accounts or server-side persistence of theme preference.
## Decisions
### 1. Theme selection mechanism: `data-theme` on `<html>`
Use `document.documentElement.dataset.theme = "dark" | "light" | "high-contrast"`.
Rationale:
- Works cleanly with CSS variables.
- Scopes theme styles across the entire page without specificity fights.
Alternatives considered:
- Adding theme classes to `body` (works, but html-scoped variables are simpler for form control theming).
### 2. Token strategy: override existing CSS variables per theme
Keep the existing variable names and provide theme-specific overrides:
- `:root` remains the default (dark)
- `html[data-theme="light"] { ... }`
- `html[data-theme="high-contrast"] { ... }`
Rationale:
- Minimizes churn in existing CSS.
- Enables incremental migration of any remaining hard-coded colors to tokens.
### 3. Default theme resolution order
On first load, resolve the active theme in this order:
1) stored user preference (`localStorage.theme`)
2) forced colors / high-contrast OS mode (if detected) -> `high-contrast`
3) system color scheme -> `light` if `prefers-color-scheme: light`, else `dark`
Rationale:
- User choice wins.
- If the user is in a forced/high-contrast environment, defaulting to high-contrast aligns with accessibility intent.
### 4. Prevent flash of wrong theme with a tiny head script
Insert a small inline script in the document `<head>` that sets `data-theme` before first paint.
Rationale:
- Avoids "flash" where the page renders in dark before switching to light/high-contrast.
Trade-off:
- Inline scripts can constrain future CSP hardening; keep script small and self-contained.
### 5. Smooth transitions without animating on every page load
Use a transient attribute/class (e.g., `data-theme-transition="on"`) only during user-initiated theme changes.
Implementation shape:
- When switching: set `data-theme-transition="on"`, update `data-theme`, then remove after ~250ms.
- CSS applies transitions for color/background/border/shadow only when the attribute is present.
Rationale:
- Avoids "everything animates" feeling during initial load.
- Avoids subtle jank on navigation.
### 6. Notch UI: fixed-position, expands on hover/focus
Implement the switcher as a fixed-position control at the right edge:
- Default collapsed: a small vertical tab.
- On `:hover` and `:focus-within`: expands into a small panel exposing the three theme options.
Accessibility decisions:
- Use a real `<button>` to open/close (for touch) OR a `<fieldset role="radiogroup">` with three radio-like buttons.
- Ensure it is reachable via keyboard and has clear `aria-label`s.
Placement decisions:
- Use a CSS variable `--theme-notch-top` to position it.
- A small inline script computes this based on `.site-header` height and, if a `.subnav` exists near the top, positions below it.
### 7. High Contrast theme semantics
The high-contrast theme will be a dedicated palette (not only increased brightness) with:
- strong background/foreground contrast
- high visibility focus ring
- more assertive stroke borders
Additionally, handle OS forced-colors mode:
- In `@media (forced-colors: active)`, prefer system colors and avoid gradients that reduce clarity.
## Risks / Trade-offs
- **[Notch overlaps content]** -> compute top offset from header/subnav; provide safe-area padding; add responsive rules for small viewports.
- **[Theme transitions reduce readability]** -> scope transitions to a short window and limit properties; disable via `prefers-reduced-motion`.
- **[High contrast breaks brand feel]** -> keep layout/typography unchanged and only adjust palette and borders.
- **[CSP constraints]** -> keep head script minimal and consider moving to an external script if CSP hardening becomes a priority.

View File

@@ -0,0 +1,27 @@
## Why
Add modern theming controls (dark/light/high-contrast) to improve accessibility and give the site a polished, customizable "WOW" experience.
## What Changes
- Add three user-selectable themes: **Dark**, **Light**, and **High Contrast**.
- Add a floating theme switcher "notch" on the right edge of the screen:
- positioned just below the primary nav bar
- leaves enough vertical space for secondary navigation
- hover state includes a tasteful animation
- Theme switching uses a smooth transition (not an abrupt flash).
## Capabilities
### New Capabilities
- `site-theming`: Theme tokens and a theme application mechanism that can switch between Dark/Light/High Contrast across the site.
- `theme-switcher-notch`: A floating, accessible UI control (right-side notch) that lets the user switch themes.
### Modified Capabilities
- `wcag-responsive-ui`: Extend accessibility baseline to include theme switching requirements (keyboard, focus, reduced motion) and ensure High Contrast theme is supported.
## Impact
- Affected UI/CSS: global design tokens (CSS variables), background layers, card/CTA styling, focus styling.
- Affected layout: a new floating notch component that must not overlap navigation across breakpoints.
- Affected UX/accessibility: keyboard navigation and motion preferences during theme transitions.

View File

@@ -0,0 +1,55 @@
## ADDED Requirements
### Requirement: Site themes
The site MUST support three themes:
- `dark`
- `light`
- `high-contrast`
Themes MUST be applied by setting a `data-theme` attribute on the root document element (`<html>`).
#### Scenario: Dark theme active
- **WHEN** `data-theme="dark"` is set on `<html>`
- **THEN** the site's background, text, and component styling reflect the dark palette
#### Scenario: Light theme active
- **WHEN** `data-theme="light"` is set on `<html>`
- **THEN** the site's background, text, and component styling reflect the light palette
#### Scenario: High contrast theme active
- **WHEN** `data-theme="high-contrast"` is set on `<html>`
- **THEN** the site uses a high-contrast palette with a clearly visible focus ring and high-contrast borders
### Requirement: Theme persistence
The site MUST persist the user's theme selection so it is retained across page loads and navigations.
Persistence MUST be stored locally in the browser (e.g., localStorage).
#### Scenario: Theme persists across reload
- **WHEN** the user selects `light` theme and reloads the page
- **THEN** the `light` theme remains active
### Requirement: Default theme selection
If the user has not explicitly selected a theme, the site MUST choose a default theme using environment signals.
Default selection order:
1) If forced colors / high-contrast mode is active, default to `high-contrast`
2) Else if the system prefers light color scheme, default to `light`
3) Else default to `dark`
#### Scenario: No stored preference uses system settings
- **WHEN** the user has no stored theme preference
- **THEN** the site selects a default theme based on forced-colors and prefers-color-scheme
### Requirement: Theme switching transition
Theme changes initiated by the user MUST transition smoothly.
The transition MUST be disabled or substantially reduced when `prefers-reduced-motion: reduce` is set.
#### Scenario: Smooth transition on switch
- **WHEN** the user switches from `dark` to `light` theme
- **THEN** theme-affecting properties transition smoothly instead of abruptly switching
#### Scenario: Reduced motion disables theme animation
- **WHEN** `prefers-reduced-motion: reduce` is set and the user switches theme
- **THEN** the theme change occurs without noticeable animation

View File

@@ -0,0 +1,42 @@
## ADDED Requirements
### Requirement: Floating theme switcher notch
The site MUST provide a floating theme switcher control anchored to the right side of the viewport.
The control MUST be positioned below the primary navigation bar and MUST leave sufficient vertical space for secondary navigation.
#### Scenario: Notch positioned below header
- **WHEN** the page loads
- **THEN** the theme switcher notch is visible on the right side and does not overlap the sticky header or sub-navigation
### Requirement: Notch interaction and animation
The notch MUST provide a hover affordance (a small, tasteful animation) that indicates it is interactive.
The hover animation MUST be disabled or substantially reduced under `prefers-reduced-motion: reduce`.
#### Scenario: Hover animation present
- **WHEN** a pointer user hovers the notch
- **THEN** the notch animates in a way that suggests it can be expanded or interacted with
#### Scenario: Reduced motion disables hover animation
- **WHEN** `prefers-reduced-motion: reduce` is set
- **THEN** hovering the notch does not trigger a noticeable animation
### Requirement: Theme selection UI
The notch MUST expose the three theme options (`dark`, `light`, `high-contrast`) and allow the user to select one.
The control MUST be keyboard accessible:
- it MUST be reachable via `Tab`
- it MUST have a visible focus indicator
- selection MUST be possible using keyboard input
#### Scenario: Keyboard selects theme
- **WHEN** a keyboard user focuses the notch and selects `high-contrast`
- **THEN** the site updates to the `high-contrast` theme and the selection is persisted
### Requirement: Accessibility labels
The notch and theme options MUST have accessible labels.
#### Scenario: Screen reader announces theme switcher
- **WHEN** a screen reader user focuses the theme switcher control
- **THEN** it announces an appropriate label (e.g., "Theme" or "Theme switcher") and the currently selected theme

View File

@@ -0,0 +1,30 @@
## ADDED Requirements
### Requirement: Theme switching accessibility
Theme switching controls MUST be accessible and usable with keyboard and assistive technology.
The theme switcher control MUST:
- be reachable via keyboard navigation
- provide a visible focus indication
- expose an accessible name/label
- allow selecting any supported theme without requiring a pointer
#### Scenario: Theme switcher is keyboard reachable
- **WHEN** a keyboard user tabs through the page
- **THEN** the theme switcher notch receives focus and shows a visible focus indicator
#### Scenario: Theme switcher is labeled
- **WHEN** a screen reader user focuses the theme switcher
- **THEN** it announces a meaningful label and the current theme state
### Requirement: High contrast theme meets WCAG intent
The `high-contrast` theme MUST provide materially higher contrast than the default theme.
The theme MUST keep text readable and interactive affordances obvious, including:
- strong foreground/background contrast
- clearly visible focus ring
- strong borders on interactive elements
#### Scenario: High contrast theme improves readability
- **WHEN** the user enables `high-contrast` theme
- **THEN** primary text and secondary UI labels remain clearly readable and interactive elements are visually distinct

View File

@@ -0,0 +1,26 @@
## 1. Theme Tokens And Application
- [x] 1.1 Add `data-theme` overrides in `site/public/styles/global.css` for `light` and `high-contrast` (keep `:root` as default dark)
- [x] 1.2 Add `color-scheme` rules per theme so native form controls match (dark/light)
- [x] 1.3 Add theme initialization script in `site/src/layouts/BaseLayout.astro` to set theme before first paint (stored preference → forced colors/high contrast → prefers-color-scheme)
- [x] 1.4 Persist theme selection to localStorage and update `data-theme` on change
- [x] 1.5 Implement scoped smooth transitions for user-initiated theme changes (no global transition on initial load)
## 2. Theme Switcher Notch UI
- [x] 2.1 Add markup for a fixed-position right-side notch in `site/src/layouts/BaseLayout.astro`
- [x] 2.2 Implement notch positioning below `.site-header` and below `.subnav` when present (compute top offset; handle resize)
- [x] 2.3 Add notch hover animation (expand/slide) and ensure it feels intentional
- [x] 2.4 Add keyboard and screen reader support (label, focus styles, keyboard selection)
- [x] 2.5 Ensure notch does not overlap critical content on mobile (responsive rules; safe-area)
## 3. High Contrast Theme Verification
- [x] 3.1 Ensure high-contrast theme has strong fg/bg contrast, obvious focus ring, and strong strokes on interactive elements
- [x] 3.2 Add `@media (forced-colors: active)` adjustments to avoid illegible gradients and ensure system colors are respected
## 4. Verification
- [x] 4.1 Run `npm run build` and verify output HTML includes the head theme-init script
- [x] 4.2 Manual smoke test: switch themes on `/`, `/videos`, `/podcast`, `/blog` and verify persistence across reload
- [x] 4.3 Manual a11y checks: keyboard-only interaction, focus visibility, prefers-reduced-motion behavior

View File

@@ -0,0 +1,92 @@
## Context
Chrome Lighthouse runs against `https://santhoshj.com/` (desktop + mobile) report several audits that prevent a 100 score.
Inputs:
- Desktop report: `C:\Users\simpl\Downloads\santhoshj.com-20260210T182644.json`
- Mobile report: `C:\Users\simpl\Downloads\santhoshj.com-20260210T182538.json`
Key failing audits (non-exhaustive):
- Accessibility: `color-contrast`
- SEO: `robots-txt`, `crawlable-anchors`
- Best Practices: `inspector-issues` (Content Security Policy)
- Performance: `render-blocking-insight`, `image-delivery-insight`, `unminified-css`, `unused-css-rules`, `unused-javascript`, `cache-insight` (plus mobile LCP/TTI pressure)
Constraints:
- Site is a static Astro build served behind Docker Compose + reverse proxy.
- Some assets are third-party (YouTube thumbnails, CloudFront podcast images, Umami script). These can influence some performance/cache audits and must be handled carefully (reduce impact where possible, but avoid breaking content).
- Service worker script MUST remain at stable URL `/sw.js` and should not be versioned via query string.
## Goals / Non-Goals
**Goals:**
- Achieve a 100 Lighthouse rating on the homepage in all categories (Performance, Accessibility, Best Practices, SEO) using the audits provided.
- Make contrast compliant (WCAG AA) for secondary text and pill/chip labels.
- Ensure SEO hygiene:
- `robots.txt` includes a valid (absolute) sitemap URL
- interactive elements do not render anchor tags without `href`.
- Remove DevTools Issues panel findings related to CSP by implementing an explicit CSP baseline that matches site needs.
- Reduce render-blocking requests and improve asset delivery so mobile LCP/TTI is consistently fast.
**Non-Goals:**
- Redesigning the site's visual identity or typography scale.
- Removing all third-party content sources (YouTube thumbnails, podcast cover images) or analytics.
- Building a full PWA manifest/offline-first experience (out of scope).
## Decisions
1. **Contrast remediation via token-level CSS adjustments**
Rationale: Lighthouse flags specific selectors in card footers and pills. Fixing contrast at the token level (e.g., `--muted`, pill bg/fg) avoids per-component overrides and reduces regressions.
Alternatives:
- Component-local overrides (harder to maintain, easy to miss).
2. **Robots sitemap MUST be absolute**
Rationale: Lighthouse treats `Sitemap: /sitemap-index.xml` as invalid. Robots will be updated to point at the full absolute URL.
Alternatives:
- Switch to `sitemap.xml` only (not desired; site already emits sitemap-index).
3. **No anchor elements without href in rendered HTML**
Rationale: Lighthouse flags the media modal anchors because they exist at load time without `href` (populated later by JS). Fix by using buttons for non-navigational actions, and ensuring any `<a>` is rendered with a valid `href` in initial HTML (or not rendered until it has one).
Alternatives:
- Keep anchors and set `href="#"` (still crawlable but semantically wrong, and can degrade UX).
4. **CSP baseline implemented at the edge (reverse proxy), compatible with site JS**
Rationale: DevTools Issues panel reports CSP issues. Implement a CSP that matches current needs (site inline scripts, Umami, fonts, images, frames) and remove/avoid inline scripts where possible to keep CSP strict.
Alternatives:
- Avoid CSP entirely (does not resolve audit and leaves security posture ambiguous).
5. **Font delivery: prefer self-hosting to remove render-blocking third-party CSS**
Rationale: Lighthouse render-blocking points to Google Fonts stylesheet. Self-hosting WOFF2 and using `@font-face` reduces blocking and improves reliability.
Alternatives:
- Keep Google Fonts and rely on preload hints (still incurs third-party CSS request; harder to reach 100).
6. **CSS delivery: move global CSS into the build pipeline (minified output)**
Rationale: Lighthouse flags unminified/unused CSS. Keeping `global.css` as a raw file in `public/` makes it harder to guarantee minification/unused pruning. Prefer having Astro/Vite handle minification and (where possible) pruning.
Alternatives:
- Add a bespoke minify step for `public/styles/global.css` (works, but adds build complexity and can drift).
7. **Caching headers: stable URLs get revalidated; fingerprinted assets get long-lived caching**
Rationale: Lighthouse cache-lifetime audit penalizes short cache lifetimes on first-party CSS/JS. For assets that are not fingerprinted (e.g., `/sw.js`, possibly `/styles/global.css`), use `no-cache` or revalidation to avoid staleness. For fingerprinted build outputs, use long-lived caching.
Alternatives:
- Querystring versioning on SW (known pitfall; can break update chain).
## Risks / Trade-offs
- **[CSP breaks site behavior]** → Start with Report-Only CSP, verify in production, then enforce. Prefer eliminating inline scripts to avoid `unsafe-inline`.
- **[Self-hosting fonts changes appearance slightly]** → Keep the same Manrope font files and weights, verify typography visually.
- **[Optimizing images reduces perceived sharpness]** → Use responsive images and appropriate sizes; keep high-DPR support via srcset.
- **[Third-party cache lifetimes cannot be controlled]** → Focus on first-party cache headers and reduce critical path reliance on third-party where possible.
## Migration Plan
1. Reproduce Lighthouse findings from a clean Chrome profile (no extensions) for both mobile/desktop.
2. Apply fixes in small slices (contrast, robots/anchors, CSP, fonts, CSS pipeline/minify, image delivery).
3. Deploy behind the reverse proxy with Report-Only CSP first.
4. Re-run Lighthouse on production URL until 100 is reached and stable.
5. Enable enforced CSP after confirming no violations.
## Open Questions
- What exact CSP issue is being reported in the DevTools Issues panel (violation message)? Lighthouse only surfaces the issue type without sub-items.
- Do we want to keep Google Fonts or commit to self-hosting fonts for maximum Lighthouse consistency?
- For cache-lifetime scoring: do we want to introduce fingerprinted CSS output (preferred) or add explicit versioning for `/styles/global.css`?

View File

@@ -0,0 +1,37 @@
## Why
Increase technical robustness by remediating the specific issues flagged by Chrome Lighthouse so the primary surface (homepage) can achieve a 100 score across categories.
Lighthouse sources:
- `C:\Users\simpl\Downloads\santhoshj.com-20260210T182644.json` (desktop)
- `C:\Users\simpl\Downloads\santhoshj.com-20260210T182538.json` (mobile)
## What Changes
- Fix accessibility contrast failures (WCAG AA) for card metadata and pill chips.
- Fix SEO hygiene issues:
- `robots.txt` must reference a valid sitemap URL
- eliminate non-crawlable anchor markup that Lighthouse flags (e.g., anchors without `href` in modal UI)
- Eliminate Best Practices "Issues" panel findings related to Content Security Policy.
- Improve Performance audits that prevent a perfect score, primarily on mobile:
- optimize above-the-fold image delivery (thumbnails/covers)
- reduce render-blocking resources (font CSS)
- ensure CSS/JS delivery is optimized (minification and unused code reduction)
- improve cache lifetimes where applicable for first-party assets, and mitigate third-party cache lifetime penalties where feasible.
## Capabilities
### New Capabilities
- `asset-delivery-optimization`: Ensure critical assets (CSS/fonts/images) are delivered in a Lighthouse-friendly way (minified, non-blocking where possible, and appropriately cached) and that mobile LCP is consistently fast.
- `security-headers`: Define and implement a CSP baseline and related headers that eliminate DevTools "Issues" panel findings without breaking third-party integrations.
### Modified Capabilities
- `wcag-responsive-ui`: Strengthen the baseline to explicitly require sufficient text contrast for secondary/muted UI text and pill/chip labels so the site passes Lighthouse contrast checks.
- `seo-content-surface`: Strengthen robots + sitemap correctness and require that link-like UI uses crawlable markup (valid `href` when an anchor is used).
## Impact
- Affected UI/CSS: card footer metadata (`.muted`) and pill styling; modal CTA markup.
- Affected SEO assets: `robots.txt` sitemap line.
- Affected security posture: CSP and related headers (may require changes to how third-party scripts are loaded).
- Affected performance: image source/size strategy for thumbnails/covers; font delivery strategy; CSS/JS build pipeline and cache headers.

View File

@@ -0,0 +1,47 @@
## ADDED Requirements
### Requirement: Render-blocking resources are minimized
The site MUST minimize render-blocking resources on the critical path.
Font delivery MUST NOT rely on a render-blocking third-party stylesheet.
#### Scenario: Homepage avoids render-blocking font CSS
- **WHEN** Lighthouse audits the homepage
- **THEN** the Google Fonts stylesheet request is not present as a render-blocking resource (fonts are self-hosted or otherwise delivered without a blocking CSS request)
### Requirement: First-party CSS and JS are optimized for Lighthouse
First-party CSS and JS delivered to the browser MUST be minified in production builds.
The site MUST minimize unused CSS and unused JavaScript on the homepage.
#### Scenario: CSS is minified
- **WHEN** a production build is served
- **THEN** `styles/global.css` (or its replacement) is minified
#### Scenario: Homepage avoids unused JS penalties
- **WHEN** Lighthouse audits the homepage
- **THEN** the amount of unused JavaScript on initial load is below Lighthouse's failing threshold
### Requirement: Images are delivered efficiently
Images used on listing surfaces MUST be delivered in a size appropriate to their rendered dimensions.
For thumbnail-like images, the site SHOULD prefer image sources that support resizing or multiple resolutions when feasible.
#### Scenario: Podcast cover image is not oversized
- **WHEN** the homepage renders a podcast episode card
- **THEN** the fetched cover image size is reasonably close to the displayed size (no large wasted bytes flagged by Lighthouse)
### Requirement: Cache lifetimes are efficient for first-party assets
First-party static assets (CSS/JS/fonts/images served from the site origin) MUST be served with cache headers that enable efficient repeat visits.
Non-fingerprinted assets MUST be served with revalidation (e.g., `no-cache` or `max-age=0,must-revalidate`) to avoid staleness.
Fingerprinted assets (build outputs) MUST be served with a long-lived immutable cache policy.
#### Scenario: First-party CSS has efficient caching
- **WHEN** Lighthouse audits the homepage
- **THEN** first-party CSS cache lifetimes are not flagged as inefficient
#### Scenario: Service worker script is revalidated
- **WHEN** the browser checks `/sw.js` for updates
- **THEN** the HTTP cache is bypassed or revalidated so an updated service worker can be fetched promptly

View File

@@ -0,0 +1,25 @@
## ADDED Requirements
### Requirement: Content Security Policy baseline
The deployed site MUST include a Content Security Policy (CSP) that is compatible with the site's runtime behavior and third-party integrations.
The CSP MUST be strict enough to avoid DevTools Issues panel findings related to CSP and MUST NOT rely on a permissive `*` wildcard for script sources.
The CSP MUST allow:
- the site's own scripts and styles
- the configured analytics script origin (Umami)
- required image origins (e.g., YouTube thumbnail host and podcast image CDN)
- required frame origins (e.g., YouTube and Spotify embeds)
#### Scenario: No CSP issues logged
- **WHEN** a user loads the homepage in Chrome
- **THEN** no CSP-related issues are reported in the DevTools Issues panel
### Requirement: Avoid inline-script CSP violations
The site SHOULD minimize the use of inline scripts to avoid requiring `unsafe-inline` in CSP.
If inline scripts are necessary, the CSP MUST use a nonce-based or hash-based approach.
#### Scenario: Inline scripts do not require unsafe-inline
- **WHEN** the site is served with CSP enabled
- **THEN** the policy does not require `script-src 'unsafe-inline'` to function

View File

@@ -0,0 +1,39 @@
## MODIFIED Requirements
### Requirement: Sitemap and robots
The site MUST provide:
- `sitemap.xml` enumerating indexable pages
- `robots.txt` that allows indexing of indexable pages
The sitemap MUST include the blog surface routes:
- `/blog`
- blog post detail routes
- blog page detail routes
- blog category listing routes
`robots.txt` MUST include a `Sitemap:` directive with an absolute URL to the sitemap (or sitemap index) and MUST NOT use a relative sitemap URL.
#### Scenario: Sitemap is available
- **WHEN** a crawler requests `/sitemap.xml`
- **THEN** the server returns an XML sitemap listing `/`, `/videos`, `/podcast`, `/about`, and `/blog`
#### Scenario: Blog URLs appear in sitemap
- **WHEN** WordPress content is available in the cache at build time
- **THEN** the generated sitemap includes the blog detail URLs for those items
#### Scenario: robots.txt includes absolute sitemap URL
- **WHEN** a crawler requests `/robots.txt`
- **THEN** the response includes a `Sitemap:` directive with an absolute URL (e.g., `https://<domain>/sitemap-index.xml`) that Lighthouse and crawlers can parse
## ADDED Requirements
### Requirement: Crawlable link markup
The site MUST NOT render anchor elements (`<a>`) without an `href` attribute.
Interactive UI that does not navigate MUST use a `<button>` element (or equivalent role) instead of a placeholder anchor.
If an anchor is used for navigation, it MUST include a valid `href` in the initial HTML (not only populated later by client-side JavaScript).
#### Scenario: Modal CTAs are crawlable
- **WHEN** the homepage is loaded and the media modal markup exists in the DOM
- **THEN** any CTA anchors within the modal have valid `href` values, or are not rendered as anchors until an `href` is available

View File

@@ -0,0 +1,18 @@
## ADDED Requirements
### Requirement: Color contrast for secondary UI text and chips
The site MUST meet WCAG 2.2 AA contrast requirements for non-decorative text, including secondary/muted metadata text and pill/chip labels.
This includes (but is not limited to):
- card footer date and view-count text
- pill/chip labels (e.g., source labels)
The contrast ratio MUST be at least 4.5:1 for normal text.
#### Scenario: Card metadata contrast passes
- **WHEN** a content card is rendered with date and view-count metadata
- **THEN** the metadata text has a contrast ratio of at least 4.5:1 against its background
#### Scenario: Pill label contrast passes
- **WHEN** a pill/chip label is rendered (e.g., a source label)
- **THEN** the pill label text has a contrast ratio of at least 4.5:1 against the pill background

View File

@@ -0,0 +1,39 @@
## 1. Baseline And Repro
- [ ] 1.1 Run Lighthouse from a clean Chrome profile (no extensions) for both Mobile and Desktop and save reports (JSON)
- [ ] 1.2 Record current failing audits and their affected selectors/URLs (from the Lighthouse "details" tables)
## 2. Accessibility Contrast
- [ ] 2.1 Adjust global CSS tokens/styles so `.muted` card metadata meets 4.5:1 contrast on cards
- [ ] 2.2 Adjust pill/chip background + text colors to meet 4.5:1 contrast (e.g., `.pill` and source variants)
- [ ] 2.3 Re-run Lighthouse accessibility category and confirm `color-contrast` passes
## 3. SEO Hygiene (robots + crawlable links)
- [ ] 3.1 Update `site/public/robots.txt` to use an absolute sitemap URL (e.g., `Sitemap: https://santhoshj.com/sitemap-index.xml`)
- [ ] 3.2 Fix non-crawlable anchors in the media modal by ensuring anchors always have `href` in initial HTML or switching to buttons until navigable
- [ ] 3.3 Re-run Lighthouse SEO category and confirm `robots-txt` and `crawlable-anchors` pass
## 4. CSP / Best Practices
- [ ] 4.1 Identify the exact CSP-related DevTools Issue message (Chrome DevTools → Issues) and capture the text
- [ ] 4.2 Implement a CSP baseline at the reverse proxy/origin that allows required resources (self + Umami + image/frame origins) and avoids permissive wildcards
- [ ] 4.3 Reduce inline scripts that force `unsafe-inline` (move registration / modal scripts to external files or use nonce/hash approach)
- [ ] 4.4 Re-run Lighthouse Best Practices and confirm `inspector-issues` passes
## 5. Performance: Fonts, CSS/JS, And Images
- [ ] 5.1 Remove render-blocking third-party font stylesheet by self-hosting Manrope and loading via `@font-face`
- [ ] 5.2 Ensure production CSS is minified (move global CSS into the build pipeline or add a build minification step)
- [ ] 5.3 Reduce unused CSS on the homepage (prune unused selectors or split critical vs non-critical styles)
- [ ] 5.4 Reduce unused JS on the homepage (remove unnecessary scripts; ensure analytics is async/defer; avoid extra inline code)
- [ ] 5.5 Improve thumbnail image delivery (use responsive `srcset` / resized sources where feasible; avoid oversized podcast covers)
- [ ] 5.6 Improve cache lifetimes for first-party static assets (fingerprint + immutable cache for build assets; revalidate non-fingerprinted)
- [ ] 5.7 Re-run Lighthouse Performance (mobile + desktop) and confirm 100 score
## 6. Verification
- [ ] 6.1 Run `npm run build` and ensure build succeeds
- [ ] 6.2 Smoke test site locally (`npm run preview`) including modal, analytics script load, and service worker registration
- [ ] 6.3 Deploy and confirm production Lighthouse scores are 100/100/100/100