migrate from Pico CSS to Tailwind CSS v4

Replace Pico CSS CDN with Tailwind v4 standalone CLI (no Node.js).
Brand theme with navy/electric/accent palette, component classes,
self-hosted Commit Mono font. Docker multi-stage CSS build.
Logo links to dashboard when logged in.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-02-16 14:45:32 +01:00
parent 2763bcd943
commit 72077fdd46
35 changed files with 1219 additions and 1031 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 KiB

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -116,7 +116,7 @@ def test_landing_light_background(live_server, page):
page.goto(live_server)
page.wait_for_load_state("networkidle")
# Pico sets background on <html>, body may be transparent
# Tailwind sets background on body via base layer
bg_color = page.evaluate("""
(() => {
const html_bg = getComputedStyle(document.documentElement).backgroundColor;
@@ -185,14 +185,14 @@ def test_landing_nav_no_overlap(live_server, page):
page.goto(live_server)
page.wait_for_load_state("networkidle")
# Get bounding boxes of all nav <li> items in the right <ul>
# Get bounding boxes of direct children in the nav's right-side flex container
boxes = page.evaluate("""
(() => {
const uls = document.querySelectorAll('nav ul');
if (uls.length < 2) return [];
const items = uls[1].querySelectorAll('li');
return Array.from(items).map(li => {
const r = li.getBoundingClientRect();
const navDiv = document.querySelector('nav > div');
if (!navDiv) return [];
const items = navDiv.children;
return Array.from(items).map(el => {
const r = el.getBoundingClientRect();
return {top: r.top, bottom: r.bottom, left: r.left, right: r.right};
});
})()
@@ -207,6 +207,32 @@ def test_landing_nav_no_overlap(live_server, page):
)
def test_landing_cards_have_colored_borders(live_server, page):
"""Verify landing page cards have a visible left border accent."""
page.goto(live_server)
page.wait_for_load_state("networkidle")
border_widths = page.evaluate("""
Array.from(document.querySelectorAll('.card')).map(
el => parseFloat(getComputedStyle(el).borderLeftWidth)
)
""")
assert len(border_widths) > 0, "No .card elements found"
cards_with_accent = [w for w in border_widths if w >= 4]
assert len(cards_with_accent) >= 10, (
f"Expected >=10 cards with 4px left border, got {len(cards_with_accent)}"
)
def test_landing_logo_links_to_landing(live_server, page):
"""Verify logo links to landing page when not logged in."""
page.goto(live_server)
page.wait_for_load_state("networkidle")
href = page.locator("nav a").first.get_attribute("href")
assert href == "/", f"Expected logo to link to /, got {href}"
def test_landing_teaser_light_theme(live_server, page):
"""Verify teaser calculator has white/light background."""
page.goto(live_server)
@@ -262,7 +288,7 @@ def test_mobile_nav_no_overflow(live_server, browser):
})()
""")
page.close()
# Pico's nav may wrap on mobile, which is fine — just verify no JS errors
# Nav may wrap on mobile, which is fine — just verify no JS errors
def test_landing_no_dark_remnants(live_server, page):