← back to Cncp Failures Mockups
v7 age-adaptive: 3→95 slider morphs UI through 8 design bands (toddler/kid/tween/teen/adult/mature/senior/elder) with band-specific palette/font/density/copy + index tile
12220e81071e92c966f0f6d8478221b5fb71d461 · 2026-05-11 14:41:39 -0700 · SteveStudio2
Files touched
M public/index.htmlA public/v7-age-adaptive.html
Diff
commit 12220e81071e92c966f0f6d8478221b5fb71d461
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date: Mon May 11 14:41:39 2026 -0700
v7 age-adaptive: 3→95 slider morphs UI through 8 design bands (toddler/kid/tween/teen/adult/mature/senior/elder) with band-specific palette/font/density/copy + index tile
---
public/index.html | 3 +-
public/v7-age-adaptive.html | 321 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 323 insertions(+), 1 deletion(-)
diff --git a/public/index.html b/public/index.html
index cfa07a3..677fd43 100644
--- a/public/index.html
+++ b/public/index.html
@@ -58,7 +58,8 @@ const variants = [
{ id:'v3-heatmap', title:'3. Heatmap · Dashboard', desc:'Density-first: 24-hour severity grid + glanceable stat cells. SRE dashboard energy.' },
{ id:'v4-kanban', title:'4. Kanban · Status Board', desc:'Four lanes (triage → investigating → resolved → dismissed). Atlassian-ish, action-oriented.' },
{ id:'v5-timeline', title:'5. Timeline · APM Trace', desc:'Each process is a lane; spans show event windows. Datadog-style, time-as-axis.' },
- { id:'v6-brutalist', title:'6. Brutalist · Data-Dense', desc:'Hard borders, full table, every field visible. No chrome — just the facts.' }
+ { id:'v6-brutalist', title:'6. Brutalist · Data-Dense', desc:'Hard borders, full table, every field visible. No chrome — just the facts.' },
+ { id:'v7-age-adaptive', title:'7. Age-Adaptive · 3 → 95', desc:'Slider morphs the whole UI through 8 design bands — toddler primary colors → elementary playful → tween → teen neon → adult → mature serif → senior hi-contrast → elder essentials only.' }
];
function renderGrid(mode) {
diff --git a/public/v7-age-adaptive.html b/public/v7-age-adaptive.html
new file mode 100644
index 0000000..d2de4be
--- /dev/null
+++ b/public/v7-age-adaptive.html
@@ -0,0 +1,321 @@
+<!doctype html><html><head>
+<meta charset="utf-8"><title>v7 — Age-adaptive (3 → 95)</title>
+<style>
+ /* The 8 age bands. Each rewrites the page's design system. */
+ :root {
+ --bg:#0a0c12; --panel:#161a26; --fg:#e6eef8; --muted:#7c8aa5; --border:#252b3d;
+ --accent:#7c3aed; --ok:#22c55e; --warn:#f59e0b; --bad:#ef4444;
+ --font:'-apple-system',BlinkMacSystemFont,'SF Pro Text',system-ui,sans-serif;
+ --font-mono:ui-monospace,Menlo,monospace;
+ --font-size-body:13px; --font-size-h:16px; --font-size-small:11px;
+ --gap:14px; --radius:8px; --padding:12px;
+ --vibe:'modern';
+ }
+ /* AGE 3-5 — Sesame Street primary colors, emoji-first, huge tap targets */
+ body[data-band="toddler"] {
+ --bg:#fff9e6; --panel:#fff; --fg:#222; --muted:#666; --border:#f4d000;
+ --accent:#ff3b30; --ok:#00b34a; --warn:#ffcc00; --bad:#ff3b30;
+ --font:'Marker Felt','Comic Sans MS',sans-serif;
+ --font-size-body:24px; --font-size-h:48px; --font-size-small:18px;
+ --gap:24px; --radius:24px; --padding:24px;
+ }
+ /* AGE 6-9 — Elementary, playful but legible */
+ body[data-band="kid"] {
+ --bg:#fff; --panel:#fef9c3; --fg:#1f2937; --muted:#4b5563; --border:#fbbf24;
+ --accent:#3b82f6; --ok:#16a34a; --warn:#f59e0b; --bad:#dc2626;
+ --font:'Comic Sans MS','Chalkboard SE',sans-serif;
+ --font-size-body:18px; --font-size-h:30px; --font-size-small:14px;
+ --gap:18px; --radius:14px; --padding:18px;
+ }
+ /* AGE 10-12 — Tween, structured, still color */
+ body[data-band="tween"] {
+ --bg:#fef3c7; --panel:#fff; --fg:#1f2937; --muted:#6b7280; --border:#fbbf24;
+ --accent:#6366f1; --ok:#16a34a; --warn:#f59e0b; --bad:#dc2626;
+ --font:'Avenir',-apple-system,sans-serif;
+ --font-size-body:15px; --font-size-h:22px; --font-size-small:12px;
+ --gap:14px; --radius:10px; --padding:14px;
+ }
+ /* AGE 13-19 — Teen / neon dark mode */
+ body[data-band="teen"] {
+ --bg:#0a0014; --panel:#1a0030; --fg:#f0f0ff; --muted:#8a7fb0; --border:#2a0050;
+ --accent:#ff00ff; --ok:#00ff88; --warn:#ffaa00; --bad:#ff0066;
+ --font:'JetBrains Mono','SF Mono',ui-monospace,monospace;
+ --font-size-body:12px; --font-size-h:18px; --font-size-small:10px;
+ --gap:10px; --radius:4px; --padding:10px;
+ }
+ /* AGE 20-44 — Adult, modern default */
+ body[data-band="adult"] {
+ --bg:#0a0c12; --panel:#161a26; --fg:#e6eef8; --muted:#7c8aa5; --border:#252b3d;
+ --accent:#7c3aed; --ok:#22c55e; --warn:#f59e0b; --bad:#ef4444;
+ --font-size-body:13px; --font-size-h:18px; --font-size-small:11px;
+ --gap:14px; --radius:8px; --padding:12px;
+ }
+ /* AGE 45-59 — Mature, slightly larger and calmer */
+ body[data-band="mature"] {
+ --bg:#f8f6f1; --panel:#fff; --fg:#1c1917; --muted:#57534e; --border:#d6d3d1;
+ --accent:#7c2d12; --ok:#15803d; --warn:#b45309; --bad:#991b1b;
+ --font:'Georgia','Iowan Old Style',serif;
+ --font-size-body:15px; --font-size-h:22px; --font-size-small:13px;
+ --gap:16px; --radius:6px; --padding:16px;
+ }
+ /* AGE 60-79 — Senior, hi-contrast, large readable */
+ body[data-band="senior"] {
+ --bg:#fff; --panel:#fff; --fg:#000; --muted:#333; --border:#000;
+ --accent:#0050a0; --ok:#006400; --warn:#a05000; --bad:#a00000;
+ --font:'Helvetica Neue',Helvetica,Arial,sans-serif;
+ --font-size-body:20px; --font-size-h:30px; --font-size-small:16px;
+ --gap:20px; --radius:6px; --padding:20px;
+ }
+ /* AGE 80+ — Elder, max contrast, essentials only */
+ body[data-band="elder"] {
+ --bg:#000; --panel:#000; --fg:#fff; --muted:#cccccc; --border:#fff;
+ --accent:#ffff00; --ok:#00ff00; --warn:#ffff00; --bad:#ff0000;
+ --font:'Helvetica Neue',Helvetica,Arial,sans-serif;
+ --font-size-body:26px; --font-size-h:42px; --font-size-small:20px;
+ --gap:28px; --radius:0; --padding:28px;
+ }
+
+ * { box-sizing:border-box; }
+ body { margin:0; background:var(--bg); color:var(--fg); font-family:var(--font); font-size:var(--font-size-body); min-height:100vh; padding:0 0 60px; transition: background 0.4s, color 0.4s; }
+
+ /* Slider bar — always visible at top */
+ .slider-bar { position:sticky; top:0; z-index:10; padding:14px 24px; background:var(--panel); border-bottom:2px solid var(--border); display:flex; gap:16px; align-items:center; flex-wrap:wrap; }
+ .slider-bar .age-num { font-weight:700; font-size:1.6em; color:var(--accent); min-width:80px; text-align:center; }
+ .slider-bar .age-band-label { color:var(--muted); font-size:0.9em; text-transform:uppercase; letter-spacing:1.5px; }
+ .slider-bar input[type=range] { flex:1; min-width:280px; accent-color:var(--accent); height:12px; }
+ .slider-bar .tagline { color:var(--muted); font-size:0.85em; flex-basis:100%; margin-top:6px; }
+
+ .container { padding:24px; }
+ h1 { font-size:var(--font-size-h); margin:0 0 8px; }
+ .sub { color:var(--muted); font-size:var(--font-size-small); margin-bottom:var(--gap); }
+
+ .grid { display:grid; gap:var(--gap); grid-template-columns:repeat(auto-fill,minmax(320px,1fr)); }
+ body[data-band="toddler"] .grid, body[data-band="senior"] .grid, body[data-band="elder"] .grid { grid-template-columns:1fr; }
+ body[data-band="kid"] .grid { grid-template-columns:repeat(auto-fill,minmax(280px,1fr)); }
+
+ .card { background:var(--panel); border:2px solid var(--border); border-radius:var(--radius); padding:var(--padding); display:flex; flex-direction:column; gap:8px; }
+ .card .name { font-family:var(--font-mono); font-weight:600; word-break:break-all; }
+ body[data-band="toddler"] .card .name, body[data-band="kid"] .card .name { font-family:var(--font); }
+ .card .last { color:var(--muted); font-size:var(--font-size-small); white-space:pre-wrap; line-height:1.4; max-height:4.2em; overflow:hidden; }
+ .card .action { color:var(--accent); font-style:italic; font-size:var(--font-size-small); }
+ body[data-band="senior"] .card .action, body[data-band="elder"] .card .action { font-style:normal; font-weight:700; }
+
+ /* Severity ribbon — meaning shifts across ages */
+ .sev-badge { display:inline-block; padding:4px 10px; border-radius:var(--radius); font-weight:700; font-size:var(--font-size-small); text-transform:uppercase; letter-spacing:1px; }
+ .sev-badge.high { background:var(--bad); color:#fff; }
+ .sev-badge.medium { background:var(--warn); color:#000; }
+ .sev-badge.low { background:var(--ok); color:#fff; }
+ body[data-band="senior"] .sev-badge, body[data-band="elder"] .sev-badge { padding:8px 14px; }
+
+ /* Hermes panel — collapses progressively */
+ .hermes { margin-top:var(--gap); padding:var(--padding); background:var(--panel); border:2px solid var(--border); border-radius:var(--radius); }
+ .hermes h2 { font-size:1.1em; margin:0 0 8px; }
+ .hermes .stat-line { color:var(--muted); font-size:var(--font-size-small); }
+ body[data-band="elder"] .hermes, body[data-band="toddler"] .hermes { display:none; }
+ body[data-band="kid"] .hermes .stat-line, body[data-band="senior"] .hermes .recent-feed { display:none; }
+
+ /* Toddler-mode: feeling face for each card */
+ .face { font-size:64px; line-height:1; }
+ body:not([data-band="toddler"]) .face { display:none; }
+ body[data-band="toddler"] .name { display:none; }
+ body[data-band="toddler"] .last, body[data-band="toddler"] .action, body[data-band="toddler"] .meta, body[data-band="toddler"] .footer { display:none; }
+ body[data-band="toddler"] .toddler-label { display:block; font-size:1.4em; text-align:center; margin-top:8px; font-weight:700; }
+ body:not([data-band="toddler"]) .toddler-label { display:none; }
+
+ /* Kid mode: simple emoji + name only */
+ .kid-icon { font-size:36px; }
+ body:not([data-band="kid"]) .kid-icon { display:none; }
+
+ /* Elder mode: just one row of essential info */
+ body[data-band="elder"] .card .last, body[data-band="elder"] .card .meta, body[data-band="elder"] .card .footer { display:none; }
+ body[data-band="elder"] .card { padding:32px; }
+ body[data-band="elder"] .card .name { font-size:0.7em; font-weight:400; color:var(--muted); }
+ body[data-band="elder"] .card .action { font-size:1.4em; line-height:1.3; }
+ body[data-band="elder"] .container h1 { font-size:1.5em; }
+
+ /* Teen mode: scan-lines */
+ body[data-band="teen"] { background-image: linear-gradient(rgba(255,0,255,0.03) 1px, transparent 1px); background-size: 100% 4px; }
+
+ .meta { color:var(--muted); font-size:var(--font-size-small); display:flex; gap:8px; flex-wrap:wrap; }
+ .footer { display:flex; gap:8px; justify-content:space-between; align-items:center; }
+ button.action-btn { background:var(--accent); color:#fff; border:none; padding:6px 12px; border-radius:var(--radius); font-size:var(--font-size-small); cursor:pointer; font-family:var(--font); font-weight:600; }
+ body[data-band="senior"] button.action-btn, body[data-band="elder"] button.action-btn { padding:18px 28px; font-size:1.2em; }
+ body[data-band="toddler"] button.action-btn { padding:22px 32px; font-size:1.4em; border-radius:32px; }
+</style>
+</head><body data-band="toddler">
+
+<div class="slider-bar">
+ <div>
+ <div class="age-num"><span id="ageDisplay">3</span> yr</div>
+ <div class="age-band-label" id="bandLabel">toddler</div>
+ </div>
+ <input id="ageSlider" type="range" min="3" max="95" value="3" />
+ <div class="tagline" id="tagline">Primary colors, huge taps. One face = good. One face = sad.</div>
+</div>
+
+<div class="container">
+ <h1 id="hed">Failures</h1>
+ <div class="sub" id="dek">A reading of what's going wrong, tuned to your age.</div>
+ <div class="grid" id="grid"></div>
+
+ <div class="hermes">
+ <h2>Hermes 3 <span style="font-size:0.7em; color:var(--muted);">(the helper)</span></h2>
+ <div class="stat-line" id="hStats"></div>
+ <div class="recent-feed" id="hRecent" style="margin-top:8px;"></div>
+ </div>
+</div>
+
+<script>
+// Age band rules — keep in sync with CSS [data-band=].
+function bandFor(age) {
+ if (age <= 5) return { id:'toddler', label:'toddler', tagline:'Primary colors, huge taps. One face = good. One face = sad.', hed:'Things to fix!' };
+ if (age <= 9) return { id:'kid', label:'elementary', tagline:'Friendly emoji and clear names. Easy actions.', hed:'Stuff to fix' };
+ if (age <= 12) return { id:'tween', label:'tween', tagline:'Brighter palette, more info per card, still simple actions.', hed:'Open issues' };
+ if (age <= 19) return { id:'teen', label:'teen', tagline:'Dense, dark, neon. Mono fonts. Power-user nav.', hed:'> FAILURES' };
+ if (age <= 44) return { id:'adult', label:'adult', tagline:'Modern dashboard. Sort + density + full Hermes panel.', hed:'Failures' };
+ if (age <= 59) return { id:'mature', label:'mature', tagline:'Serif typeface, calmer palette, larger touch targets.', hed:'Open Failures' };
+ if (age <= 79) return { id:'senior', label:'senior', tagline:'High contrast. Larger text. Clear primary actions.', hed:'What needs your attention' };
+ return { id:'elder', label:'elder', tagline:'Black & white, maximum text size, only the essentials. One issue at a time.', hed:'Today' };
+}
+
+const slider = document.getElementById('ageSlider');
+const ageDisplay = document.getElementById('ageDisplay');
+const bandLabel = document.getElementById('bandLabel');
+const tagline = document.getElementById('tagline');
+const hed = document.getElementById('hed');
+
+function applyBand(age) {
+ const b = bandFor(age);
+ document.body.dataset.band = b.id;
+ ageDisplay.textContent = age;
+ bandLabel.textContent = b.label;
+ tagline.textContent = b.tagline;
+ hed.textContent = b.hed;
+ renderGrid(b);
+}
+
+slider.addEventListener('input', e => applyBand(Number(e.target.value)));
+
+let _cachedData = null;
+async function loadData() {
+ const r = await fetch('/data' + location.search);
+ _cachedData = await r.json();
+ applyBand(Number(slider.value));
+}
+
+function emojiFor(severity, status) {
+ if (status === 'resolved') return '✅';
+ if (status === 'dismissed') return '😴';
+ if (severity === 'high') return '🚨';
+ if (severity === 'medium') return '⚠️';
+ if (severity === 'low') return '🟢';
+ return '❓';
+}
+function faceFor(severity, status) {
+ if (status === 'resolved' || status === 'dismissed') return '😊';
+ if (severity === 'high') return '😟';
+ if (severity === 'medium') return '😐';
+ if (severity === 'low') return '🙂';
+ return '😶';
+}
+function plainLabel(f) {
+ if (f.severity === 'high') return 'Something is BROKEN!';
+ if (f.severity === 'medium') return 'Something needs a look';
+ if (f.severity === 'low') return 'Everything is OK';
+ return 'Not sure yet';
+}
+
+function renderGrid(b) {
+ if (!_cachedData) return;
+ const grid = document.getElementById('grid');
+ let items = (_cachedData.failures || []).filter(f => f.status === 'triage' || f.status === 'investigating');
+
+ // Information density shrinks with age extremes
+ if (b.id === 'toddler') items = items.slice(0, 3);
+ else if (b.id === 'kid') items = items.slice(0, 4);
+ else if (b.id === 'elder') items = items.slice(0, 1);
+ else if (b.id === 'senior') items = items.slice(0, 3);
+
+ grid.innerHTML = items.map(f => {
+ const sevClass = f.severity || 'medium';
+ const ageBand = b.id;
+ if (ageBand === 'toddler') {
+ return `
+ <div class="card">
+ <div class="face">${faceFor(f.severity, f.status)}</div>
+ <div class="toddler-label">${plainLabel(f)}</div>
+ </div>`;
+ }
+ if (ageBand === 'kid') {
+ return `
+ <div class="card">
+ <div style="display:flex; align-items:center; gap:12px;">
+ <div class="kid-icon">${emojiFor(f.severity, f.status)}</div>
+ <div>
+ <div style="font-weight:700;">${f.processName}</div>
+ <div class="last">${(f.lastLines||'').split('\\n')[0].slice(0,80)}</div>
+ </div>
+ </div>
+ <button class="action-btn">Tell me more</button>
+ </div>`;
+ }
+ if (ageBand === 'elder') {
+ return `
+ <div class="card">
+ <div class="action">${f.suggestedAction || 'Click here when ready.'}</div>
+ <div class="name">${f.processName}</div>
+ <button class="action-btn">Done</button>
+ </div>`;
+ }
+ if (ageBand === 'senior') {
+ return `
+ <div class="card">
+ <div style="display:flex; gap:10px; align-items:center; margin-bottom:8px;">
+ <span class="sev-badge ${sevClass}">${f.severity || 'check'}</span>
+ <span style="font-weight:600;">${f.processName}</span>
+ </div>
+ <div class="last">${(f.lastLines||'').split('\\n')[0].slice(0,120)}</div>
+ ${f.suggestedAction ? `<div class="action">${f.suggestedAction}</div>` : ''}
+ <button class="action-btn">View details</button>
+ </div>`;
+ }
+ // adult / mature / tween / teen — full standard card with band-specific styling via CSS vars
+ return `
+ <div class="card">
+ <div class="meta">
+ <span class="sev-badge ${sevClass}">${f.severity || '—'}</span>
+ <span>${f.source}</span>
+ <span>×${f.eventCount}</span>
+ </div>
+ <div class="name">${f.processName}</div>
+ <div class="last">${(f.lastLines||'').split('\\n').filter(Boolean)[0]?.slice(0,120) || ''}</div>
+ ${f.suggestedAction ? `<div class="action">→ ${f.suggestedAction}</div>` : ''}
+ <div class="footer">
+ <span style="font-size:var(--font-size-small); color:var(--muted);">${new Date(f.lastSeen||f.created).toLocaleTimeString([],{hour:'2-digit',minute:'2-digit'})}</span>
+ <button class="action-btn">Open</button>
+ </div>
+ </div>`;
+ }).join('');
+ if (items.length === 0) grid.innerHTML = '<div class="card" style="text-align:center; padding:40px;">All clear!</div>';
+
+ // Hermes summary
+ const h = _cachedData.hermes ? _cachedData.hermes.last24h : null;
+ if (h) {
+ document.getElementById('hStats').innerHTML = b.id === 'kid'
+ ? `Hermes checked <b>${h.total}</b> things today and answered <b>${h.ok}</b> right.`
+ : `${h.total} calls · ${h.byType.classify} cls · ${h.byType['idea-chat']} idea · ${(h.avgLatencyMs/1000).toFixed(1)}s avg · ${h.fail} failed`;
+ const recent = (_cachedData.hermes.recent || []).slice(0, b.id==='senior'?2:b.id==='mature'?3:5);
+ document.getElementById('hRecent').innerHTML = recent.map(c => {
+ const ok = c.ok ? '✓' : '✗';
+ const t = new Date(c.ts).toLocaleTimeString([],{hour:'2-digit',minute:'2-digit'});
+ return `<div style="font-size:var(--font-size-small); color:var(--muted); margin-top:2px;">${ok} ${t} ${c.type} · ${(c.target||'').slice(0,40)}</div>`;
+ }).join('');
+ } else {
+ document.getElementById('hStats').textContent = '';
+ document.getElementById('hRecent').textContent = '';
+ }
+}
+
+loadData();
+</script>
+</body></html>
← 5d00c00 live-data toggle: /data proxies real CNCP failures + hermes
·
back to Cncp Failures Mockups
·
v7 UI hooks: 8 band quick-jump pills, per-band modal/toast h 788f2be →