Files
cali_scraper/design/wireframes/watch-and-opt-in-controls.html
T
2026-09-06 10:18:26 -07:00

193 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>