@gurupanguji

Leica Black Theme Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Add a Leica black-paint theme across the site, default it from system preference, and let visitors switch between chrome and black from a quiet header control or the homepage finish module.

Architecture: Keep one theme engine for the whole static site. Put semantic color and surface tokens in the shared stylesheet, store theme state on the root element with data-theme, use a small shared JavaScript file for persistence and control syncing, and patch page-level inline styles so both finishes inherit the same material system.

Tech Stack: Jekyll, static HTML, shared CSS, small vanilla JavaScript, local Jekyll preview, GitHub Actions HTML validation


File Map

Create

Modify

Verify Only

Implementation Tasks

Task 1: Add the shared theme runtime

Files:

Write down the exact shared API before coding:

window.GuruTheme = {
  init(),
  applyTheme(theme),
  getPreferredTheme(),
  setStoredTheme(theme),
  syncControls(theme)
};

Expected:

Insert a small inline script in <head> before the stylesheet:

<script>
  (function () {
    try {
      var stored = localStorage.getItem("site-theme");
      var prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
      var theme = stored || (prefersDark ? "black" : "chrome");
      document.documentElement.setAttribute("data-theme", theme);
    } catch (error) {
      document.documentElement.setAttribute("data-theme", "chrome");
    }
  })();
</script>

Expected:

Apply the same snippet to:

Expected:

Start with the smallest working implementation:

(function () {
  var STORAGE_KEY = "site-theme";
  var THEMES = ["chrome", "black"];

  function getStoredTheme() {
    try {
      return localStorage.getItem(STORAGE_KEY);
    } catch (error) {
      return null;
    }
  }

  function getPreferredTheme() {
    var stored = getStoredTheme();
    if (THEMES.indexOf(stored) !== -1) return stored;
    return window.matchMedia("(prefers-color-scheme: dark)").matches ? "black" : "chrome";
  }

  function applyTheme(theme) {
    document.documentElement.setAttribute("data-theme", theme);
  }

  window.GuruTheme = { getPreferredTheme: getPreferredTheme, applyTheme: applyTheme };
})();

Expected:

Add:

<script src="/assets/js/theme.js" defer></script>

Use relative path form where needed:

Expected:

Implement:

function setStoredTheme(theme) {
  try {
    localStorage.setItem(STORAGE_KEY, theme);
  } catch (error) {}
}

function syncControls(theme) {
  document.querySelectorAll("[data-theme-control]").forEach(function (control) {
    var value = control.getAttribute("data-theme-value");
    var active = value === theme;
    control.setAttribute("aria-pressed", active ? "true" : "false");
    control.setAttribute("data-active", active ? "true" : "false");
  });
}

Expected:

Implement init() to:

Expected:

Run:

bundle exec jekyll serve

Check:

git add assets/js/theme.js index.html about/index.html reviews/index.html _layouts/post.html reviews/camera/fujifilm/x100vi/index.html reviews/camera/leica/m11-p/index.html
git commit -m "Add shared site theme runtime"

Task 2: Build the semantic theme token system

Files:

Add theme-neutral tokens near :root:

:root {
  --accent-red: #e30613;
  --accent-brass: #b08a52;
  --page-bg: #f5f5f7;
  --surface-bg: rgba(255, 255, 255, 0.72);
  --surface-elevated: #ffffff;
  --text-primary: #1c1c1e;
  --text-muted: #6a6b70;
  --border-subtle: rgba(0, 0, 0, 0.08);
  --header-glass: rgba(245, 245, 247, 0.9);
  --grid-dot: rgba(108, 108, 112, 0.42);
}

Expected:

Define dark-theme values:

html[data-theme="black"] {
  --page-bg: #111214;
  --surface-bg: rgba(17, 18, 20, 0.82);
  --surface-elevated: #17181b;
  --text-primary: #f1ede4;
  --text-muted: #b4aa99;
  --border-subtle: rgba(187, 149, 92, 0.18);
  --header-glass: rgba(15, 16, 18, 0.88);
  --grid-dot: rgba(196, 177, 147, 0.22);
}

Expected:

Update rules for:

Expected:

Create shared classes such as:

.theme-toggle
.theme-toggle-button
.theme-toggle-button[data-active="true"]
.theme-finish-module
.theme-finish-copy

Expected:

Define hover, focus, and active states for:

Expected:

Run:

bundle exec jekyll serve

Check:

git add assets/css/style.css
git commit -m "Add Leica theme tokens and shared controls"

Task 3: Add the homepage finish module and homepage-specific token cleanup

Files:

Update styles such as:

Example:

.home-intro { color: var(--text-muted); }
.feed-item { color: var(--text-primary); border-bottom: 1px solid var(--border-subtle); }

Expected:

Insert a compact module with:

Example:

<section class="theme-finish-module" aria-label="Choose finish">
  <p class="theme-finish-copy">Silver-chrome or black paint, same restraint.</p>
  <div class="theme-toggle" role="group" aria-label="Theme finish">
    <button type="button" class="theme-toggle-button" data-theme-control data-theme-value="chrome">Chrome</button>
    <button type="button" class="theme-toggle-button" data-theme-control data-theme-value="black">Black</button>
  </div>
</section>

Expected:

Tune margin and gap values around:

Expected:

Run:

bundle exec jekyll serve

Check:

git add index.html
git commit -m "Add homepage finish selector"

Task 4: Patch interior templates and duplicated headers

Files:

Use the same button contract as the homepage, but visually quieter:

<div class="theme-toggle theme-toggle-header" role="group" aria-label="Theme finish">
  <button type="button" class="theme-toggle-button" data-theme-control data-theme-value="chrome">Chrome</button>
  <button type="button" class="theme-toggle-button" data-theme-control data-theme-value="black">Black</button>
</div>

Expected:

Expected:

Expected:

Patch values like:

Map them to semantic variables such as:

Expected:

Update _layouts/post.html inline CSS to use semantic values for:

Expected:

Run:

bundle exec jekyll serve

Check:

git add about/index.html reviews/index.html _layouts/post.html reviews/camera/fujifilm/x100vi/index.html reviews/camera/leica/m11-p/index.html
git commit -m "Apply theme controls across site pages"

Task 5: Verify behavior, preview the site, and prepare the branch

Files:

Run:

bundle exec jekyll serve

Expected:

Manual checks:

Expected:

Manual checks:

Expected:

Run:

python3 scripts/check_markdown_in_html.py

Expected:

Run:

git status --short
git diff --stat

Expected:

git add assets/css/style.css assets/js/theme.js index.html about/index.html reviews/index.html _layouts/post.html reviews/camera/fujifilm/x100vi/index.html reviews/camera/leica/m11-p/index.html
git commit -m "Refine Leica black theme behavior"
git push -u origin feature/leica-black-theme
gh pr create --fill

Expected:

Plan Review

Local review outcome

Status: Approved

Notes: