ui: staffing co-pilot UX fixes — new-tab reference nav + discoverable collapsibles

Reconciles month-old working-tree UX work (served per-request, live on the demo since
2026-05-30) into git. Implements UX_FIX_PLAN.md's 5 user complaints: reference pages
(Profiler/Architecture/Spec/Onboard/Alerts/Workspaces) open in new tabs; contract-card
collapsible shows a persistent chevron + expand/collapse label in both states; proof.html
gains a substrate-signals chapter. Not authored this session — captured as-is (working
state verified: pages serve 200).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claw
2026-06-30 22:55:33 -05:00
co-authored by Claude Opus 4.8
parent 7dddb98f4b
commit 7365a4c23e
7 changed files with 230 additions and 85 deletions
+91 -84
View File
@@ -135,6 +135,26 @@ body{font-family:'Inter',-apple-system,system-ui,'Segoe UI',sans-serif;backgroun
.ft{text-align:center;padding:24px;color:#3d444d;font-size:11px;border-top:1px solid #171d27;margin-top:32px}
.ft a{color:#545d68;text-decoration:none;transition:color 0.15s}
.ft a:hover{color:#e6edf3}
/* ── UX pass 2026-05-30: clearer interactive affordances ── */
[onclick]{cursor:pointer}
[role="button"]{cursor:pointer}
.iworker{cursor:pointer}
.iworker:hover{background:#1c2333;transform:translateY(-1px);box-shadow:0 2px 8px rgba(0,0,0,.3),0 0 0 1px #30363d;transition:background .15s,transform .15s,box-shadow .15s}
.iworker:active{transform:translateY(0);box-shadow:none}
details>summary{cursor:pointer}
details>summary:hover{color:#e6edf3;background:rgba(58,90,127,.15);border-radius:6px}
a:focus-visible,button:focus-visible,summary:focus-visible,[onclick]:focus-visible{outline:2px solid #388bfd;outline-offset:2px;border-radius:4px}
/* ③ example-search disclosure (2026-05-30) — collapsed by default, CSS-only hover/focus */
.samples-disclosure{font-size:11px}
.samples-summary{display:inline-flex;align-items:center;gap:6px;cursor:pointer;color:#8b949e;list-style:none;padding:4px 0;user-select:none}
.samples-summary::-webkit-details-marker{display:none}
.samples-summary::before{content:'▸';display:inline-block;font-size:10px;transition:transform .15s}
.samples-disclosure[open] .samples-summary::before{transform:rotate(90deg)}
.samples-summary:hover{color:#e6edf3}
.samples-row{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.search-chip{font-size:11px;padding:5px 10px;background:#161b22;border:1px solid #30363d;border-radius:14px;color:#8b949e;cursor:pointer;transition:border-color .15s,color .15s,background .15s}
.search-chip:hover{border-color:#58a6ff;color:#e6edf3;background:#1c2333}
.search-chip:focus-visible{outline:2px solid #388bfd;outline-offset:2px}
.ld{color:#3d444d;text-align:center;padding:40px;font-size:13px}
/* Reused pulse keyframe — shared by status dots in the market-pulse
@@ -336,6 +356,18 @@ body{font-family:'Inter',-apple-system,system-ui,'Segoe UI',sans-serif;backgroun
line-height: 1;
}
.contract-card.expanded .card-toggle .chevron { transform: rotate(180deg) }
/* Persistent top-of-card expand affordance (2026-05-30 UX) — always
visible, button-styled so users immediately see the card expands. */
.contract-card .card-top-toggle {
display: inline-flex; align-items: center; gap: 6px;
padding: 4px 10px; margin-bottom: 10px;
font-size: 11px; font-weight: 600; color: #8b949e;
background: #161b22; border: 1px solid #30363d; border-radius: 7px;
cursor: pointer; user-select: none;
transition: background .15s, border-color .15s, color .15s;
}
.contract-card .card-top-toggle:hover { background: #1c2333; border-color: #58a6ff; color: #e6edf3 }
.contract-card .card-top-toggle .chevron { display:inline-block; font-size:12px; line-height:1 }
@media (prefers-reduced-motion: reduce) {
.contract-card { transition: none }
.contract-card:hover { transform: none }
@@ -591,12 +623,12 @@ body{font-family:'Inter',-apple-system,system-ui,'Segoe UI',sans-serif;backgroun
<nav>
<a href="." class="active">Dashboard</a>
<a href="console">Walkthrough</a>
<a href="profiler">Profiler</a>
<a href="proof">Architecture</a>
<a href="spec">Spec</a>
<a href="onboard">Onboard</a>
<a href="alerts">Alerts</a>
<a href="workspaces">Workspaces</a>
<a href="profiler" target="_blank" rel="noopener">Profiler ↗</a>
<a href="proof" target="_blank" rel="noopener">Architecture ↗</a>
<a href="spec" target="_blank" rel="noopener">Spec ↗</a>
<a href="onboard" target="_blank" rel="noopener">Onboard ↗</a>
<a href="alerts" target="_blank" rel="noopener">Alerts ↗</a>
<a href="workspaces" target="_blank" rel="noopener">Workspaces ↗</a>
</nav>
<div class="rt" id="status">Loading...</div>
</div>
@@ -711,10 +743,15 @@ body{font-family:'Inter',-apple-system,system-ui,'Segoe UI',sans-serif;backgroun
<div class="section" id="market-section">
<div class="section-header">
<span class="section-title">Market Intelligence</span>
<span class="section-meta">Public permit data · Updated live</span>
<span class="section-title">Market Intelligence — Chicago permit map</span>
<span class="section-meta">Where the construction money is · live from data.cityofchicago.org</span>
</div>
<div id="market"></div>
<p style="color:#8b949e;font-size:11px;margin:0 0 10px;line-height:1.5;max-width:680px">
The geographic companion to ① Live Market: every active building permit plotted
by location, sized by construction value. ① tells you <em>when</em> the shifts are;
this tells you <em>where</em> the work is.
</p>
<div id="market"><div style="color:#8b949e;font-size:11px;padding:8px 0">Loading Chicago permit map…</div></div>
</div>
<!-- ═══ ③ Worker Search — natural-language lookup over the 500K bench ═══ -->
@@ -747,12 +784,18 @@ body{font-family:'Inter',-apple-system,system-ui,'Segoe UI',sans-serif;backgroun
</div>
<!-- ═══ ④ System Activity — what the substrate has learned to do ═══ -->
<div class="section" id="learning-section">
<div class="section-header">
<!-- 2026-05-30: demoted to a collapsed-by-default <details> (tier 3). It's
capability/reference info, not the day's staffing work, so it no longer
competes for attention on every load. Mirrors the ⓪ legacy-bridge pattern:
ontoggle flips the ▸/▾ hint. loadLearning() still populates #learning. -->
<details class="section" id="learning-section"
ontoggle="var s=this.querySelector('.lr-toggle-hint');if(s)s.textContent=this.open?'▾ click to collapse':'▸ click to expand'">
<summary style="list-style:none;cursor:pointer;display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;outline:none">
<span class="section-title" style="color:#e6edf3;font-size:13px">④ System Activity — what the substrate has learned to do</span>
<span class="section-meta">Live capabilities · pulled from each subsystem on load</span>
</div>
<p style="color:#8b949e;font-size:11px;margin:0 0 12px;line-height:1.5;max-width:780px">
<span class="lr-toggle-hint" style="margin-left:auto;font-size:10px;color:#545d68">▸ click to expand</span>
</summary>
<p style="color:#8b949e;font-size:11px;margin:10px 0 12px;line-height:1.5;max-width:780px">
Each tile is a capability the system has acquired and the live metric proving
it's running. Operational learning (fills, playbooks, hot-swaps) compounds
inside each capability; what changes here is the <em>set of things the
@@ -760,25 +803,14 @@ body{font-family:'Inter',-apple-system,system-ui,'Segoe UI',sans-serif;backgroun
capability replicates by config, not code.
</p>
<div id="learning"></div>
</div>
</details>
<!-- ═══ ⑤ Substrate signals — compact architecture-health strip (bottom) ═══ -->
<div class="section" id="arch-signals-section">
<div class="section-header">
<span class="section-title" style="color:#e6edf3;font-size:13px">⑤ Substrate Signals — architecture health</span>
<span class="section-meta">Live probes of the index, memory, and pathway layers</span>
</div>
<p style="color:#8b949e;font-size:11px;margin:0 0 10px;line-height:1.5;max-width:680px">
These tiles measure the architecture itself, not the staffing workload.
Instant-search latency, index shape, playbook-memory depth, pathway-matrix
compounding — four probes that answer "is the substrate healthy right now?"
</p>
<div id="arch-signals" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px">
<div style="color:#8b949e;font-size:11px;grid-column:1/-1">Probing substrate…</div>
</div>
</div>
<!-- ⑤ Substrate Signals (architecture-health probes) moved to the Architecture
page (proof.html, Chapter 11) on 2026-05-30 — they measure the substrate,
not the staffing workload, so they belong with the architecture story and
keep this operator dashboard focused on the day's work. Link in the footer. -->
<div class="ft" id="footer">Staffing Co-Pilot · Hybrid SQL + Vector Search · loading scale… · <a href="console">Console</a> · <a href="proof">Architecture</a></div>
<div class="ft" id="footer">Staffing Co-Pilot · Hybrid SQL + Vector Search · loading scale… · <a href="console">Console</a> · <a href="proof" target="_blank" rel="noopener">Architecture ↗</a></div>
</div>
<!-- ═══ Mobile section-jump dock — visible < 768px only via CSS ═══ -->
@@ -792,7 +824,7 @@ body{font-family:'Inter',-apple-system,system-ui,'Segoe UI',sans-serif;backgroun
<a href="#live-contracts-section" title="Open contracts + candidates">②<span class="dock-label">Jobs</span></a>
<a href="#worker-search-section" title="Search 500K workers">③<span class="dock-label">Search</span></a>
<a href="#learning-section" title="What the substrate has learned">④<span class="dock-label">Learn</span></a>
<a href="#arch-signals-section" title="Live architecture health">⑤<span class="dock-label">Stack</span></a>
<a href="proof" title="Architecture &amp; live substrate signals" target="_blank" rel="noopener">✦<span class="dock-label">Arch</span></a>
</nav>
<script>
var P=location.pathname.indexOf('/lakehouse')>=0?'/lakehouse':'';
@@ -826,7 +858,7 @@ function styleSkelStages(){
}
window.addEventListener('load',function(){
styleSkelStages(); startSkelStages();
loadSystemSummary();loadLegacyBridge();loadDay();loadStaffingForecast();loadLiveContracts();loadMarket();loadLearning();loadWorkerSearchSamples();loadArchSignals();loadStaffers();
loadSystemSummary();loadLegacyBridge();loadDay();loadStaffingForecast();loadLiveContracts();loadMarket();loadLearning();loadWorkerSearchSamples();loadStaffers();
});
// Per-staffer hot-swap dropdown — runs independently of the simulation
@@ -989,6 +1021,15 @@ function loadWorkerSearchSamples(){
{tag:'Specialist', q:'maintenance tech comfortable with Allen-Bradley PLCs'},
{tag:'High-volume', q:'warehouse associates available next week near Indianapolis'}
];
// 2026-05-30: wrap the 6 example chips in a collapsed disclosure so they
// don't consume vertical space on every load. The chip keeps its tag+query
// two-span layout and scroll-into-view click; the disclosure just gates them.
el.textContent='';
var det=document.createElement('details');det.className='samples-disclosure';
var sum=document.createElement('summary');sum.className='samples-summary';
sum.textContent='Example searches';
det.appendChild(sum);
var row=document.createElement('div');row.className='samples-row';
samples.forEach(function(s){
var chip=document.createElement('button');
chip.type='button';
@@ -1002,8 +1043,10 @@ function loadWorkerSearchSamples(){
var input=document.getElementById('sq');
if(input){input.value=s.q;doSearch();input.scrollIntoView({behavior:'smooth',block:'center'});}
};
el.appendChild(chip);
row.appendChild(chip);
});
det.appendChild(row);
el.appendChild(det);
}
function loadSystemSummary(){
@@ -1023,7 +1066,7 @@ function loadSystemSummary(){
foot.appendChild(document.createTextNode('Staffing Co-Pilot · Hybrid SQL + Vector Search · '+totalRows+' rows across '+ds+' datasets · '+chunks+' vector chunks · '));
var a1=document.createElement('a');a1.href='console';a1.textContent='Console';foot.appendChild(a1);
foot.appendChild(document.createTextNode(' · '));
var a2=document.createElement('a');a2.href='proof';a2.textContent='Architecture';foot.appendChild(a2);
var a2=document.createElement('a');a2.href='proof';a2.target='_blank';a2.rel='noopener';a2.textContent='Architecture ↗';foot.appendChild(a2);
}
// Also update the collapsible search box label if not yet populated
var sum=document.querySelector('.sa summary');
@@ -1033,56 +1076,9 @@ function loadSystemSummary(){
}).catch(function(){/* non-fatal */});
}
// ─── Substrate signals: render the 4 architecture-health tiles ───
function loadArchSignals(){
var el=document.getElementById('arch-signals');
api('/intelligence/arch_signals',{}).then(function(s){
el.textContent='';
function tile(label, big, sub, accent){
var t=document.createElement('div');
t.style.cssText='background:#0d1117;border:1px solid #171d27;border-radius:10px;padding:14px 16px;border-left:3px solid '+(accent||'#58a6ff');
var l=document.createElement('div');l.style.cssText='font-size:10px;text-transform:uppercase;letter-spacing:1px;color:#545d68;margin-bottom:6px';l.textContent=label;
var b=document.createElement('div');b.style.cssText='font-size:20px;font-weight:600;color:#e6edf3;line-height:1.1';b.textContent=big;
var u=document.createElement('div');u.style.cssText='font-size:10px;color:#8b949e;margin-top:6px;line-height:1.4';u.textContent=sub;
t.appendChild(l);t.appendChild(b);t.appendChild(u);
return t;
}
var idx=s.index||{};
var pbm=s.playbook_memory||{};
var pwm=s.pathway_memory||{};
// Tile 1 — instant search (the "we cleverly indexed at ingest" claim)
var latencyColor=s.instant_search_probe_ms<100?'#2ea043':s.instant_search_probe_ms<500?'#d29922':'#f85149';
el.appendChild(tile(
'Instant Search',
(s.instant_search_probe_ms||'?')+'ms',
'Live /vectors/hybrid probe · 500K-row index · '+(idx.chunk_count||0).toLocaleString()+' chunks',
latencyColor
));
// Tile 2 — index shape (hot-swap claim)
el.appendChild(tile(
'Index',
(idx.dimensions||768)+'d · '+(idx.model||'?'),
(idx.source||'?')+' → '+(idx.name||'?')+' · '+(idx.backend||'parquet'),
'#58a6ff'
));
// Tile 3 — self-regulating memory
el.appendChild(tile(
'Playbook Memory',
(pbm.entries||0).toLocaleString()+' entries',
pbm.entries>0?'Meta-index active · boosts candidates from past fills':'Empty · POST /vectors/playbook_memory/rebuild to populate',
pbm.entries>0?'#2ea043':'#d29922'
));
// Tile 4 — ADR-021 pathway compounding
el.appendChild(tile(
'Pathway Matrix',
(pwm.total_pathways||0)+' traces',
pwm.retired+' retired · '+pwm.total_replays+' replays · ADR-021 compounding',
'#58a6ff'
));
}).catch(function(e){
el.textContent='substrate signals unavailable: '+e.message;
});
}
// ⑤ loadArchSignals() was MOVED to proof.html (Architecture, Chapter 11)
// on 2026-05-30 — the architecture-health probes live with the rest of the
// architecture story now, so the dashboard stays focused on staffing work.
// ─── Live Market hero: 24/7 shift clock (left) + Chicago permit pulse (right) ──
// Combines two previously-separate tiles into one coherent "what's happening in
@@ -2534,6 +2530,15 @@ function loadLiveContracts(){
right.appendChild(rate);
}
hdr.appendChild(left);hdr.appendChild(right);card.appendChild(hdr);
// Persistent expand affordance at the TOP of the card (2026-05-30
// UX). The whole card is already clickable; this makes the toggle
// obvious and shows expand state in BOTH collapsed and expanded
// form. Text + chevron are flipped by the card click handler below.
var topToggle=document.createElement('div');topToggle.className='card-top-toggle';
var topChev=document.createElement('span');topChev.className='chevron';topChev.textContent='▸';
var topLabel=document.createElement('span');topLabel.textContent='Show details';
topToggle.appendChild(topChev);topToggle.appendChild(topLabel);
card.appendChild(topToggle);
// Architecture pill row — instant-search latency + shift coverage
// + pool-size proof that the index actually fired on this call.
// This is the "our substrate is better" surface J asked for.
@@ -2853,6 +2858,8 @@ function loadLiveContracts(){
toggleLabel.textContent=nowExpanded
? 'click to collapse'
: 'click for full curve, economics, candidates, project index';
topLabel.textContent=nowExpanded?'Hide details':'Show details';
topChev.textContent=nowExpanded?'▾':'▸';
// Auto-open the Project Index ONLY on user-driven expand. This
// avoids firing 20+ OSHA scrapes on page load — each open
// triggers /intelligence/permit_entities, which live-scrapes