--- name: Portfolio 2026 Theme Design description: Surface overhaul, conflict resolution, and template build-out for the ks-portfolio WordPress theme. created: 2026-08-16 status: approved --- # Portfolio 2026 Theme — Design Spec ## 1. Purpose Rebuild the surface of `ks-portfolio` (WordPress theme at `wp-content/themes/ks-portfolio/`) to match the **Portfolio 2026** identity defined in `notes/DESIGN.md`, `notes/TOKENS.md`, and the three mockups (`home-screen.png`, `archive-screen.png`, `single-screen.png`). Resolve the documented conflicts in `notes/DESIGN.md` §12. Keep the SoloFrame Evo architecture and the installed `projects-portfolio` plugin as-is; build only the presentation layer. ## 2. Source hierarchy When sources disagree, follow `notes/DESIGN.md` §1. In short: 1. `style.css` for current identity. 2. `notes/Projects Plugin Design.md` for content model. 3. `notes/Background Gradient.md` for atmospheric field. 4. `theme.json`, `styles/`, ACF JSON, templates for implemented tokens. 5. `README.md` and `docs/` for inherited architecture. User decisions (locked at brainstorm time): - **Projects source**: theme renders templates against the `projects` CPT provided by the installed `projects-portfolio` plugin. The theme does NOT re-register the CPT. - **Mockup content**: live `projects` CPT with empty-state fallbacks ("Nothing here yet..."). The mockups are layout references, not content sources. - **Test scope**: Chromium + axe only. Firefox / WebKit / mobile are out of scope. - **Pen-test**: static security audit (PHPCS + grep + manual review). No OWASP ZAP. ## 3. Identity & naming - `style.css` keeps `Theme Name: Portfolio 2026`, `Text Domain: ks-portfolio`. - PHP namespace `SoloFrameEvo` → `KsPortfolio` across all PHP files (composer script + manual review). - Drop `screenshot.png` (Basic WP) at the end; replace with a Carbon-Blue-themed capture. ## 4. Visual system ### 4.1 Body surface ```css body { background-color: #100e0b; /* Carbon Blue page base */ color: var(--color-on-surface); /* #e3e1e9 — ~14:1 on dark */ } ``` The existing rule `main#maincontent { background: var(--color-background); }` is removed. Sections paint directly on the dark body; there is no light block underneath content. ### 4.2 Carbon Blue atmospheric field Implemented as a `views/partials/aura-bg.php` partial loaded on the home and project archive templates (per mockup: dark atmospheric field on hero surfaces, plain dark surface elsewhere). - Layer 1: linear 138deg `#05070c → #0f172a → #172554 → #1e3a8a`. `mix-blend-mode: normal`. `transform: translateZ(0)`. - Layer 2: radial ellipse `45% 50% at 72% 40%`, `rgba(96,165,250,0.20)` → transparent 68%. `mix-blend-mode: screen`. `filter: blur(105px)` mobile, `151px` desktop. - Layer 3: inline SVG `feTurbulence baseFrequency="0.7" numOctaves="4" stitchTiles="stitch"`, `mix-blend-mode: overlay`, `opacity: 0.85`. - All three: `position: absolute; inset: 0;`, `pointer-events: none;`, `aria-hidden="true"`. - Parent container: `position: relative; overflow: hidden; min-height: 100vh;` with NO `background-color` (per the blend-mode architecture warning in `notes/Background Gradient.md`). - Content wrapper: `position: relative; z-index: 1`. ### 4.3 Tokens Resolve the unresolved tokens from `notes/DESIGN.md` §12: - Define `--font-headings: var(--font-sans)` in `styles/base/typography.css`. - Update `theme.json` `styles` block to reference the existing palette slugs (`theme-bg`, `theme-text`) — currently references `background` / `text` which don't exist. - Add Carbon-Blue editor palette entries in `theme.json`: `theme-surface` (#121318), `theme-on-surface` (#e3e1e9), `theme-outline` (#8f909d), `theme-outline-variant` (#444651), `theme-primary` (#b6c4ff), `theme-on-primary` (#05297a). - Add 100–900 mix tokens for `theme-primary` if not already present. - Remove legacy hex values (`#3857BC`, `#ddd`) from pagination CSS; replace with `var(--color-outline-variant)` / `var(--color-primary)`. Keep the implemented light tokens in `styles/base/colors.css` for any block-editor surface that still wants light, but default new portfolio-facing CSS to the dark surface. ## 5. Template → mockup mapping ### 5.1 `front-page.php` — matches `notes/home-screen.png` - Header: `WP_DEV_2026` logo, top nav (Plugins, Themes, Open Source, Documentation, Blog), `Download CV` button (right-aligned). - Hero on Carbon Blue: heading + intro + two CTAs (`Download CV`, `View Repositories`) pulled from ACF Homepage Hero fields. No hardcoded sample text. - "Recent Projects" section: queries `projects` CPT, max 3, rendered as 3-column grid on `lg`, single column on mobile. - Each card: type badge (Plugin / Theme / Pattern), title, excerpt, `Download` + `View Repo` links when both URLs exist (provider-agnostic labels). - Empty state when zero published projects: "Nothing here yet..." + "No published projects found." centered in the grid area. - Footer: copyright + GitHub / Privacy / License / Site Status links. ### 5.2 `archive-projects.php` (new) — matches `notes/archive-screen.png` - Hero: `Project Archive` heading + intro from ACF option (or page-derived intro). - Grid: project cards 3-up on `lg`, 2-up on `md`, 1-up on mobile. - Each card: type label (PLUGIN / THEME FRAMEWORK / INTEGRATION, uppercase tracking-wide), title, excerpt, language pill + star count, `View Repo →` link. - Pagination via `the_posts_pagination` styled against dark surface. ### 5.3 `single-projects.php` (new) — matches `notes/single-screen.png` - Hero: provider icon + type pill, project title + version suffix (from `projects_portfolio_get_latest_version()`), excerpt. - Primary `Download vX.Y.Z` button + secondary `View Repo` link. - Two-column body below: featured image / project content on the left; sidebar (Maintainer, Repository Details table, four stat cards) on the right. - Owner avatar: 40px square using `background-image` with explicit `width: 40px; height: 40px; background-size: 40px 40px;` (per `notes/Projects Plugin Design.md` §9 — host CSS quirk workaround). - Below columns: `Architecture & Implementation` (post body content), `Key Features` (list), `Installation` (code block) — all from WordPress content. ### 5.4 `taxonomy-project-type.php` (new) - Same template as `archive-projects.php` with taxonomy-aware title: `

{project-type label}

` plus a back link to the full archive. ### 5.5 Other templates - `index.php` (post archive), `search.php`, `single.php` (post), `page.php`, `404.php`: keep structure, recolor surfaces to dark, remove `picsum.photos` fallback URLs, ensure empty-state copy matches existing `Nothing here yet...` / `No published posts found.` / `Page Not Found` patterns. - Keep `Resources` CPT and `resource_type` taxonomy styling independent from `projects`. ## 6. Components ### 6.1 Buttons Keep the existing token-driven button block (Primary / Secondary / White / Black × Default / Outline × Small / Medium / Large × Auto / Small / Wide / Full Width). The Primary button in the mockup maps to the existing default-styled Primary button (3px border, semibold 16px, 200ms transitions, focus outline offset, 99% active press). ### 6.2 Project card New `views/components/project-card.php`: - Border `1px solid var(--color-outline-variant)`. - Background `var(--color-surface-container)` (#1e1f25). - Radius `lg` (1rem). - Padding `1.5rem`. - Type badge top-left (small, uppercase, tracking-wide). - Provider icon top-right (decorative if visible text label is present). - Title (h3 if in archive, h2 on home), excerpt (line-clamp), action row at bottom with `Download` and `View Repo`. - Hover: subtle border tint to `var(--color-primary)`. - Focus-visible: 2px primary outline, 3px offset. ### 6.3 Stat card New `views/components/project-stat-card.php`: - Square surface with `var(--color-surface-container)`, radius `lg`, padding `1rem`. - Icon (decorative), large value, uppercase label below. ### 6.4 Navigation Keep `views/components/nav-main.php`, `nav-aux.php`, `nav-main__toggle.php`. Recolor links to `var(--color-on-surface)`. Preserve skip link, dropdown behavior, focus visibility, mobile variants. ### 6.5 Header layout Switch from `grid-cols-[83px_auto]` to a three-region responsive layout (logo | main nav | aux action button). The `Download CV` button is in the right region on `lg`, collapses into the mobile menu below. ## 7. Accessibility (WCAG 2.1 AA) - Skip-to-main link: preserved (`#f6ff00` on black, yellow focus outline). - Body text contrast: `#e3e1e9` on `#100e0b` ≈ 14:1 — passes AA. - Primary buttons: `#b6c4ff` background with `#05297a` text ≈ 9:1 — passes AA. - All decorative layers `aria-hidden="true"` + `pointer-events: none`. - Heading order: each template has exactly one `

`. Mockup headings map to page `

`; lower-level headings step down in order. - Provider icons supplement text (GitHub, Gitea, Download, View Repo) — never replace them. - Keyboard: tab order header → hero → projects → footer; focus-visible on every interactive element. - `prefers-reduced-motion`: media-query guard around hover scale on cards / media. ## 8. Security - All forms use `wp_nonce_field`; state-changing requests use `wp_verify_nonce`. - Dynamic output escaped with the right `esc_*` function for its context (`esc_html`, `esc_attr`, `esc_url`, `wp_kses_post`). - Post meta access via `get_post_meta( $id, $key, true )` with explicit defaults. - No `$_GET` / `$_POST` / `$_REQUEST` without `sanitize_*` + `wp_unslash`. - External URLs (Download / View Repo) use `esc_url` and add `rel="noopener noreferrer"` when `target="_blank"`. ## 9. Testing plan ### 9.1 Unit / static (composer) - `composer run lint` (PHPCS with WordPress + WPCS ruleset) must pass clean across all theme PHP. - Fix any violations inline. ### 9.2 Static security audit - PHPCS `WordPress.Security` ruleset (`NonceVerification`, `ValidatedSanitizedInput`, `EscapeOutput`). - Grep audit for `$_GET` / `$_POST` / `$_REQUEST` without `sanitize_*` / `wp_unslash` / `esc_*`. - Manual review of every new template for nonce, sanitize, escape coverage. - Severity-ranked written report (Critical / High / Medium / Low / Info) with `file:line` citations and remediation per finding. ### 9.3 Browser / functional (Playwright) - `playwright.config.js`: chromium project only, base URL `http://portfolio.test` (matches `.env`). - New `tests/home.spec.js`: home renders Carbon Blue hero, project grid or empty state, no axe violations. - New `tests/archive.spec.js`: project archive grid renders, no axe violations. - New `tests/single.spec.js`: project detail hero + sidebar + Download button visible, no axe violations. - Keep existing `tests/site-a11y.spec.js` (homepage, blog index, 404). - axe tags: `wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22a, wcag22aa`. - Full-page screenshots saved to `test-results/` per test. ## 10. File-level changes ### Modified - `style.css` (already correct — verify) - `functions.php` (namespace swap, project helper include) - `header.php`, `footer.php` (namespace swap, dark surface) - `index.php`, `single.php`, `page.php`, `search.php`, `404.php`, `front-page.php` (namespace swap, dark surface, remove `picsum.photos`) - `lib/*.php` (11 files: `activation.php`, `class-acf.php`, `class-breadcrumbs.php`, `class-enqueue.php`, `class-menuitems.php`, `class-resources.php`, `extras.php`, `helpers.php`, `hooks.php`, `search-features.php`, `show-template.php` — namespace swap + dark surface tweaks) - `views/blocks/*/block.json` and any block PHP that uses a namespace (light touch — only what axe or the new templates require) - `views/forms/search.php` (light touch — escape review only, no behavior change) - `theme.json` (fix preset references, add dark palette) - `styles/base/colors.css` (add Carbon Blue tokens) - `styles/base/typography.css` (define `--font-headings`) - `styles/base/global.css` (dark body, remove light main rule) - `views/components/nav-*.php`, `views/partials/*.php` (namespace swap, dark overrides) ### New - `archive-projects.php` - `single-projects.php` - `taxonomy-project-type.php` - `views/partials/aura-bg.php` (Carbon Blue layers + grain) - `views/components/project-card.php` - `views/components/project-stat-card.php` - `lib/class-projects.php` (thin wrapper around plugin helpers: `get_provider_label()`, `get_release_url()`, `get_repo_browse_url()`, `get_repo_data()`, `get_owner_data()`, `get_download_url()` with provider-agnostic fallbacks) - `tests/home.spec.js` - `tests/archive.spec.js` - `tests/single.spec.js` - `docs/superpowers/specs/2026-08-16-portfolio-2026-design.md` (this file) - `docs/superpowers/specs/2026-08-16-portfolio-2026-testing-report.md` (final report) ### Removed - `screenshot.png` (Basic WP) — replaced at the end - `picsum.photos` fallback URLs in `index.php`, `search.php` - Legacy hex values in pagination CSS ## 11. Out of scope - Migrating existing content (site has minimal published content — no destructive cleanup). - Changing `projects-portfolio` plugin behavior (we only consume its helpers). - Removing the `Resources` CPT (per notes: keep both, don't conflate). - Block-editor UI polish (follow-up). - Firefox / WebKit / mobile browser testing (out of scope per user choice). - OWASP ZAP scan (out of scope per user choice). ## 12. Definition of done - `composer run lint` exits 0. - Playwright suite passes locally (Chromium, axe-core zero violations across all four specs). - Static security audit produced with no Critical or High findings (Medium+ requires remediation before sign-off). - All three mockups (home, archive, single project) reachable on `http://portfolio.test` and visually consistent with their reference screenshot. - `screenshot.png` replaced with a Carbon-Blue capture. - Final testing report committed to `docs/superpowers/specs/2026-08-16-portfolio-2026-testing-report.md`.