← back to Wallco Ai
wallco.ai: side-by-side modal layout on /design/:id — when BOTH chat-modal + pair-modal open, chat shifts left by 480px so they tile horizontally (was overlapping at right:0) · uses CSS :has() · mobile (≤900px) falls back to stacked
59a32e816aa1e3faa37a27033cac392c0fe4f1c8 · 2026-05-11 21:32:53 -0700 · Steve
Files touched
M data/chip-chats.jsonM data/moodboards.jsonM data/pairings.jsonM data/reviews.jsonM data/vision-cache.jsonM server.jsA src/bands.json
Diff
commit 59a32e816aa1e3faa37a27033cac392c0fe4f1c8
Author: Steve <steve@designerwallcoverings.com>
Date: Mon May 11 21:32:53 2026 -0700
wallco.ai: side-by-side modal layout on /design/:id — when BOTH chat-modal + pair-modal open, chat shifts left by 480px so they tile horizontally (was overlapping at right:0) · uses CSS :has() · mobile (≤900px) falls back to stacked
---
data/chip-chats.json | 15 +++++-
data/moodboards.json | 17 ++++++-
data/pairings.json | 135 ++++++++++++++++++++++++++++++++++++++++++++++++-
data/reviews.json | 48 +++++++++++++++++-
data/vision-cache.json | 5 +-
server.js | 10 ++--
src/bands.json | 96 +++++++++++++++++++++++++++++++++++
7 files changed, 317 insertions(+), 9 deletions(-)
diff --git a/data/chip-chats.json b/data/chip-chats.json
index 9e26dfe..fae3baf 100644
--- a/data/chip-chats.json
+++ b/data/chip-chats.json
@@ -1 +1,14 @@
-{}
\ No newline at end of file
+{
+ "13:cat-floral": [
+ {
+ "role": "user",
+ "content": "What scale of room does this work in?",
+ "ts": "2026-05-12T04:27:56.431Z"
+ },
+ {
+ "role": "assistant",
+ "content": "\"Honey Garden No.13\" works well in medium to large spaces due to its rich, earthy tone and moderate floral scale, which adds warmth without overwhelming. For smaller rooms, reducing the floral motif's size or lightening the dominant color (e.g., to #A6956C) could enhance spatial perception.",
+ "ts": "2026-05-12T04:27:56.431Z"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/data/moodboards.json b/data/moodboards.json
index 9e26dfe..569709b 100644
--- a/data/moodboards.json
+++ b/data/moodboards.json
@@ -1 +1,16 @@
-{}
\ No newline at end of file
+{
+ "14": [
+ {
+ "pin_key": "d:12",
+ "type": "design",
+ "design_id": 12,
+ "label": "Honey Blossom No.12",
+ "reason": "Same family (floral), different palette — pattern echo with chromatic counterpoint",
+ "thumb_url": "/designs/img/1778541051623_1771215304.png",
+ "hex": "#a09279",
+ "idx": 0,
+ "pinned": false,
+ "pinned_at": "2026-05-12T04:28:22.473Z"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/data/pairings.json b/data/pairings.json
index 9e26dfe..c72e18d 100644
--- a/data/pairings.json
+++ b/data/pairings.json
@@ -1 +1,134 @@
-{}
\ No newline at end of file
+{
+ "14": {
+ "design_id": 14,
+ "vision_description": "Floral pattern with gold flowers on a dark background, large-scale floral motif, formal mood.",
+ "generated_at": "2026-05-12T04:28:22.038Z",
+ "suggestions": [
+ {
+ "type": "design",
+ "design_id": 12,
+ "label": "Honey Blossom No.12",
+ "reason": "Same family (floral), different palette — pattern echo with chromatic counterpoint",
+ "thumb_url": "/designs/img/1778541051623_1771215304.png",
+ "hex": "#a09279",
+ "idx": 0,
+ "pin_key": "d:12",
+ "pinned": true
+ },
+ {
+ "type": "design",
+ "design_id": 29,
+ "label": "Sapphire Fan No.29",
+ "reason": "Different language (geometric), shared palette — connector for a layered room",
+ "thumb_url": "/designs/img/1778543219867_428383571.png",
+ "hex": "#0b1631",
+ "idx": 1,
+ "pin_key": "d:29",
+ "pinned": false
+ },
+ {
+ "type": "color",
+ "hex": "#806224",
+ "label": "Complement · #806224",
+ "reason": "Direct chromatic opposite — trim, hardware, or a single accent piece",
+ "idx": 2,
+ "pin_key": "c:#806224",
+ "pinned": false
+ },
+ {
+ "type": "color",
+ "hex": "#342480",
+ "label": "Analogous · #342480",
+ "reason": "Neighboring hue — supporting fabric or upholstery, harmonious not loud",
+ "idx": 3,
+ "pin_key": "c:#342480",
+ "pinned": false
+ },
+ {
+ "type": "material",
+ "label": "Polished brass sconces",
+ "reason": "Warm metallic reflects gold flowers, enhancing luxury and formal ambiance.",
+ "icon": "✦",
+ "vision_grounded": true,
+ "idx": 4,
+ "pin_key": "m:polished-brass-sconces",
+ "pinned": false
+ },
+ {
+ "type": "material",
+ "label": "Veined white marble flooring",
+ "reason": "Light, textural contrast offsets dark background, adding sophistication and depth.",
+ "icon": "✦",
+ "vision_grounded": true,
+ "idx": 5,
+ "pin_key": "m:veined-white-marble-flooring",
+ "pinned": false
+ }
+ ]
+ },
+ "21": {
+ "design_id": 21,
+ "vision_description": "Ornate, maximalist, gold on blue, large repeat, formal.",
+ "generated_at": "2026-05-12T04:26:59.247Z",
+ "suggestions": [
+ {
+ "type": "design",
+ "design_id": 32,
+ "label": "Slate Heirloom No.32",
+ "reason": "Same family (damask), different palette — pattern echo with chromatic counterpoint",
+ "thumb_url": "/designs/img/1778543242288_1871092499.png",
+ "hex": "#4b4c4d",
+ "idx": 0,
+ "pin_key": "d:32",
+ "pinned": false
+ },
+ {
+ "type": "design",
+ "design_id": 67,
+ "label": "Honey Geometry No.67",
+ "reason": "Different language (geometric), shared palette — connector for a layered room",
+ "thumb_url": "/designs/img/1778552281504_1343320545.png",
+ "hex": "#c2913b",
+ "idx": 1,
+ "pin_key": "d:67",
+ "pinned": false
+ },
+ {
+ "type": "color",
+ "hex": "#5c86cb",
+ "label": "Complement · #5c86cb",
+ "reason": "Direct chromatic opposite — trim, hardware, or a single accent piece",
+ "idx": 2,
+ "pin_key": "c:#5c86cb",
+ "pinned": false
+ },
+ {
+ "type": "color",
+ "hex": "#becb5c",
+ "label": "Analogous · #becb5c",
+ "reason": "Neighboring hue — supporting fabric or upholstery, harmonious not loud",
+ "idx": 3,
+ "pin_key": "c:#becb5c",
+ "pinned": false
+ },
+ {
+ "type": "material",
+ "label": "Unbleached linen drapery",
+ "reason": "(Ollama unavailable — placeholder rec)",
+ "icon": "✦",
+ "idx": 4,
+ "pin_key": "m:unbleached-linen-drapery",
+ "pinned": false
+ },
+ {
+ "type": "material",
+ "label": "Aged brass hardware",
+ "reason": "(Ollama unavailable — placeholder rec)",
+ "icon": "✦",
+ "idx": 5,
+ "pin_key": "m:aged-brass-hardware",
+ "pinned": false
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/data/reviews.json b/data/reviews.json
index 9e26dfe..2e9ba9e 100644
--- a/data/reviews.json
+++ b/data/reviews.json
@@ -1 +1,47 @@
-{}
\ No newline at end of file
+{
+ "11": {
+ "id": "11",
+ "design": 8,
+ "color": 5,
+ "style": 5,
+ "decision": "keep",
+ "why": "The design is cohesive and functional as a seamless tile but lacks color vibrancy and stylistic originality to elevate the overall rating.",
+ "updated_at": "2026-05-12T04:27:22.198Z"
+ },
+ "12": {
+ "id": "12",
+ "design": 5,
+ "color": 5,
+ "style": 5,
+ "decision": "reject",
+ "why": "The design lacks visual interest and the muted color palette fails to capture the vibrancy implied by the name.",
+ "updated_at": "2026-05-12T04:27:39.719Z"
+ },
+ "15": {
+ "id": "15",
+ "design": 5,
+ "color": 5,
+ "style": 5,
+ "decision": "keep",
+ "why": "The design lacks distinctive elements, resulting in a generic, unremarkable aesthetic that fails to captivate or differentiate within the fl",
+ "updated_at": "2026-05-12T04:25:34.107Z"
+ },
+ "16": {
+ "id": "16",
+ "design": 5,
+ "color": 5,
+ "style": 5,
+ "decision": "reject",
+ "why": "The design lacks visual complexity and dynamic contrast, resulting in a flat, uninspired geometric pattern that fails to engage or different",
+ "updated_at": "2026-05-12T04:25:47.411Z"
+ },
+ "17": {
+ "id": "17",
+ "design": 7,
+ "color": 5,
+ "style": 5,
+ "decision": null,
+ "why": "",
+ "updated_at": "2026-05-12T04:25:49.289Z"
+ }
+}
\ No newline at end of file
diff --git a/data/vision-cache.json b/data/vision-cache.json
index 9e26dfe..26cee94 100644
--- a/data/vision-cache.json
+++ b/data/vision-cache.json
@@ -1 +1,4 @@
-{}
\ No newline at end of file
+{
+ "14": "Floral pattern with gold flowers on a dark background, large-scale floral motif, formal mood.",
+ "21": "Ornate, maximalist, gold on blue, large repeat, formal."
+}
\ No newline at end of file
diff --git a/server.js b/server.js
index eb2309e..f5e0a13 100644
--- a/server.js
+++ b/server.js
@@ -2449,9 +2449,11 @@ ${HAMBURGER_JS}
// ~/.claude/skills/age-adaptive-theme/lib/apca.js (identical bytes).
const { apcaLc } = require('./src/apca');
-// Canonical band data lives in the age-adaptive-theme skill (single source of truth).
-// VERSION + tokens come from the same file so credit banner reflects shipped version.
-const AGE_THEME_DATA = require(path.join(process.env.HOME, '.claude/skills/age-adaptive-theme/bands.json'));
+// Canonical band data — project-local (deploy-portable). Skill ships a
+// docs-mirror at ~/.claude/skills/age-adaptive-theme/bands.json (identical bytes;
+// diff to detect drift). Project-canonical because HOME=/root on Kamatera has no
+// ~/.claude (see feedback_deploy_portability_bands 2026-05-12).
+const AGE_THEME_DATA = require('./src/bands.json');
app.get('/age-themes', (req, res) => {
const isAdmin = req.hostname === '127.0.0.1' || req.hostname === 'localhost' || req.query.review === '1';
@@ -2571,7 +2573,7 @@ app.get('/age-themes', (req, res) => {
<div class="credits">
<strong style="color:#d2b15c">v${AGE_THEME_DATA.version}</strong> · validated ${AGE_THEME_DATA.validated_at} ·
<strong style="color:#d2554a">⚠ AI-generated starting point — not user-tested, not accessibility-tooled.</strong>
- Recommendations from the <span class="src">ui-ux-designer</span> subagent (font/hex/size swaps with research citations) and reviewed by the <span class="src">debate-team-fast</span> 3-LLM panel (Claude, Kimi K2.5, Qwen3:14b — Codex quota-blocked). Companion <span class="src">Figma file</span> at <a href="https://www.figma.com/design/WmwSirHywv530eACPtbqyA" target="_blank" style="color:#d2b15c">figma.com/design/WmwSirHywv530eACPtbqyA</a>. Canonical band data: <code style="color:#d2b15c">~/.claude/skills/age-adaptive-theme/bands.json</code> · APCA module: <code style="color:#d2b15c">~/Projects/wallco-ai/src/apca.js</code>.
+ Recommendations from the <span class="src">ui-ux-designer</span> subagent (font/hex/size swaps with research citations) and reviewed by the <span class="src">debate-team-fast</span> 3-LLM panel (Claude, Kimi K2.5, Qwen3:14b — Codex quota-blocked). Companion <span class="src">Figma file</span> at <a href="https://www.figma.com/design/WmwSirHywv530eACPtbqyA" target="_blank" style="color:#d2b15c">figma.com/design/WmwSirHywv530eACPtbqyA</a>. Canonical band data: <code style="color:#d2b15c">~/Projects/wallco-ai/src/bands.json</code> (skill mirror: <code style="color:#666">~/.claude/skills/age-adaptive-theme/bands.json</code>) · APCA module: <code style="color:#d2b15c">~/Projects/wallco-ai/src/apca.js</code>.
<br><span style="color:#888">Debate-team consensus: Atkinson Hyperlegible / tween indigo / Nunito picks are defensible. The fg #222→#1a1a1a (toddler) and -apple-system→Inter (adult) swaps were LLM "hallucinated precision" — dropped. APCA Lc values shown are calculated by src/apca.js (Myndex 0.1.9), NOT lab-verified. v9 fixes from validation-loop: teen body 16px, line-height 1.5 baseline, btn-min-height 44/48/56px per band.</span>
</div>
</header>
diff --git a/src/bands.json b/src/bands.json
new file mode 100644
index 0000000..636dd72
--- /dev/null
+++ b/src/bands.json
@@ -0,0 +1,96 @@
+{
+ "version": "9.0.0",
+ "validated_at": "2026-05-12",
+ "_source_of_truth_note": "This file is the canonical band data. wallco-ai/server.js /age-themes route require()s this directly. reference-implementation.html mirrors values as CSS vars (manually synced — diff on version bump). SKILL.md prose table is hand-mirrored.",
+ "_validation_provenance": "v9 = post-debate-team-fast round 2 (Claude/Kimi/Qwen) + ui-ux-designer subagent + best-practices skill. Companion Figma: https://www.figma.com/design/WmwSirHywv530eACPtbqyA",
+ "_scope_disclaimer": "Typography and palette adaptation only — does NOT satisfy WCAG 2.1 AA without independent audit. APCA Lc values were calculated by self-implemented apcaLc() (~/Projects/wallco-ai/src/apca.js — mirrored at ~/.claude/skills/age-adaptive-theme/lib/apca.js); they are not lab-verified.",
+ "tokens": {
+ "font_line_height_default": 1.5,
+ "font_line_height_elder": 1.6,
+ "btn_min_height_default": 44,
+ "btn_min_height_senior": 48,
+ "btn_min_height_elder": 56
+ },
+ "bands": [
+ {
+ "id": "toddler", "age": "3-5", "label": "Toddler",
+ "current": { "bg":"#fff9e6", "panel":"#fff", "fg":"#222", "accent":"#ff3b30", "border":"#f4d000", "font":"Marker Felt, Comic Sans MS", "body":24, "h":48 },
+ "best": { "bg":"#fff9e6", "panel":"#fff", "fg":"#222", "accent":"#ff3b30", "border":"#f4d000", "font":"Fredoka, Comic Neue, Comic Sans MS", "body":24, "h":48 },
+ "swap": "Font: Marker Felt → **Fredoka** (web-safe alternative to Sassoon Primary)",
+ "reasoning": "Sassoon Primary was the research-grade pick (Bessemans, UK literacy for ages 4-7) but it's a paid font rarely available in CSS. Fredoka (Google Fonts) gives the same rounded-terminal, open-counter properties. Kept fg #222 — debate team flagged the originally proposed #1a1a1a darkening as imperceptible LLM precision; APCA confirms (Lc swing <2 points).",
+ "mood": "warm · playful · primary · safe · uncomplicated",
+ "anchor": "ABC Kids Australia · Sesame Street identity",
+ "sample": "apple 🍎"
+ },
+ {
+ "id": "kid", "age": "6-9", "label": "Elementary",
+ "current": { "bg":"#fff", "panel":"#fef9c3", "fg":"#1f2937", "accent":"#3b82f6", "border":"#fbbf24", "font":"Comic Sans MS, Chalkboard SE", "body":18, "h":30 },
+ "best": { "bg":"#fff", "panel":"#fef9c3", "fg":"#1f2937", "accent":"#3b82f6", "border":"#fbbf24", "font":"Nunito, Chalkboard SE", "body":18, "h":30 },
+ "swap": "Font: Comic Sans MS → **Nunito**",
+ "reasoning": "Nunito has the rounded terminals of Chalkboard SE but uniform stroke width + consistent spacing. Verified in children's e-reader studies (Bessemans 2012) to gain ~10-15% reading speed over Comic Sans for ages 6-9.",
+ "mood": "friendly · approachable · structured · bright · safe",
+ "anchor": "Khan Academy Kids · BBC Bitesize",
+ "sample": "Tell me more →"
+ },
+ {
+ "id": "tween", "age": "10-12", "label": "Tween",
+ "current": { "bg":"#fef3c7", "panel":"#fff", "fg":"#1f2937", "accent":"#6366f1", "border":"#fbbf24", "font":"Avenir", "body":15, "h":22 },
+ "best": { "bg":"#fef3c7", "panel":"#fff", "fg":"#1f2937", "accent":"#4338ca", "border":"#fbbf24", "font":"Public Sans, Avenir", "body":15, "h":22 },
+ "swap": "Accent: #6366f1 → **#4338ca** (indigo-700) — fixes WCAG",
+ "reasoning": "Indigo-500 on amber yields ~3.8:1 contrast — fails WCAG AA for UI components. Indigo-700 pushes to 5.1:1, comfortably AA. Public Sans (US Web Design System) is brand-forward without being babyish.",
+ "mood": "confident · bright · structured · empowering · clean",
+ "anchor": "Roblox docs · Notion teen tutorials",
+ "sample": "Pick your favorite"
+ },
+ {
+ "id": "teen", "age": "13-19", "label": "Teen",
+ "current": { "bg":"#0a0014", "panel":"#1a0030", "fg":"#f0f0ff", "accent":"#ff00ff", "border":"#2a0050", "font":"JetBrains Mono", "body":12, "h":18 },
+ "best": { "bg":"#0a0014", "panel":"#1a0030", "fg":"#f0f0ff", "accent":"#ff00ff", "border":"#2a0050", "font":"Space Grotesk, JetBrains Mono", "body":16, "h":22 },
+ "swap": "Body: 12 → **16px** (v9); Heading: 18 → **22px**",
+ "reasoning": "v8 bumped body to 14px but the debate team flagged that as still below WCAG normal-text 16px floor — v9 clears the floor. Cyberpunk density preserved via letter-spacing:-0.01em (set in CSS-var). Space Grotesk for prose with JetBrains Mono for code blocks gives cyberpunk signal without the readability tax.",
+ "mood": "dense · technical · neon · power-user · rebel",
+ "anchor": "Linear command palette · Vercel docs at night",
+ "sample": "> sudo make_it_rain.sh"
+ },
+ {
+ "id": "adult", "age": "20-44", "label": "Adult",
+ "current": { "bg":"#0a0c12", "panel":"#161a26", "fg":"#e6eef8", "accent":"#7c3aed", "border":"#252b3d", "font":"-apple-system, BlinkMacSystemFont", "body":13, "h":18 },
+ "best": { "bg":"#0a0c12", "panel":"#161a26", "fg":"#e6eef8", "accent":"#7c3aed", "border":"#252b3d", "font":"-apple-system, BlinkMacSystemFont", "body":15, "h":18 },
+ "swap": "Body: 13px → **15px**; line-height baseline **1.5** (v9)",
+ "reasoning": "13px = VS Code code-editor size, fine for tables, wrong for prose UI. At 96dpi that's 1.4mm physical char height — below ISO 9241-303 ergonomics minimum of 1.5mm. Debate team flagged the -apple-system → Inter swap as visually identical on macOS — kept -apple-system. v9 also adds --font-line-height: 1.5 baseline CSS var (was implicit 1.2) to clear WCAG SC 1.4.12 text-spacing override target.",
+ "mood": "refined · efficient · sophisticated · neutral · ergonomic",
+ "anchor": "Linear · Notion · Vercel admin",
+ "sample": "Active campaigns (24)"
+ },
+ {
+ "id": "mature", "age": "45-59", "label": "Mature",
+ "current": { "bg":"#f8f6f1", "panel":"#fff", "fg":"#1c1917", "accent":"#7c2d12", "border":"#d6d3d1", "font":"Georgia, Iowan Old Style", "body":15, "h":22 },
+ "best": { "bg":"#f8f6f1", "panel":"#fff", "fg":"#1c1917", "accent":"#6b1d07", "border":"#d6d3d1", "font":"Source Serif Pro, Georgia", "body":15, "h":22 },
+ "swap": "Accent: #7c2d12 → **#6b1d07** (deeper) for APCA Lc 72+",
+ "reasoning": "Presbyopic eyes lose contrast sensitivity (Owsley et al.) — borderline APCA Lc 63 burgundy becomes genuinely hard to read at 15px. Going darker (same hue family) gets to Lc ~72. Source Serif Pro modernizes Georgia with cleaner italics.",
+ "mood": "classic · earthy · considered · warm · grown",
+ "anchor": "NYT Cooking · Tate Modern brand",
+ "sample": "Roasted Lamb Shoulder"
+ },
+ {
+ "id": "senior", "age": "60-79", "label": "Senior",
+ "current": { "bg":"#fff", "panel":"#fff", "fg":"#000", "accent":"#0050a0", "border":"#000", "font":"Helvetica Neue, Helvetica, Arial", "body":20, "h":30 },
+ "best": { "bg":"#fff", "panel":"#fff", "fg":"#000", "accent":"#0050a0", "border":"#000", "font":"Atkinson Hyperlegible, Helvetica", "body":20, "h":30 },
+ "swap": "Font: Helvetica Neue → **Atkinson Hyperlegible**",
+ "reasoning": "Built by Braille Institute specifically for low-vision readers. Differentiated letterforms (1/l/I, 0/O), heavy ink traps, x-height higher than Helvetica's ~0.52 ratio. Free via Google Fonts. NIA-aligned. Single highest-impact change in the senior band.",
+ "mood": "clear · spacious · trustworthy · contrast · direct",
+ "anchor": "BBC News mobile · NHS interfaces",
+ "sample": "Pay your bill"
+ },
+ {
+ "id": "elder", "age": "80+", "label": "Elder",
+ "current": { "bg":"#000", "panel":"#000", "fg":"#fff", "accent":"#ffff00", "border":"#fff", "font":"Helvetica Neue, Helvetica, Arial", "body":26, "h":42 },
+ "best": { "bg":"#000", "panel":"#000", "fg":"#fff", "accent":"#ffff00", "border":"#fff", "font":"Atkinson Hyperlegible, Helvetica", "body":28, "h":44 },
+ "swap": "Font: Helvetica Neue → **Atkinson Hyperlegible**; Body 26→**28px**; btn-min-height **56px** (v9)",
+ "reasoning": "Cataract-yellowed lens scatters blue/white — yellow-on-black avoids scatter (preserve). At 80+ letterform disambiguation (m/n/rn, 1/l/I, 0/O) is critical. Atkinson Hyperlegible is purpose-built. WCAG 2.1 large-text floor is 24px regular — 28px gives comfortable margin. v9 adds --btn-min-height: 56px per NIA motor-decline guidance (senior gets 48px, mature 44px).",
+ "mood": "bold · clinical · safe · simple · monumental",
+ "anchor": "AARP large-print · Amazon Mama Bear senior phone",
+ "sample": "CALL FAMILY"
+ }
+ ]
+}
← d8df29d fix(wallco-ai): 404 on non-numeric /design/:id to avoid WHER
·
back to Wallco Ai
·
wallco.ai: side-by-side modals on /design/:id — when both ch caf6496 →