Files
intotheeast-com/docs/superpowers/plans/2026-06-19-dark-mode.md
T

12 KiB

Dark Mode & Visual Polish 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.

Status: Complete (2026-06-20)

Goal: Replace the warm-paper light theme with a warm-dark "notebook at night" aesthetic — dark-only, no toggle, paper grain texture, dark terrain map tiles, typography polish.

Architecture: Pure CSS token swap in tokens.css (all components update automatically), grain overlay via body::after SVG data URI in style.css, map tile URL swap in two Twig templates. No new dependencies, no JS changes, no structural changes.

Tech Stack: CSS custom properties, inline SVG noise filter, Stadia Maps Alidade Smooth Dark tile CDN, Leaflet.js (already present)

Global Constraints

  • All changes in user/ — commit with git -C user, not main-repo git
  • Dark-only — no prefers-color-scheme media query, no light-mode fallback, no toggle
  • Existing token names in tokens.css must not change — only values swap
  • No new npm/JS dependencies
  • make test-ui must pass after every task (pre-existing P2 FilePond failure is acceptable)
  • Map tile URL: https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png (CartoDB — no API key required)
  • CartoDB attribution (exact): © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>
  • Note: Stadia Maps requires an API key even for local dev — CartoDB dark_all is the keyless alternative

Task 1: Dark color tokens

Files:

  • Modify: user/themes/intotheeast/css/tokens.css

Interfaces:

  • Produces: CSS custom properties consumed by every component in style.css and Twig templates

  • Step 1: Read the current tokens file

cat user/themes/intotheeast/css/tokens.css

Confirm these token names exist before editing: --color-paper, --color-canvas, --color-ink, --color-ink-2, --color-ink-muted, --color-border, --color-border-soft, --color-accent, --color-accent-hover, --color-accent-light, --color-accent-on.

  • Step 2: Replace the color block in tokens.css

Replace the entire :root color block (from --color-paper through --color-accent-on) with:

    /* ── Dark palette (warm notebook) ──────────────────────────────────────── */
    --color-paper:          #1A1814;   /* page background — warm near-black */
    --color-canvas:         #22201B;   /* card surfaces, form backgrounds */
    --color-ink:            #EDE8DF;   /* primary text — warm cream */
    --color-ink-2:          #B8B0A4;   /* body text — muted warm */
    --color-ink-muted:      #7A7268;   /* labels, timestamps, captions */
    --color-border:         #2E2B25;   /* standard dividers */
    --color-border-soft:    #252219;   /* subtle dividers */
    --color-accent:         #2A8C73;   /* teal — lightened for dark contrast */
    --color-accent-hover:   #236655;   /* hover/pressed teal */
    --color-accent-light:   #1A2E29;   /* pale teal tint backgrounds */
    --color-accent-on:      #FFFFFF;   /* text on accent surfaces */
    --color-surface-raised: #2A2720;   /* elevated surfaces: tooltips, hover */
    --color-ink-inverse:    #17171A;   /* text on accent-coloured buttons */

Keep all non-color tokens (--text-*, --leading-*, --space-*, font variables, etc.) unchanged.

  • Step 3: Verify no syntax errors
docker exec intotheeast_grav bash -c "cd /var/www/html && php bin/grav clearcache" && curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026/dailies

Expected: 200

  • Step 4: Visual smoke check
curl -s http://localhost:8081/trips/japan-korea-2026/dailies | grep -o 'color: var(--color-paper)' | head -3

Not a definitive check — just confirm the page renders. Open a browser and verify the background is dark and text is cream.

  • Step 5: Run test suite
make test-ui

Expected: 24/25 pass (P2 FilePond is pre-existing failure, all others pass).

  • Step 6: Commit
git -C user add themes/intotheeast/css/tokens.css
git -C user commit -m "feat: switch to warm-dark color tokens"

Task 2: Paper grain texture + hardcoded color fixes + typography

Files:

  • Modify: user/themes/intotheeast/css/style.css

Interfaces:

  • Consumes: dark color tokens from Task 1

  • Step 1: Find all hardcoded color literals in style.css

grep -n '#[0-9a-fA-F]\{3,6\}\|background: white\|background:#fff\|color: #\|background-color: #' user/themes/intotheeast/css/style.css

Make note of every hit — each one is a candidate to replace with a token. Exceptions: the CSS SVG data URI you are about to add (the noise filter hex values are part of the graphic, not UI colors).

  • Step 2: Add paper grain texture to body

Find the body rule in style.css. It will look something like:

body {
    background-color: var(--color-paper);
    color: var(--color-ink);
    ...
}

Add a body::after rule immediately after the body rule:

body::after {
    content: '';
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 9998;
    opacity: 0.035;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23noise)' opacity='1'/%3E%3C/svg%3E");
    background-repeat: repeat;
    background-size: 200px 200px;
}
  • Step 3: Fix hardcoded login form colors

Find this rule (around line 497):

.login-form .button.secondary { background: #f0f0f0; color: #333; text-decoration: none; line-height: 44px; padding: 0 1rem; }

Replace with:

.login-form .button.secondary { background: var(--color-canvas); color: var(--color-ink); text-decoration: none; line-height: 44px; padding: 0 1rem; }
  • Step 4: Fix any other hardcoded colors found in Step 1

For each hardcoded literal found in Step 1 (excluding the data URI you added):

  • #fff / whitevar(--color-canvas) (if a surface) or var(--color-paper) (if a page background)
  • #333 / dark grays → var(--color-ink) or var(--color-ink-2)
  • #eee / light grays → var(--color-border) or var(--color-border-soft)
  • #f0f0f0 / near-white → var(--color-canvas)

Use judgment: if a hex is inside a gradient or SVG path data, leave it alone.

  • Step 5: Typography — increase entry body paragraph spacing

Find:

.entry-body p { margin-bottom: 1.1em; font-size: var(--text-md); line-height: var(--leading-normal); color: var(--color-ink-2); }

Change margin-bottom: 1.1em to margin-bottom: 1.4em.

  • Step 6: Typography — tighten h1/h2 tracking

Find the h1 and h2 rules. Any rule that applies letter-spacing: -0.01em to an h1 or h2 — change it to -0.02em. Do not touch h3/h4/h5/h6.

  • Step 7: Stats page — tabular numbers

Find any CSS rule targeting stats numbers (look for .stat-value, .stats-number, or similar). Add font-variant-numeric: tabular-nums to it. If no such specific rule exists, search the template:

grep -n 'stat\|number\|count' user/themes/intotheeast/templates/stats.html.twig | head -20

Then add a targeted rule in style.css for whatever class wraps the numeric values.

  • Step 8: Verify no syntax errors and visual check
docker exec intotheeast_grav bash -c "cd /var/www/html && php bin/grav clearcache" && curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026/dailies

Expected: 200. Open browser — grain should be subtly visible on the dark background.

  • Step 9: Run test suite
make test-ui

Expected: 24/25 (P2 pre-existing).

  • Step 10: Commit
git -C user add themes/intotheeast/css/style.css
git -C user commit -m "feat: add paper grain texture, fix hardcoded colors, improve typography"

Task 3: Dark terrain map tiles

Files:

  • Modify: user/themes/intotheeast/templates/map.html.twig
  • Modify: user/themes/intotheeast/templates/dailies.html.twig

Interfaces:

  • Consumes: Leaflet.js already loaded in both templates

  • Produces: Stadia Alidade Smooth Dark tiles replacing OpenStreetMap tiles in both map views

  • Step 1: Read current tile setup in both templates

grep -n "tileLayer\|openstreetmap\|attribution\|stadia" user/themes/intotheeast/templates/map.html.twig user/themes/intotheeast/templates/dailies.html.twig

Confirm the current tile URL pattern ({s}.tile.openstreetmap.org) in both files.

  • Step 2: Replace tile layer in map.html.twig

Find:

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

Replace with:

// TODO: add Stadia API key before launch — free dev use requires no key, production does
L.tileLayer('https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png', {
    maxZoom: 20,
    attribution: '© <a href="https://stadiamaps.com/">Stadia Maps</a> © <a href="https://openmaptiles.org/">OpenMapTiles</a> © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
  • Step 3: Replace tile layer in dailies.html.twig (mini-map)

Apply the identical tile swap to the mini-map L.tileLayer call in dailies.html.twig. Find the OpenStreetMap tile URL and replace it with the Stadia dark URL (same as Step 2, same attribution, same TODO comment).

  • Step 4: Verify tiles load
curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026/map

Expected: 200.

Check the tile URL is in the HTML:

curl -s http://localhost:8081/trips/japan-korea-2026/map | grep -o 'stadiamaps'

Expected: stadiamaps (appears in the tile URL).

Open the map in a browser and confirm:

  • Dark terrain tiles render (not the default light OSM tiles)

  • GPX polyline is visible in teal on the dark background

  • Entry pins render correctly on top

  • Attribution footer is present

  • Step 5: Check mini-map on dailies page

curl -s http://localhost:8081/trips/japan-korea-2026/dailies | grep -o 'stadiamaps'

Expected: stadiamaps.

  • Step 6: Run test suite
make test-ui

Expected: 24/25 (P2 pre-existing).

  • Step 7: Commit
git -C user add themes/intotheeast/templates/map.html.twig themes/intotheeast/templates/dailies.html.twig
git -C user commit -m "feat: switch to Stadia Alidade Smooth Dark map tiles"

Final verification

After all 3 tasks:

  1. make test-config && make test-post && make test-ui — all pass
  2. Visual check list (browser, not curl):
    • /trips/japan-korea-2026/dailies — dark warm background, cream text, grain visible, teal accents
    • /trips/japan-korea-2026/map — dark terrain tiles, teal GPX polyline, entry pins
    • /trips/japan-korea-2026/dailies/<any-entry> — dark canvas card, no white boxes
    • /post — form fields readable, no black-on-black inputs
    • /trips/japan-korea-2026/stats — numbers align (tabular-nums)
  3. Final hardcoded-literal check:
    grep -n '#[0-9a-fA-F]\{3,6\}' user/themes/intotheeast/css/style.css | grep -v 'data:image'
    
    All remaining hits should be either intentional (e.g. SVG path data) or documented.