Skip to content

Latest commit

 

History

History
539 lines (396 loc) · 20.1 KB

codebase-consistency-implementation-plan.md

File metadata and controls

539 lines (396 loc) · 20.1 KB

Codebase Consistency — Implementation Plan

Created: 2026-09-10 Generated by: /prompts/codebase-consistency-audit/orchestrator.md Audit reports: /reports/codebase-consistency-audit/ Task tracking: /tasks/codebase-consistency-audit-tasks.md Status: ✅ All items implemented (2026-06-19)


Background

This plan was produced by running the codebase consistency audit prompt: /prompts/codebase-consistency-audit/orchestrator.md

The audit covered five domains across the Nova News codebase:

  1. Button padding and variant inconsistencies

  2. Hardcoded values vs design token usage

  3. Illegal inline styles in TSX components

  4. Unguarded console logging

  5. Undefined / mismatched CSS custom property references

The most impactful finding was systemic: dozens of --wp--preset--* tokens were referenced across button.css, read-more-btn.css, and not-found-page.css but never defined anywhere. Every button focus ring, hover glow, and border radius silently fell back to empty — an invisible regression across all interactive elements site-wide.


Severity Overview

Priority Count Description
🔴 Critical 6 items Silent visual breakage — undefined tokens causing invisible states
🟠 High 9 items Standards violations — hardcoded values, unguarded logs, inline styles
🟡 Medium 5 items Inconsistencies to resolve — dual token system, CSS var injection

🔴 Critical Fixes

Critical fixes resolve silent failures — issues where no error is thrown but visual output is broken or missing.


CRIT-01 — Define all missing shadow, border-radius, z-index tokens

Audit refs: E-01, E-02, E-07 Root cause: button.css referenced --wp--preset--shadow--focus-ring, --wp--preset--border-radius--full, --wp--preset--z-index--0 etc. — none existed in globals.css. Every button focus state, pill radius, and layering rule silently rendered as empty. Affected files: src/styles/blocks/button.css, src/styles/blocks/read-more-btn.css, src/styles/tokens/content-interactive.css Fix: Add complete token blocks to globals.css :root {}

/* Shadow tokens */
--wp--preset--shadow--focus-ring: 0 0 0 3px rgba(255, 16, 240, 0.4);
--wp--preset--shadow--neon-sm: 0 0 8px rgba(255, 16, 240, 0.35);
--wp--preset--shadow--card-hover: 0 8px 24px rgba(0, 0, 0, 0.4);
--wp--preset--shadow--neon-pink: 0 0 12px rgba(255, 16, 240, 0.5), 0 0 24px
rgba(255, 16, 240, 0.25);
--wp--preset--shadow--neon-blue: 0 0 12px rgba(31, 81, 255, 0.5), 0 0 24px
rgba(31, 81, 255, 0.25);
--wp--preset--shadow--neon-purple: 0 0 12px rgba(190, 0, 254, 0.5), 0 0 24px
rgba(190, 0, 254, 0.25);

/* Border-radius tokens */
--wp--preset--border-radius--full: 9999px;
--wp--preset--border-radius--circle: 50%;
--wp--preset--border-radius--lg: 1rem;
--wp--preset--border-radius--md: 0.5rem;
--wp--preset--border-radius--sm: 0.25rem;

/* Z-index tokens */
--wp--preset--z-index--n1: -1;
--wp--preset--z-index--0: 0;
--wp--preset--z-index--1: 1;
--wp--preset--z-index--10: 10;
--wp--preset--z-index--100: 100;
--wp--preset--z-index--overlay: 1000;
--wp--preset--z-index--modal: 9000;
--wp--preset--z-index--toast: 9999;

```text

**Implemented:** ✅ 2026-06-19 — Added to `src/styles/globals.css` `:root {}`

---

### CRIT-02 — Define missing semantic colour aliases

**Audit refs:** E-03, E-04
**Root cause:** `not-found-page.css` used `--wp--preset--color--base` and
`--wp--preset--color--contrast`; `button.css` used
`--wp--preset--color--primary`, `--wp--preset--color--neon-purple`,
`--wp--preset--color--neon-purple-text`, `--wp--preset--color--neon-pink-text`.
None were defined.
**Affected files:** `src/styles/blocks/button.css`,
`src/styles/blocks/not-found-page.css`, `src/styles/blocks/read-more-btn.css`
**Fix:**

```css
/* Semantic aliases */
--wp--preset--color--primary: var(--wp--preset--color--neon-pink);
--wp--preset--color--base: var(--wp--preset--color--atomic-black);
--wp--preset--color--contrast: var(--wp--preset--color--text-light);

/* Neon aliases */
--wp--preset--color--neon-purple: var(--wp--preset--color--uv-violet);
--wp--preset--color--neon-purple-text: #6B3FCC;
--wp--preset--color--neon-pink-text: #CC007A;
--wp--preset--color--neon-red: #FF3860;

```text

**Implemented:** ✅ 2026-06-19 — Added to `src/styles/globals.css` `:root {}`

---

### CRIT-03 — Define missing font-family and spacing tokens

**Audit refs:** E-05, E-06
**Root cause:** `button-variations.css` referenced
`--wp--preset--font-family--brand-body`; multiple layout files referenced
`--wp--preset--spacing--fluid-*` and `--wp--preset--spacing--section-*`. None
existed. Buttons fell back to browser default font; section padding collapsed.
**Affected files:** `src/styles/blocks/button-variations.css`, multiple layout
blocks
**Fix:**

```css
/* Font family brand aliases */
--wp--preset--font-family--brand-heading:
var(--wp--preset--font-family--heading);
--wp--preset--font-family--brand-body: var(--wp--preset--font-family--body);
--wp--preset--font-family--brand-title: 'Righteous',
var(--wp--preset--font-family--heading);

/* Spacing scale */
--wp--preset--spacing--10: 0.5rem;
--wp--preset--spacing--20: 1rem;
--wp--preset--spacing--30: 1.5rem;
--wp--preset--spacing--40: 2rem;
--wp--preset--spacing--50: 2.5rem;
--wp--preset--spacing--60: 3rem;
--wp--preset--spacing--80: 5rem;

/* Fluid spacing scale */
--wp--preset--spacing--fluid-xs: clamp(0.25rem, 1vw, 0.5rem);
--wp--preset--spacing--fluid-sm: clamp(0.5rem, 1.5vw, 1rem);
--wp--preset--spacing--fluid-md: clamp(1rem, 3vw, 2rem);
--wp--preset--spacing--fluid-lg: clamp(2rem, 5vw, 4rem);
--wp--preset--spacing--fluid-xl: clamp(3rem, 7vw, 6rem);
--wp--preset--spacing--fluid-2xl: clamp(4rem, 10vw, 8rem);
--wp--preset--spacing--section-horizontal: clamp(1.5rem, 6vw, 4rem);
--wp--preset--spacing--section-vertical: clamp(3rem, 8vw, 6rem);

```text

**Implemented:** ✅ 2026-06-19 — Added to `src/styles/globals.css` `:root {}`

---

### CRIT-04 — Consolidate button padding to fluid `clamp()` system

**Audit refs:** A-01, A-02, A-03
**Root cause:** Three competing button systems existed (`.btn`, `.button`,
`.wp-block-button_*link`) with incompatible padding. `.wp-block-button*_link`
used hardcoded `12px 24px`; `read-more-btn.css` used fixed `rem` values;
`.button` in `globals.css` used pixel values. None were responsive.

## Three systems identified

- `.btn` — canonical system in `button.css` (correct)
- `.button` — legacy in `globals.css` (used by `EbookLandingPage.tsx`, `EbookSettingsModal.tsx` — cannot delete)
- `.wp-block-button__link` — WordPress-style in `button-variations.css`

**Fix approach:** Standardise padding to `clamp()` in all three. `.button`
retained as legacy but modernised.

**Changes:**

| File | Before | After |
|---|---|---|
| `button-variations.css` | `padding: 12px 24px` | `padding: clamp(0.75rem, 1.5vw, 1rem) clamp(1.5rem, 4vw, 2.5rem)` |
| `button-variations.css` (ghost) | `padding: 8px 16px` | `padding: clamp(0.25rem, 1vw, 0.5rem) clamp(0.75rem, 2vw, 1rem)` |
| `read-more-btn.css` | `padding: 0.75rem 1.25rem` | `padding: clamp(0.5rem, 1.25vw, 0.75rem) clamp(0.875rem, 2.5vw, 1.25rem)` |
| `read-more-btn.css` (compact) | `padding: 0.25rem 0.75rem` | `padding: clamp(0.2rem, 0.75vw, 0.375rem) clamp(0.5rem, 1.5vw, 0.875rem)` |
| `globals.css` `.button` | `padding: 12px 24px` | `padding: clamp(0.75rem, 1.5vw, 1rem) clamp(1.5rem, 4vw, 2.5rem)` |

**Implemented:** ✅ 2026-06-19

---

## 🟠 High Priority Fixes

High priority fixes address standards violations that will cause regressions if
left unchecked.

---

### HIGH-01 — Replace hardcoded hex in `globals.css` selectors

**Audit ref:** B-01
**Root cause:** Component-level selectors in `globals.css` hardcoded brand
colours directly instead of consuming design tokens. Theme switching would not
affect these values.
**Affected file:** `src/styles/globals.css`

| Selector | Before | After |
|---|---|---|
| `.header__nav-link` | `color: #F6F2EB` | `color: var(--color-text-light)` |
| `.header__nav-link:hover` | `color: #FF10F0` | `color: var(--color-neon-pink)` |
| `.header__nav-link--active` | `color: #F4FF3C` | `color: var(--color-neon-yellow)` |
| `.form--error` | `border-color: #FF3860` | `border-color: var(--wp--preset--color--neon-red)` |
| `.button--primary` | `color: #fff` | `color: var(--wp--preset--color--white)` |
| `.button--primary:hover` | `background-color: #ff52b9` | `background-color: var(--wp--preset--color--neon-magenta)` |

**Implemented:** ✅ 2026-06-19

---

### HIGH-02 — Replace hardcoded pixel `font-size` with `clamp()`

**Audit ref:** B-03
**Root cause:** Typography utility classes in `globals.css` used fixed `px`
values, breaking fluid scaling and accessibility zoom behaviour.
**Affected file:** `src/styles/globals.css`

| Class | Before | After |
|---|---|---|
| `.eyebrow` | `font-size: 12px` | `font-size: clamp(0.625rem, 1vw, 0.75rem)` |
| `.heading-card` | `font-size: 24px` | `font-size: clamp(1.25rem, 2.5vw, 1.5rem)` |
| `.text-body` | `font-size: 16px` | `font-size: clamp(0.875rem, 1.5vw, 1rem)` |
| `.text-fine` | `font-size: 12px` | `font-size: clamp(0.625rem, 1vw, 0.75rem)` |
| `.form__label` | `font-size: 14px` | `font-size: clamp(0.75rem, 1.25vw, 0.875rem)` |

**Implemented:** ✅ 2026-06-19

---

### HIGH-03 — Fix unguarded `console.log` in `ThemeToggleES5.tsx`

**Audit ref:** D-01
**Root cause:** `ThemeToggleES5.tsx:79` used `if (typeof console !== 'undefined'
&& console.log)` — a non-standard guard that does not strip the log from
production builds.
**Affected file:** `src/app/components/common/ThemeToggleES5.tsx`
**Fix:**

```tsx
// Before
if (typeof console !== 'undefined' && console.log) {
  console.log('Theme toggled to:', newMode ? 'dark' : 'light');
}

// After
if (import.meta.env.DEV) {
  console.log('Theme toggled to:', newMode ? 'dark' : 'light');
}

```text

**Note:** `import.meta.env.DEV` is bundler-safe in Vite but forbidden in
router/lib code per bundler constraints. This component is a React component
(not a lib file), so the usage is acceptable.

**Implemented:** ✅ 2026-06-19

---

### HIGH-04 — Refactor `PaletteDemoModal.tsx` layout inline styles to BEM

**Audit ref:** C-01
**Root cause:** 40+ inline styles for layout, spacing, and typography in
`PaletteDemoModal.tsx` — the demo functions `DashboardDemo`, `GradientTextDemo`,
`ButtonDemo`, `NavigationDemo`, `GradientBackgroundDemo` all used `style={{}}`
for structural styles.
**Affected files:** `src/app/components/ui/PaletteDemoModal.tsx`,
`src/styles/blocks/palette-demo-modal.css`

## New BEM classes created in `palette-demo-modal.css`

- `.demo-section` — base wrapper with padding and background
- `.demo-section--padded`, `.demo-section--centered` — modifiers
- `.demo-section_*grid`, `.demo-section*_flex-row` — layout children
- `.demo-section_*heading`, `.demo-section**body-text`, `.demo-section*_subtext` — typography
- `.demo-section_*nav`, `.demo-section*_nav-link` — navigation demo
- `.demo-card_*title`, `.demo-card**body`, `.demo-card*_btn` — card elements

**Preserved as acceptable exceptions** (dynamic, no CSS alternative):

- `style={{ color: color.hex }}` — live colour swatch
- `style={{ background: 'linear-gradient(...)' }}` — dynamic gradient from data
- `style={{ boxShadow: ... }}` — dynamic neon from data

**Implemented:** ✅ 2026-06-19

---

### HIGH-05 — Sweep `dark.css` and `dark-extended.css` — replace hex with tokens

**Audit refs:** B-02, E-09
**Root cause:** Component-level overrides in the theme files bypassed the token
system and hardcoded brand colours directly. Theme reconfiguration would require
hunting every hex occurrence rather than changing one token value.
**Affected files:** `src/styles/themes/dark.css`,
`src/styles/themes/dark-extended.css`

## Replacements applied (systemic pass)

| Hex | Token |
|---|---|
| `#0F0F0F` | `var(--color-atomic-black)` |
| `#F6F2EB` | `var(--color-text-light)` |
| `#FF3AAE` | `var(--color-neon-pink)` |
| `#CFC7BB` | `var(--color-text-muted)` |
| `#333333` | `var(--color-border)` |
| `#1A1A1A` | `var(--color-surface-elevated)` |
| `#222222` | `var(--color-divider)` |
| `#FFFFFF` | `var(--wp--preset--color--white)` |

**Scope:** body, header, footer, sidebar, nav-menu, figure, figcaption
overrides.

**Implemented:** ✅ 2026-06-19

---

## 🟡 Medium Priority Fixes

Medium fixes address inconsistencies that violate the BEM/token contract but do
not produce immediate visual regressions.

---

### MED-01 — CSS custom property injection for `TimelinePage.tsx` dynamic colours

**Audit ref:** C-02
**Root cause:** `TimelinePage.tsx` applied dynamic category colours via
`style={{ borderColor: accentColor }}`, `style={{ color: accentColor }}`, and
`style={{ backgroundColor: catMeta.neonColour }}` directly — a violation of the
no-inline-styles rule.
**Approach:** Use the accepted CSS var injection pattern. Inject runtime value
as a custom property; consume in CSS with `var()`.

## Changes in `TimelinePage.tsx`

```tsx
// Before
style={{ borderColor: accentColor }}
style={{ color: accentColor }}
style={{ backgroundColor: catMeta.neonColour }}

// After
style={{ '--timeline-accent': accentColor } as React.CSSProperties}
// icon color: removed from JSX, handled by CSS var
style={{ '--cat-neon': catMeta.neonColour } as React.CSSProperties}

```text

## Changes in `timeline-page.css`

```css
.timeline-card { border: 2px solid var(--timeline-accent,
var(--wp--preset--color--neutral-200)); }
.timeline-card__icon { color: var(--timeline-accent,
var(--wp--preset--color--neon-pink)); }
.timeline-card__category { background-color: var(--cat-neon,
var(--wp--preset--color--neon-pink)); }
.timeline-legend-item__icon { color: var(--cat-neon,
var(--wp--preset--color--neon-pink)); }
.timeline-legend-item__color { background-color: var(--cat-neon,
var(--wp--preset--color--neon-pink)); }

```text

**Implemented:** ✅ 2026-06-19

---

### MED-02 — CSS custom property injection for `HistoryPage.tsx` legend dots

**Audit ref:** C-03
**Root cause:** `HistoryPage.tsx:134` used `style={{ background: catHex }}` on
legend dot elements.
**Approach:** Same CSS var injection pattern as MED-01.

## Changes in `HistoryPage.tsx`

```tsx
// Before
style={{ background: catHex }}

// After
style={{ '--cat-hex': catHex } as React.CSSProperties}

```text

## Changes in `history-page.css`

```css
.history-page__legend-dot {
  background: var(--cat-hex, var(--wp--preset--color--neon-pink));
}

```text

**Implemented:** ✅ 2026-06-19

---

### MED-03 — Classify and confirm `PressKitPage.tsx` and `WhySection.tsx` inline styles

**Audit refs:** C-04, C-05
**Outcome:** Both confirmed as accepted exceptions — no change required.

- **`PressKitPage.tsx:38`** — `backgroundImage` with dynamic URL + gradient overlay. No CSS-only alternative for a data-driven URL.
- **`WhySection.tsx:152`** — CSS custom property injection for slider animation (`--slide-index`, `--slides-per-view`). This is the accepted pattern, used correctly.

**Implemented:** ✅ 2026-06-19 — Confirmed accepted, documented in consolidated
report.

---

### MED-04 — Deprecate legacy `.button` block in `globals.css`

**Audit ref:** B-05
**Root cause:** The legacy `.button` system in `globals.css` conflicts with the
canonical `.btn` system in `button.css`. Cannot be deleted because
`EbookLandingPage.tsx` and `EbookSettingsModal.tsx` depend on `.button--primary`
and `.button--secondary`.
**Approach:** Modernise in place — update to use `clamp()`, token refs, and
brand fonts. Add deprecation comment. Do not delete.

## Changes applied to `.button` block in `globals.css`

- `padding: 12px 24px` → `padding: clamp(0.75rem, 1.5vw, 1rem) clamp(1.5rem, 4vw, 2.5rem)`
- `font-family: [literal]` → `font-family: var(--wp--preset--font-family--brand-heading)`
- `font-size: [px]` → `font-size: clamp(0.875rem, 1.5vw, 1rem)`
- `border-radius: [px]` → `border-radius: var(--wp--preset--border-radius--full)`
- `color: #fff` → `color: var(--wp--preset--color--white)`
- `background-color: #ff52b9` → `background-color: var(--wp--preset--color--neon-magenta)`

**Implemented:** ✅ 2026-06-19

---

### MED-05 — Adopt single token convention going forward

**Audit refs:** B-04, E-08
**Root cause:** Some CSS files use legacy `--color-*` tokens; others use
`--wp--preset--color--*`. The legacy tokens are aliased from the wp-preset
tokens in `globals.css` `:root {}`, so they technically resolve — but mixing
conventions makes grepping and auditing harder.
**Decision:** Both conventions remain valid. Legacy `--color-*` tokens are
aliased and intentionally preserved for backwards compatibility. New code should
prefer `--wp--preset--color--*`. No bulk rename required.

**Status:** Accepted as-is — documented as intentional dual-alias system. No
file changes needed.

---

## Accepted Exceptions — No Action Required

These inline styles were reviewed and classified as acceptable during the audit:

| File | Pattern | Reason |
|---|---|---|
| `PortfolioMegaMenu.tsx` | `--col-index`, `--item-index` | CSS var injection for animation stagger |
| `BlogMegaMenu.tsx` | `--item-index` | CSS var injection for animation stagger |
| `AboutDropdown.tsx` | `--node-index` | CSS var injection for animation stagger |
| `BlogPostPage.tsx:243` | `width: readingProgress + '%'` | Dynamic progress bar — no CSS alternative |
| `PodcastDetailPage.tsx:177` | `width: readingProgress + '%'` | Dynamic progress bar — no CSS alternative |
| `PortfolioCard.tsx:194` | `backgroundImage: url(...)` | Dynamic asset URL from data |
| `ResponsiveGridSlider.tsx:183,191` | `flex` basis percentage | Computed from data — no CSS alternative |
| `PaletteDemoModal.tsx` | `color: hex`, gradient, boxShadow | Dev-tool context — live colour swatches |
| `PressKitPage.tsx:38` | `backgroundImage` + gradient | Dynamic URL + gradient overlay |
| `WhySection.tsx:152` | `--slide-index`, `--slides-per-view` | CSS var injection for slider |
| `ErrorBoundary.tsx:196–199` | `console.error` | `componentDidCatch` crash reporting |
| `StyleGuidePage.tsx:661` | `console.log` | String literal in demo code (not a call) |
| `extensionErrorSuppressor.ts` | `console.*` | Suppressor utility |

---

## Re-run Instructions

Run this audit again after any major sprint to catch regressions. The prompt is
at:
`/prompts/codebase-consistency-audit/orchestrator.md`

## Trigger conditions

- After adding a new page component
- After any CSS refactor
- Before a production deployment
- After a third-party dependency update

**Process:**

1. Archive the previous report folder to `/reports/archive/`

1. Execute all 5 sub-audits in order: E → B → A → C → D

1. Save reports to `/reports/codebase-consistency-audit/`

1. Save actionable plan to `/plan/` (this folder)

1. Update task tracking in `/tasks/`

---

## Files Modified in This Implementation

| File | Change Type | Summary |
|---|---|---|
| `src/styles/globals.css` | Major additions + selector fixes | ~60 token definitions added; 6 hex selectors replaced; 5 px font-sizes converted |
| `src/styles/blocks/button-variations.css` | Padding fix | `clamp()` padding on all variants; `--wp--preset--` token refs |
| `src/styles/blocks/read-more-btn.css` | Padding fix | `clamp()` padding on default and compact variants |
| `src/styles/themes/dark.css` | Sweep | All hex in component overrides replaced with `--color-*` token refs |
| `src/styles/themes/dark-extended.css` | Sweep | All hex in sidebar, nav, figure overrides replaced with `--color-*` token refs |
| `src/styles/blocks/palette-demo-modal.css` | New BEM classes | 14 new structural classes added |
| `src/app/components/ui/PaletteDemoModal.tsx` | Inline style removal | Static `style={{}}` replaced with BEM classNames in 5 demo functions |
| `src/app/components/common/ThemeToggleES5.tsx` | Console guard fix | `console.log` wrapped in `import.meta.env.DEV` |
| `src/app/components/pages/about/TimelinePage.tsx` | CSS var injection | Dynamic colour applied via `--timeline-accent` and `--cat-neon` props |
| `src/styles/blocks/timeline-page.css` | CSS var consumers | `var(--timeline-accent)` and `var(--cat-neon)` on card, icon, category, legend |
| `src/app/components/pages/about/HistoryPage.tsx` | CSS var injection | Legend dot colour applied via `--cat-hex` prop |
| `src/styles/blocks/history-page.css` | CSS var consumer | `var(--cat-hex)` on `.history-page__legend-dot` |