Initial commit

This commit is contained in:
kfj001 committed 2026-09-06 10:18:26 -07:00
commit 5f2db08b43
100 files changed
+16985

No files matched your search

@@ -0,0 +1,192 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Watch a legislator / Opt into a topic — controls (wireframe)</title>
<style>
:root{
--ink:#1a1a1a;--muted:#5b5b5b;--paper:#fff;--surface:#f4f5f7;
--border:#d5d9df;--border-strong:#b8bfc9;
--accent:#0b5394;--accent-ink:#08345f;--success:#1e7e34;--warn:#8a5a00;--danger:#b3261e;
--personal-band:#eaf1f8;
--ring:0 0 0 2px #fff,0 0 0 4px var(--accent);
--font-ui:-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
--font-mono:ui-monospace,"SFMono-Regular","Menlo",Consolas,monospace;
--radius:4px;--shadow:0 1px 2px rgba(0,0,0,.06),0 2px 8px rgba(0,0,0,.05);--maxw:1080px;
}
*{box-sizing:border-box}html,body{margin:0}
body{font-family:var(--font-ui);color:var(--ink);background:var(--surface);font-size:15px;line-height:1.5;text-wrap:pretty}
a{color:var(--accent);text-underline-offset:2px}h1,h2,h3{line-height:1.2;margin:0}
:where(a,button,[tabindex]):focus-visible{outline:none;box-shadow:var(--ring);border-radius:var(--radius)}
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}
.skip{position:absolute;left:-999px;top:0;background:var(--accent);color:#fff;padding:.6em 1em;z-index:10}.skip:focus{left:8px;top:8px}
.wrap{max-width:var(--maxw);margin:0 auto;padding:22px 20px 64px}
h1{font-size:20px;margin-bottom:2px}.sub{color:var(--muted);margin:0 0 18px;font-size:14px}
.panel{background:var(--paper);border:1px solid var(--border);border-radius:var(--radius);padding:16px 18px;margin-bottom:16px;box-shadow:var(--shadow)}
.panel h2{font-size:14px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);margin:0 0 4px}
.panel .desc{font-size:14px;color:var(--ink);margin:0 0 12px}
.states{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px}
.state{border:1px solid var(--border);border-radius:6px;padding:12px;background:var(--surface)}
.state .lbl{font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);margin-bottom:8px;font-weight:600}
.state .note{font-size:11px;color:var(--muted);margin-top:8px}
/* toggle */
.toggle{position:relative;width:40px;height:22px;flex:none}
.toggle input{opacity:0;width:100%;height:100%;margin:0;cursor:pointer}
.toggle .knob{position:absolute;inset:0;background:var(--border-strong);border-radius:999px;transition:background .12s}
.toggle .knob::after{content:"";position:absolute;width:16px;height:16px;background:#fff;border-radius:50%;top:3px;left:3px;transition:left .12s}
.toggle input:checked+.knob{background:var(--success)}.toggle input:checked+.knob::after{left:21px}
.toggle input:disabled+.knob{background:#e6e8ec}.toggle input:disabled+.knob::after{background:#fff}
.stat{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.4px}
.stat.on{color:var(--success)}.stat.off{color:var(--muted)}
/* opt-in chip */
.optchip{display:inline-flex;align-items:center;gap:7px;font-size:14px;border:1px solid var(--border-strong);
background:#fff;border-radius:999px;padding:6px 12px;cursor:pointer;color:var(--ink);min-height:40px}
.optchip:hover{border-color:var(--accent)}.optchip:disabled{opacity:.55;cursor:not-allowed;border-color:var(--border)}
.optchip.on{background:var(--personal-band);border-color:var(--accent);font-weight:600}
.optchip .box{width:15px;height:15px;border:1.5px solid var(--border-strong);border-radius:3px;display:inline-flex;align-items:center;justify-content:center;font-size:11px}
.optchip.on .box{background:var(--accent);border-color:var(--accent);color:#fff}
.optchip .n{color:var(--muted);font-variant-numeric:tabular-nums}
.row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.who{flex:1;min-width:150px}.who b{font-weight:600}.who small{display:block;color:var(--muted);font-size:12px}
/* legend for the meaning-cued indicators */
.legend{display:flex;gap:18px;flex-wrap:wrap;font-size:13px;color:var(--muted);margin-top:6px}
.legend i{display:inline-block;width:3px;height:14px;border-radius:2px;vertical-align:middle;margin-right:6px}
.leg-l{background:var(--success)}.leg-t{background:var(--accent)}
/* buttons */
.btn{background:var(--accent);color:#fff;border:none;border-radius:var(--radius);padding:8px 14px;min-height:36px;font-weight:600;cursor:pointer}
.btn:hover{background:var(--accent-ink)}.btn.ghost{background:#fff;border:1px solid var(--accent);color:var(--accent)}
.btn.ghost:hover{background:var(--accent);color:#fff}
.pillrow{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.pill{border:1px solid var(--border-strong);border-radius:999px;padding:4px 10px;font-size:12px;background:#fff;cursor:pointer}
.wf-note{position:fixed;right:12px;bottom:12px;background:var(--ink);color:#fff;font-size:11px;padding:5px 9px;border-radius:3px;opacity:.9;font-family:var(--font-mono)}
@media(max-width:640px){.states{grid-template-columns:1fr 1fr}}
@media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
</style>
</head>
<body>
<a class="skip" href="#main">Skip to content</a>
<main id="main" class="wrap">
<h1>Control states — “Watch a legislator” &amp; “Opt into a topic”</h1>
<p class="sub">Every control, every state, with the meaning-cued indicators that tell the user *why* a bill floated. These are the pieces of §5B / §10 of the design spec, shown in isolation for the build lane.</p>
<!-- 1. ZIP / address resolution -->
<section class="panel" aria-labelledby="z">
<h2 id="z">1 · Resolve ZIP / address → legislators</h2>
<p class="desc">Fast path first; falls back to address or manual because a ZIP can span more than one district.</p>
<div class="row" style="gap:10px;align-items:flex-end;flex-wrap:wrap">
<label style="display:flex;flex-direction:column;gap:3px;font-size:12px;color:var(--muted)">ZIP
<input inputmode="numeric" maxlength="5" placeholder="90210" style="max-width:130px;padding:8px 10px;border:1px solid var(--border-strong);border-radius:var(--radius);font-family:var(--font-mono)" aria-label="ZIP code"></label>
<button class="btn" type="button">Find my legislators</button>
<a href="#">Use a full address instead →</a>
</div>
<div class="pillrow" aria-label="Result states">
<span style="font-size:12px;color:var(--muted);align-self:center">Result states:</span>
<button class="pill" type="button">single district ✓</button>
<button class="pill" type="button">ambiguous (2–3) → confirm</button>
<button class="pill" type="button">zero → manual picker</button>
<button class="pill" type="button">out-of-state</button>
</div>
</section>
<!-- 2. Watch toggle: all states -->
<section class="panel" aria-labelledby="w">
<h2 id="w">2 · Watch toggle (legislator)</h2>
<p class="desc">Watches a legislator by authorship or committee membership. Optimistic update on toggle; re-ranks the personal band instantly.</p>
<div class="states">
<div class="state">
<div class="lbl">Default · not watched</div>
<div class="row">
<div class="who"><b>R. Riu</b><small>Senate D-08 · R · Health</small></div>
<label class="toggle"><input type="checkbox" aria-label="Watch R. Riu"><span class="knob"></span></label>
<span class="stat off">Not watched</span>
</div>
<div class="note">Off. No effect on ranking.</div>
</div>
<div class="state">
<div class="lbl">Checked · watching</div>
<div class="row">
<div class="who"><b>M. Schiavo</b><small>Assembly D-14 · D · Resources &amp; Water</small></div>
<label class="toggle"><input type="checkbox" checked aria-label="Watch M. Schiavo"><span class="knob"></span></label>
<span class="stat on">Watching</span>
</div>
<div class="note">On. Bills float to top. Green bar.</div>
</div>
<div class="state">
<div class="lbl">Focus</div>
<div class="row">
<div class="who"><b>T. Vega</b><small>Assembly D-14 · D</small></div>
<label class="toggle"><input type="checkbox" aria-label="Watch T. Vega" style="outline:none;box-shadow:var(--ring)"><span class="knob"></span></label>
<span class="stat off">Not watched</span>
</div>
<div class="note">2px focus ring visible.</div>
</div>
<div class="state">
<div class="lbl">Disabled · off-rolodex</div>
<div class="row">
<div class="who"><b>(term-end)</b><small>Not on current roster</small></div>
<label class="toggle"><input type="checkbox" disabled aria-label="Watch (unavailable)"><span class="knob"></span></label>
<span class="stat off">Unavailable</span>
</div>
<div class="note">Past legislator; locked out.</div>
</div>
</div>
</section>
<!-- 3. Topic opt-in: a live chip with its states -->
<section class="panel" aria-labelledby="t">
<h2 id="t">3 · Topic opt-in chip</h2>
<p class="desc">Opt into a subject-matter tag (from the LLM lane). Count shows how many bills carry it. Toggling re-ranks.</p>
<div class="states">
<div class="state"><div class="lbl">Off</div>
<button class="optchip" type="button" data-toggle><span class="box"></span>Housing <span class="n">· 97</span></button>
<div class="note">Not followed. No effect.</div></div>
<div class="state"><div class="lbl">On (followed)</div>
<button class="optchip on" type="button" data-toggle><span class="box" aria-hidden="true">✓</span>Waste <span class="n">· 42</span></button>
<div class="note">Followed. Bills float up.</div></div>
<div class="state"><div class="lbl">Focus</div>
<button class="optchip" type="button" data-toggle style="outline:none;box-shadow:var(--ring)"><span class="box"></span>Transportation <span class="n">· 51</span></button>
<div class="note">Keyboard target.</div></div>
<div class="state"><div class="lbl">Unavailable · no tags yet</div>
<button class="optchip" type="button" disabled><span class="box"></span>Topic analysis pending <span class="n">—</span></button>
<div class="note">LLM lane warming; not offered yet.</div></div>
</div>
</section>
<!-- 4. Meaning-cued indicator legend -->
<section class="panel" aria-labelledby="m">
<h2 id="m">4 · “Why this here” indicators (the float reason)</h2>
<p class="desc">The left bar + chip tell the user <em>why</em> a bill floated — a trust requirement, not decoration.</p>
<div class="row" style="align-items:stretch;gap:14px;flex-wrap:wrap">
<div style="flex:1;min-width:280px;border:1px solid var(--border);border-left:3px solid var(--success);border-radius:4px;padding:12px">
<div style="font-weight:600">AB 28 — Waste standards</div>
<div style="font-size:13px;color:var(--muted);margin-top:4px">Schiavo · Resources &amp; Water · 9:30am</div>
<div style="font-size:12px;color:var(--success);font-weight:600;margin-top:6px">● Your legislator · Topic: Waste</div>
<a href="#" style="font-size:12px">Why is this here? →</a>
</div>
<div style="flex:1;min-width:280px;border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:4px;padding:12px">
<div style="font-weight:600">SB 795 — Health program</div>
<div style="font-size:13px;color:var(--muted);margin-top:4px">Riu · Health · 10:00am</div>
<div style="font-size:12px;color:var(--accent);font-weight:600">● Topic: Health</div>
<a href="#" style="font-size:12px">Why is this here? →</a>
</div>
</div>
<div class="legend">
<span><i class="leg-l"></i>green bar = watched-legislator match</span>
<span><i class="leg-t"></i>blue bar = opted-in-topic match</span>
<span>color never the only signal — each pair carries text too</span>
</div>
</section>
</main>
<span class="wf-note">wireframe · 03 watch / opt-in controls</span>
<script>
document.querySelectorAll('[data-toggle]').forEach(c=>c.addEventListener('click',()=>{
const on=c.classList.toggle('on');
const box=c.querySelector('.box');
box.textContent=on?'✓':'';
box.setAttribute('aria-hidden', on?'true':'false');
}));
</script>
</body>
</html>