Initial commit
This commit is contained in:
commit
5f2db08b43
100 files changed
+16985
No files matched your search
@@ -0,0 +1,286 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Legislative Dashboard — Anonymous overview (wireframe)</title>
|
||||
<style>
|
||||
/* --- Design tokens: government-appropriate, calm, high contrast (WCAG AA) --- */
|
||||
:root{
|
||||
--ink:#1a1a1a; --muted:#5b5b5b; --paper:#ffffff; --surface:#f4f5f7;
|
||||
--border:#d5d9df; --border-strong:#b8bfc9;
|
||||
--accent:#0b5394; --accent-ink:#08345f;
|
||||
--success:#1e7e34; --warn:#8a5a00; --danger:#b3261e;
|
||||
--asm:#2f5aa7; --sen:#7a3b8f; /* chip tints only, never page fill */
|
||||
--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; /* restrained, not rounded-everywhere */
|
||||
--shadow:0 1px 2px rgba(0,0,0,.06), 0 2px 8px rgba(0,0,0,.05);
|
||||
--maxw:1160px;
|
||||
}
|
||||
*{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-decoration:underline; text-underline-offset:2px}
|
||||
a:hover{color:var(--accent-ink)}
|
||||
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}
|
||||
|
||||
/* --- Layout scaffold --- */
|
||||
.top{position:sticky;top:0;z-index:5;display:flex;align-items:center;gap:16px;
|
||||
background:var(--paper);border-bottom:1px solid var(--border);padding:10px 20px}
|
||||
.wordmark{font-weight:700;font-size:17px;letter-spacing:.2px;white-space:nowrap}
|
||||
.wordmark small{display:block;font-weight:500;font-size:11px;color:var(--muted);letter-spacing:.4px;text-transform:uppercase}
|
||||
nav.main{display:flex;gap:18px;margin-left:4px}
|
||||
nav.main a{color:var(--ink);text-decoration:none;font-weight:500}
|
||||
nav.main a:hover{text-decoration:underline}
|
||||
.spacer{flex:1}
|
||||
.signin{background:var(--accent);color:#fff;font-weight:600;border:none;border-radius:var(--radius);
|
||||
padding:8px 14px;font-size:14px;cursor:pointer;min-height:36px}
|
||||
.signin:hover{background:var(--accent-ink)}
|
||||
.shell{max-width:var(--maxw);margin:0 auto;padding:18px 20px 64px}
|
||||
|
||||
/* --- Status / freshness band --- */
|
||||
.fresh{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;background:var(--paper);
|
||||
border:1px solid var(--border);border-radius:var(--radius);padding:10px 14px;box-shadow:var(--shadow)}
|
||||
.fresh .badge{font-size:12px;font-weight:600;background:var(--surface);border:1px solid var(--border);
|
||||
border-radius:999px;padding:2px 10px}
|
||||
.fresh .ok{color:var(--success)} .fresh .pend{color:var(--warn)}
|
||||
.fresh .dot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px;vertical-align:middle}
|
||||
.dot.g{background:var(--success)} .dot.y{background:var(--warn)}
|
||||
.refresh{margin-left:auto;font-size:13px;color:var(--muted)}
|
||||
h1.page{font-size:22px;margin:18px 0 4px}
|
||||
.lede{color:var(--muted);max-width:70ch;margin:0 0 16px}
|
||||
|
||||
/* --- Controls bar --- */
|
||||
.controls{display:flex;flex-wrap:wrap;gap:8px 10px;align-items:center;
|
||||
background:var(--paper);border:1px solid var(--border);border-radius:var(--radius);
|
||||
padding:10px 12px;margin-bottom:16px;box-shadow:var(--shadow)}
|
||||
.controls label{font-size:12px;color:var(--muted);display:flex;flex-direction:column;gap:2px}
|
||||
.controls input[type=search]{min-width:280px;padding:7px 10px;font-size:14px;
|
||||
border:1px solid var(--border-strong);border-radius:var(--radius)}
|
||||
.controls select{padding:7px 8px;font-size:14px;border:1px solid var(--border-strong);
|
||||
border-radius:var(--radius);background:#fff}
|
||||
.chipfilter{display:flex;flex-wrap:wrap;gap:6px}
|
||||
.fchip{display:inline-flex;align-items:center;gap:6px;font-size:13px;border:1px solid var(--border-strong);
|
||||
background:#fff;border-radius:999px;padding:4px 10px;cursor:pointer;color:var(--ink)}
|
||||
.fchip:hover{border-color:var(--accent)}
|
||||
.fchip .n{color:var(--muted);font-variant-numeric:tabular-nums}
|
||||
|
||||
/* --- Grid: main + aside --- */
|
||||
.grid{display:grid;grid-template-columns:1fr 340px;gap:20px;align-items:start}
|
||||
@media(max-width:860px){.grid{grid-template-columns:1fr}}
|
||||
|
||||
/* --- Day group + bill rows (the Monitor list) --- */
|
||||
.dayhead{display:flex;align-items:baseline;gap:10px;margin:22px 0 8px}
|
||||
.dayhead h2{font-size:16px}
|
||||
.dayhead .count{color:var(--muted);font-size:13px}
|
||||
.rows{border:1px solid var(--border);border-radius:var(--radius);background:var(--paper);
|
||||
overflow:hidden;box-shadow:var(--shadow)}
|
||||
.row{display:grid;grid-template-columns:30px 88px 1fr auto;gap:12px;align-items:start;
|
||||
padding:12px 14px;border-top:1px solid var(--border)}
|
||||
.row:first-child{border-top:0}
|
||||
.chamber{text-align:center;font-size:10px;font-weight:700;padding:2px 0;border-radius:3px;letter-spacing:.5px}
|
||||
.chamber.asm{background:rgba(47,90,167,.12);color:var(--asm)}
|
||||
.chamber.sen{background:rgba(122,59,143,.12);color:var(--sen)}
|
||||
.blnum{font-family:var(--font-mono);font-weight:600;font-size:14px;color:var(--ink)}
|
||||
.blnum a{color:inherit;text-decoration:none;display:block}
|
||||
.blnum small{display:block;color:var(--muted);font-family:var(--font-ui);font-weight:500;font-size:12px}
|
||||
.body .title{font-weight:600;margin:0 0 2px}
|
||||
.meta{color:var(--muted);font-size:13px;display:flex;flex-wrap:wrap;gap:3px 10px;align-items:center}
|
||||
.meta time{font-variant-numeric:tabular-nums}
|
||||
.tags{display:flex;flex-wrap:wrap;gap:5px;margin-top:7px}
|
||||
.tag{font-size:11px;color:var(--ink);background:var(--surface);border:1px solid var(--border);
|
||||
border-radius:999px;padding:2px 8px}
|
||||
.tags .n{color:var(--muted)}
|
||||
.side{display:flex;flex-direction:column;align-items:flex-end;gap:4px;white-space:nowrap}
|
||||
.side .where{font-size:12px;color:var(--muted)}
|
||||
.view{display:inline-block;font-size:13px;font-weight:600;text-decoration:none}
|
||||
@media(max-width:560px){
|
||||
.row{grid-template-columns:30px 1fr;gap:8px}
|
||||
.chamber span{display:none}
|
||||
.side{grid-column:2/3;flex-direction:row;justify-content:flex-start;flex-wrap:wrap;gap:8px;white-space:normal}
|
||||
}
|
||||
|
||||
/* --- Unlock affordance (anon only) — value-stated, non-annoying, not a modal --- */
|
||||
.unlock{border:1px dashed var(--border-strong);border-radius:var(--radius);
|
||||
padding:14px 16px;margin:0 0 16px;background:#fbf7ef}
|
||||
.unlock h3{font-size:15px;margin:0 0 4px}
|
||||
.unlock p{margin:0 0 10px;color:var(--muted);font-size:14px;max-width:62ch}
|
||||
.unlock .cta{background:#fff;border:1px solid var(--accent);color:var(--accent);
|
||||
font-weight:600;border-radius:var(--radius);padding:7px 14px;cursor:pointer;min-height:36px}
|
||||
.unlock .cta:hover{background:var(--accent);color:#fff}
|
||||
|
||||
/* --- Aside cards --- */
|
||||
.card{background:var(--paper);border:1px solid var(--border);border-radius:var(--radius);
|
||||
padding:14px;box-shadow:var(--shadow);margin-bottom:16px}
|
||||
.card h3{font-size:14px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);margin:0 0 10px}
|
||||
.topline{display:flex;justify-content:space-between;align-items:baseline;
|
||||
padding:7px 0;border-top:1px solid var(--border);font-size:14px}
|
||||
.topline:first-of-type{border-top:0}
|
||||
.topline .n{font-variant-numeric:tabular-nums;color:var(--muted)}
|
||||
|
||||
footer{max-width:var(--maxw);margin:0 auto;padding:20px;color:var(--muted);font-size:12px;
|
||||
border-top:1px solid var(--border)}
|
||||
.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(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="top">
|
||||
<div class="wordmark">CA Legislature<small>Upcoming legislation</small></div>
|
||||
<nav class="main" aria-label="Primary">
|
||||
<a href="#main">Dashboard</a><a href="#">Legislators</a><a href="#">Bills</a>
|
||||
</nav>
|
||||
<div class="spacer"></div>
|
||||
<button class="signin" type="button">Sign in / register</button>
|
||||
</header>
|
||||
|
||||
<main id="main" class="shell">
|
||||
|
||||
<!-- Freshness / status band -->
|
||||
<section class="fresh" aria-label="Data freshness">
|
||||
<span><span class="dot g"></span><b style="font-weight:600">Assembly</b> <span class="ok">updated 2026-09-05</span></span>
|
||||
<span class="badge"><span class="pend">Senate</span> — pending today</span>
|
||||
<span class="badge">Session 2025–2026</span>
|
||||
<span class="refresh">Source: leginfo / daily files · <a href="https://leginfo.legislature.ca.gov" target="_blank" rel="noopener">source</a></span>
|
||||
</section>
|
||||
|
||||
<h1 class="page">Upcoming legislation</h1>
|
||||
<p class="lede">A chronological view of what comes up next on the California Assembly and Senate calendars — committee hearings and floor action, with the subject matter of each bill. Set your ZIP to pin your legislators and topics to the top.</p>
|
||||
|
||||
<!-- Unlock affordance: names the value, no dark pattern, no modal-on-arrival -->
|
||||
<section class="unlock" aria-labelledby="unlock-h">
|
||||
<h3 id="unlock-h">Make this dashboard work for you</h3>
|
||||
<p>Enter your ZIP code to find your State Senate and Assembly members, then mark them “watched” and choose the topics you care about. Bills they’re involved in float to the top of your personal view. No account required to browse — sign in only to save it.</p>
|
||||
<button class="cta" type="button">Set my ZIP →</button>
|
||||
</section>
|
||||
|
||||
<!-- Controls bar (personalization-lite for anon) -->
|
||||
<section class="controls" aria-label="Filters">
|
||||
<label>Search
|
||||
<input type="search" placeholder="bill title, author, keyword… ⌘K" aria-label="Search bills">
|
||||
</label>
|
||||
<label>Chamber
|
||||
<select aria-label="Chamber"><option>Both</option><option>Assembly</option><option>Senate</option></select>
|
||||
</label>
|
||||
<label>Date range
|
||||
<select aria-label="Date range"><option>Upcoming</option><option>This week</option><option>This month</option><option>All</option></select>
|
||||
</label>
|
||||
<label>Sort
|
||||
<select aria-label="Sort"><option>Earliest</option><option>Latest</option><option>Relevance</option></select>
|
||||
</label>
|
||||
<div class="chipfilter" style="align-self:flex-end;gap:6px">
|
||||
<button class="fchip" type="button">Waste <span class="n">42</span></button>
|
||||
<button class="fchip" type="button">Education <span class="n">188</span></button>
|
||||
<button class="fchip" type="button">Health <span class="n">214</span></button>
|
||||
<button class="fchip" type="button">Housing <span class="n">97</span></button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="grid">
|
||||
<!-- MAIN: the Monitor list, grouped by day -->
|
||||
<div>
|
||||
<section aria-label="Events on September 7, 2026">
|
||||
<div class="dayhead"><h2>Mon, Sep 7, 2026</h2><span class="count">14 items · 6 committee hearings · 8 floor items</span></div>
|
||||
<div class="rows">
|
||||
|
||||
<article class="row">
|
||||
<div class="chamber asm" title="Assembly"><span class="sr">Assembly</span>A<br>AS</div>
|
||||
<div class="blnum"><a href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260AB28" target="_blank" rel="noopener">AB 28</a><small>A · Schiavo et al.</small></div>
|
||||
<div class="body">
|
||||
<p class="title">Waste: requires statewide recycling standards and reporting</p>
|
||||
<div class="meta"><time datetime="09:30">9:30am</time> · <span>Committee of Resources and Water</span> · <span>S. Capitol, Rm 444</span></div>
|
||||
<div class="tags"><span class="tag">Waste <span class="n">· 42</span></span><span class="tag">Environment</span></div>
|
||||
</div>
|
||||
<div class="side"><span class="where">Rm 444</span><a class="view" href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260AB28" target="_blank" rel="noopener">View →</a></div>
|
||||
</article>
|
||||
|
||||
<article class="row">
|
||||
<div class="chamber sen" title="Senate"><span class="sr">Senate</span>S<br>SE</div>
|
||||
<div class="blnum"><a href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260SB795" target="_blank" rel="noopener">SB 795</a><small>S · Riu</small></div>
|
||||
<div class="body">
|
||||
<p class="title">Health: establishes a community health worker program</p>
|
||||
<div class="meta"><time>10:00am</time> · <span>Committee of Health</span> · <span>S. Capitol, Rm 1340</span></div>
|
||||
<div class="tags"><span class="tag">Health <span class="n">· 214</span></span><span class="tag">Housing</span></div>
|
||||
</div>
|
||||
<div class="side"><span class="where">Rm 1340</span><a class="view" href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260SB795" target="_blank" rel="noopener">View →</a></div>
|
||||
</article>
|
||||
|
||||
<article class="row">
|
||||
<div class="chamber asm" title="Assembly"><span class="sr">Assembly</span>A<br>AS</div>
|
||||
<div class="blnum"><a target="_blank" rel="noopener" href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260AB300">AB 300</a><small>A · Chen</small></div>
|
||||
<div class="body">
|
||||
<p class="title">Education: modernizes K-12 career-technical standards</p>
|
||||
<div class="meta"><time>1:30pm</time> · <span>Committee of Education</span> · <span>S. Capitol, Rm 1080</span></div>
|
||||
<div class="tags"><span class="tag">Education <span class="n">· 188</span></span></div>
|
||||
</div>
|
||||
<div class="side"><span class="where">Rm 1080</span><a class="view" href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260AB300" target="_blank" rel="noopener">View →</a></div>
|
||||
</article>
|
||||
|
||||
<article class="row">
|
||||
<div class="chamber asm" title="Assembly"><span class="sr">Assembly</span>A<br>AS</div>
|
||||
<div class="blnum">—<small>Floor action</small></div>
|
||||
<div class="body">
|
||||
<p class="title">Assembly Floor — item 14, supplement 2</p>
|
||||
<div class="meta"><time>Upon Call of the Chair</time> · <span>A-SAC Assembly Chamber</span></div>
|
||||
<div class="tags"><span class="tag">Fiscal</span></div>
|
||||
</div>
|
||||
<div class="side"><span class="where">Floor</span><a class="view" href="#" >View →</a></div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section aria-label="Events on September 8, 2026">
|
||||
<div class="dayhead"><h2>Tue, Sep 8, 2026</h2><span class="count">31 items</span></div>
|
||||
<div class="rows">
|
||||
<article class="row">
|
||||
<div class="chamber sen" title="Senate"><span class="sr">Senate</span>S<br>SE</div>
|
||||
<div class="blnum"><a target="_blank" rel="noopener" href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260SB42">SB 42</a><small>S · Nguyen</small></div>
|
||||
<div class="body">
|
||||
<p class="title">Housing: expands affordable housing bond authority</p>
|
||||
<div class="meta"><time>9:00am</time> · <span>Committee of Housing</span> · <span>S. Capitol, Rm 1012</span></div>
|
||||
<div class="tags"><span class="tag">Housing <span class="n">· 97</span></span><span class="tag">Taxation</span></div>
|
||||
</div>
|
||||
<div class="side"><span class="where">Rm 1012</span><a class="view" href="#" >View →</a></div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- ASIDE: secondary, opt-in teaser -->
|
||||
<aside aria-label="Top topics this session">
|
||||
<section class="card">
|
||||
<h3>Top subject-matter this session</h3>
|
||||
<div class="topline"><button type="button">Health</button><span class="n">214 bills</span></div>
|
||||
<div class="topline"><button type="button">Education</button><span class="n">188 bills</span></div>
|
||||
<div class="topline"><button type="button">Housing</button><span class="n">97 bills</span></div>
|
||||
<div class="topline"><button type="button">Waste</button><span class="n">42 bills</span></div>
|
||||
<p style="margin:10px 0 0;font-size:12px;color:var(--muted)">Click a topic to filter. <a href="#">Sign in to pin topics to your dashboard →</a></p>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>About this data</h3>
|
||||
<p style="margin:0;font-size:13px;color:var(--muted)">Heard from the California Assembly & Senate daily files via <a href="https://leginfo.legislature.ca.gov" target="_blank" rel="noopener">leginfo</a>. “Upcoming” = future-dated, not-yet-acted events. <a href="#">How is this computed? →</a></p>
|
||||
</section>
|
||||
</aside>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
CA Legislature · Upcoming legislation — a free public service. Senate data pending today. · <a href="#">Accessibility</a> · <a href="#">Privacy</a> · <a href="#">How “upcoming” is computed</a>
|
||||
</footer>
|
||||
|
||||
<span class="wf-note">wireframe · 01 anonymous dashboard</span>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,445 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Legislative Dashboard — Logged-in / personalized (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;
|
||||
--asm:#2f5aa7; --sen:#7a3b8f;
|
||||
--personal:#08345f; --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:1160px;
|
||||
}
|
||||
*{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} a:hover{color:var(--accent-ink)}
|
||||
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}
|
||||
|
||||
.top{position:sticky;top:0;z-index:6;display:flex;align-items:center;gap:16px;background:var(--paper);border-bottom:1px solid var(--border);padding:10px 20px}
|
||||
.wordmark{font-weight:700;font-size:17px;white-space:nowrap}
|
||||
.wordmark small{display:block;font-weight:500;font-size:11px;color:var(--muted);letter-spacing:.4px;text-transform:uppercase}
|
||||
nav.main{display:flex;gap:18px;margin-left:4px}
|
||||
nav.main a{color:var(--ink);text-decoration:none;font-weight:500}
|
||||
nav.main a:hover{text-decoration:underline}
|
||||
.spacer{flex:1}
|
||||
/* User band — the personalization summary, always visible */
|
||||
.userband{display:flex;align-items:center;gap:8px;background:var(--personal-band);border:1px solid #cdddec;
|
||||
border-radius:999px;padding:5px 13px;font-size:13px;white-space:nowrap}
|
||||
.userband .mono{font-family:var(--font-mono);font-weight:600}
|
||||
.userband .sep{color:var(--border-strong)}
|
||||
.usermenu{position:relative}
|
||||
.usermenu > button{background:#fff;border:1px solid var(--border);border-radius:999px;padding:5px 10px;cursor:pointer;font-size:13px;display:flex;gap:8px;align-items:center}
|
||||
.usermenu .menu{position:absolute;right:0;top:110%;background:#fff;border:1px solid var(--border);border-radius:6px;box-shadow:var(--shadow);min-width:190px;display:none;padding:4px}
|
||||
.usermenu:hover .menu,.usermenu:focus-within .menu{display:block}
|
||||
.usermenu .menu a{display:block;padding:8px 10px;text-decoration:none;font-size:14px;border-radius:4px}
|
||||
.usermenu .menu a:hover{background:var(--surface)}
|
||||
.shell{max-width:var(--maxw);margin:0 auto;padding:18px 20px 64px}
|
||||
|
||||
.fresh{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;background:var(--paper);border:1px solid var(--border);border-radius:var(--radius);padding:10px 14px;box-shadow:var(--shadow)}
|
||||
.fresh .badge{font-size:12px;font-weight:600;background:var(--surface);border:1px solid var(--border);border-radius:999px;padding:2px 10px}
|
||||
.fresh .ok{color:var(--success)} .fresh .pend{color:var(--warn)}
|
||||
.fresh .refresh{margin-left:auto;font-size:13px;color:var(--muted)}
|
||||
.live{min-height:20px;font-size:13px;color:var(--muted);margin:8px 2px}
|
||||
h1.page{font-size:22px;margin:10px 0 2px}
|
||||
.controls{display:flex;flex-wrap:wrap;gap:8px 10px;align-items:center;background:var(--paper);border:1px solid var(--border);border-radius:var(--radius);padding:10px 12px;margin:14px 0 18px;box-shadow:var(--shadow)}
|
||||
.controls label{font-size:12px;color:var(--muted);display:flex;flex-direction:column;gap:2px}
|
||||
.controls input[type=search]{min-width:260px;padding:7px 10px;font-size:14px;border:1px solid var(--border-strong);border-radius:var(--radius)}
|
||||
.controls select{padding:7px 8px;font-size:14px;border:1px solid var(--border-strong);border-radius:var(--radius);background:#fff}
|
||||
|
||||
/* Personal band — the floated, promoted region */
|
||||
.band{border:1px solid #cdddec;background:var(--personal-band);border-radius:var(--radius);padding:14px 16px;margin-bottom:18px}
|
||||
.band .bandhead{display:flex;align-items:center;gap:10px;margin-bottom:4px}
|
||||
.band .bandhead h2{font-size:16px;color:var(--personal)}
|
||||
.band .count{font-size:13px;color:var(--muted)}
|
||||
.band .allpill{margin-left:auto;font-size:13px;font-weight:600;cursor:pointer;background:#fff;border:1px solid #cdddec;color:var(--accent);border-radius:999px;padding:4px 12px}
|
||||
/* Meaning-cued indicator: NOT decoration — it encodes WHY this row is here. */
|
||||
.relevant{border-left:3px solid var(--accent);padding-left:11px}
|
||||
.relevant.leg{border-left-color:var(--success)}
|
||||
.legmark{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:600;color:var(--success);
|
||||
background:rgba(30,126,52,.1);border-radius:3px;padding:1px 7px}
|
||||
.tagmark{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:600;color:var(--accent);
|
||||
background:rgba(11,83,148,.09);border-radius:3px;padding:1px 7px}
|
||||
|
||||
/* Why popover */
|
||||
.whywrap{position:relative;display:inline-block}
|
||||
.whybtn{font-size:12px;color:var(--muted);background:none;border:none;cursor:pointer;padding:2px 0;text-decoration:underline;text-underline-offset:2px}
|
||||
.why-pop{position:absolute;left:0;top:118%;z-index:8;width:290px;background:#fff;border:1px solid var(--border);
|
||||
border-radius:6px;box-shadow:var(--shadow);padding:12px;display:none;font-size:13px;text-align:left}
|
||||
.why-pop[open],.whywrap:hover .why-pop,.whywrap:focus-within .why-pop{display:block}
|
||||
.why-pop h4{margin:0 0 6px;font-size:13px}
|
||||
.why-pop ul{margin:6px 0 0;padding-left:16px}
|
||||
.why-pop code{font-family:var(--font-mono);font-size:12px;background:var(--surface);padding:1px 5px;border-radius:3px}
|
||||
|
||||
.grid{display:grid;grid-template-columns:1fr 340px;gap:20px;align-items:start}
|
||||
@media(max-width:860px){.grid{grid-template-columns:1fr}}
|
||||
.dayhead{display:flex;align-items:baseline;gap:10px;margin:22px 0 8px}
|
||||
.dayhead h3{font-size:16px}
|
||||
.dayhead .count{color:var(--muted);font-size:13px}
|
||||
.rows{border:1px solid var(--border);border-radius:var(--radius);background:var(--paper);overflow:hidden;box-shadow:var(--shadow)}
|
||||
.row{display:grid;grid-template-columns:30px 88px 1fr auto;gap:12px;align-items:start;padding:12px 14px;border-top:1px solid var(--border)}
|
||||
.row:first-child{border-top:0}
|
||||
.chamber{text-align:center;font-size:10px;font-weight:700;padding:2px 0;border-radius:3px;letter-spacing:.5px;line-height:1.05}
|
||||
.chamber.asm{background:rgba(47,90,167,.12);color:var(--asm)} .chamber.sen{background:rgba(122,59,143,.12);color:var(--sen)}
|
||||
.blnum{font-family:var(--font-mono);font-weight:600;font-size:14px}
|
||||
.blnum a{color:inherit;text-decoration:none;display:block}
|
||||
.blnum small{display:block;color:var(--muted);font-family:var(--font-ui);font-weight:500;font-size:12px}
|
||||
.title{font-weight:600;margin:0 0 2px}
|
||||
.meta{color:var(--muted);font-size:13px;display:flex;flex-wrap:wrap;gap:3px 10px;align-items:center}
|
||||
.meta time{font-variant-numeric:tabular-nums}
|
||||
.tags{display:flex;flex-wrap:wrap;gap:5px;margin-top:7px}
|
||||
.tag{font-size:11px;background:var(--surface);border:1px solid var(--border);border-radius:999px;padding:2px 8px}
|
||||
.tags .n{color:var(--muted)}
|
||||
.tag.on{background:var(--personal-band);border-color:#cdddec}
|
||||
.reason{margin-top:6px;font-size:12px}
|
||||
.side{display:flex;flex-direction:column;align-items:flex-end;gap:4px;white-space:nowrap}
|
||||
.side .where{font-size:12px;color:var(--muted)}
|
||||
.view{display:inline-block;font-size:13px;font-weight:600;text-decoration:none}
|
||||
@media(max-width:560px){.row{grid-template-columns:30px 1fr;gap:8px}.chamber span{display:none}.side{grid-column:2/3;flex-direction:row;justify-content:flex-start;flex-wrap:wrap;white-space:normal}}
|
||||
|
||||
.card{background:var(--paper);border:1px solid var(--border);border-radius:var(--radius);padding:14px;box-shadow:var(--shadow);margin-bottom:16px}
|
||||
.card h3{font-size:14px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);margin:0 0 4px}
|
||||
.card .sub{font-size:12px;color:var(--muted);margin:0 0 10px}
|
||||
/* Watch toggle */
|
||||
.watch{display:flex;align-items:center;gap:10px;padding:8px 0;border-top:1px solid var(--border)}
|
||||
.watch:first-child{border-top:0}
|
||||
.watch .who{flex:1}
|
||||
.watch .who b{font-weight:600}.watch .who small{display:block;color:var(--muted);font-size:12px}
|
||||
.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}
|
||||
.watch .stat{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.4px}
|
||||
.stat.on{color:var(--success)}.stat.off{color:var(--muted)}
|
||||
/* Topic opt-in chips */
|
||||
.opt{display:flex;flex-wrap:wrap;gap:7px}
|
||||
.optchip{display:inline-flex;align-items:center;gap:7px;font-size:13px;border:1px solid var(--border-strong);
|
||||
background:#fff;border-radius:999px;padding:5px 11px;cursor:pointer;color:var(--ink)}
|
||||
.optchip:hover{border-color:var(--accent)}
|
||||
.optchip.on{background:var(--personal-band);border-color:var(--accent);font-weight:600}
|
||||
.optchip .n{color:var(--muted);font-variant-numeric:tabular-nums}
|
||||
.optchip .box{width:14px;height:14px;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}
|
||||
|
||||
footer{max-width:var(--maxw);margin:0 auto;padding:20px;color:var(--muted);font-size:12px;border-top:1px solid var(--border)}
|
||||
|
||||
/* ZIP setup empty-state (toggled on via #state-setup) — shown when a user has no prefs */
|
||||
#setup{border:1px dashed var(--border-strong);border-radius:var(--radius);background:#fbf7ef;padding:16px;margin:14px 0}
|
||||
.setup-row{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap}
|
||||
.setup-row label{display:flex;flex-direction:column;font-size:12px;color:var(--muted);gap:3px}
|
||||
.setup-row input{padding:8px 10px;border:1px solid var(--border-strong);border-radius:var(--radius);font-size:14px}
|
||||
.setup-row input.zip{max-width:130px;font-family:var(--font-mono)}
|
||||
#btn-find{background:var(--accent);color:#fff;border:none;border-radius:var(--radius);padding:8px 14px;min-height:36px;font-weight:600;cursor:pointer}
|
||||
#btn-find:hover{background:var(--accent-ink)}
|
||||
.candidates{margin-top:12px;border-top:1px solid #eadfca;padding-top:10px;font-size:13px;color:var(--muted)}
|
||||
|
||||
.modebar{display:flex;gap:8px;align-items:center;margin:0 0 12px;background:var(--ink);color:#fff;border-radius:6px;padding:8px 12px}
|
||||
.modebar b{font-family:var(--font-mono);font-size:12px}
|
||||
.modebar button{background:transparent;color:#fff;border:1px solid #5a6270;border-radius:4px;padding:4px 10px;font-size:12px;cursor:pointer}
|
||||
.modebar button[aria-pressed=true]{background:#fff;color:var(--ink);font-weight:600}
|
||||
.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(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
|
||||
</style>
|
||||
</head>
|
||||
<body data-state="personal">
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="top">
|
||||
<div class="wordmark">CA Legislature<small>Upcoming legislation</small></div>
|
||||
<nav class="main" aria-label="Primary"><a href="#main">Dashboard</a><a href="#">Legislators</a><a href="#">Bills</a></nav>
|
||||
<div class="spacer"></div>
|
||||
<!-- User band reflects the personalization summary at a glance -->
|
||||
<div class="userband" id="ub-personal">
|
||||
<span class="mono">ZIP 90210</span><span class="sep">·</span>Districts <b>A-14 S-08</b>
|
||||
<span class="sep">·</span><b id="ub-watch">2</b> watching <span class="sep">·</span><b id="ub-topics">3</b> topics
|
||||
</div>
|
||||
<div class="usermenu">
|
||||
<button type="button" aria-haspopup="true">A. R. ▾</button>
|
||||
<div class="menu" role="menu">
|
||||
<a role="menuitem" href="#prefs">Preferences</a>
|
||||
<a role="menuitem" href="#prefs">Watched & topics</a>
|
||||
<a role="menuitem" href="#">Signed out</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Demo control only: not part of the product. Toggles the two personal states. -->
|
||||
<div class="modebar" role="group" aria-label="Demo state selector (wireframe only)">
|
||||
Wireframe demo — show state:
|
||||
<button type="button" aria-pressed="true" data-set="personal">Personalized (configured)</button>
|
||||
<button type="button" aria-pressed="false" data-set="setup">ZIP setup (empty)</button>
|
||||
<button type="button" aria-pressed="false" data-set="anon">No login (anon)</button>
|
||||
</div>
|
||||
|
||||
<main id="main" class="shell">
|
||||
<section class="fresh" aria-label="Data freshness">
|
||||
<span><b style="font-weight:600">Assembly</b> <span class="ok">updated 2026-09-05</span></span>
|
||||
<span class="badge"><span class="pend">Senate</span> — pending today</span>
|
||||
<span class="badge">Session 2025–2026</span>
|
||||
<span class="refresh">Source: leginfo / daily files · <a href="https://leginfo.legislature.ca.gov" target="_blank" rel="noopener">source</a></span>
|
||||
</section>
|
||||
|
||||
<h1 class="page">Your dashboard</h1>
|
||||
<p class="live" role="status" aria-live="polite"></p>
|
||||
|
||||
<!-- =========== ZIP / ADDRESS setup empty-state (state=setup) =========== -->
|
||||
<section id="setup" hidden aria-labelledby="setup-h">
|
||||
<h2 id="setup-h"><span style="font-size:17px;font-weight:600">Pin your view</span></h2>
|
||||
<p style="margin:6px 0 12px;color:#6a5a3a;max-width:62ch">Enter your ZIP code and we’ll find your State Senate and Assembly representatives, then surface their bills and the topics you care about at the top. Prefer exact results? You can enter a full address instead — a ZIP alone can’t always pin a district.</p>
|
||||
<form class="setup-row" onsubmit="return false">
|
||||
<label>ZIP code
|
||||
<input class="zip" inputmode="numeric" maxlength="5" placeholder="90210" aria-label="ZIP code">
|
||||
</label>
|
||||
<button id="btn-find" type="submit">Find my legislators <span style="opacity:.75;font-weight:400;font-size:11px">(demo: cycles the 4 outcome panels)</span></button>
|
||||
<span style="flex:1"></span>
|
||||
<a href="#" style="align-self:flex-end">Use a full address instead →</a>
|
||||
</form>
|
||||
<div class="candidates" role="note">
|
||||
<p style="margin:0 0 8px;font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px">Resolve outcome on ZIP 90210 — <b style="font-weight:600;color:var(--ink)">single district ✓</b></p>
|
||||
<b>We found your district → <span style="color:var(--accent)">District 14 (Assembly) · District 08 (Senate)</span></b>
|
||||
<p style="margin:6px 0 8px">Confirm which representatives to watch and what topics to follow. Nothing is saved until you choose.</p>
|
||||
<div class="watch"><div class="who"><b>M. Schiavo</b> <small>Assembly District 14 · D</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="watch"><div class="who"><b>R. Riu</b> <small>Senate District 08 · R</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>
|
||||
<p style="margin:8px 0 4px;color:var(--muted)">Suggested topics for these representatives:</p>
|
||||
<div class="opt">
|
||||
<button class="optchip on" type="button"><span class="box" aria-hidden="true">✓</span>Waste <span class="n">· 42</span></button>
|
||||
<button class="optchip on" type="button"><span class="box" aria-hidden="true">✓</span>Water <span class="n">· 63</span></button>
|
||||
<button class="optchip" type="button"><span class="box"></span>Housing <span class="n">· 97</span></button>
|
||||
<button class="optchip" type="button"><span class="box"></span>Transportation <span class="n">· 51</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Other resolve outcomes (§6.4 of DESIGN_DASHBOARD) — shown as alternative panels, hidden by default -->
|
||||
<div class="candidates" role="note" hidden data-outcome="ambiguous">
|
||||
<p style="margin:0 0 8px;font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px">Outcome — <b style="font-weight:600;color:var(--warn)">ambiguous ZIP</b></p>
|
||||
<p style="margin:0 0 8px">ZIP <code style="font-family:var(--font-mono)">95602</code> spans more than one district — which one is yours?</p>
|
||||
<div class="watch"><div class="who"><b>District 5 (Assembly)</b> <small>69% of residents in this ZIP</small></div><a href="#" class="view">Use this →</a></div>
|
||||
<div class="watch"><div class="who"><b>District 1 (Assembly)</b> <small>31% of residents in this ZIP</small></div><a href="#" class="view">Use this →</a></div>
|
||||
</div>
|
||||
<div class="candidates" role="note" hidden data-outcome="zero">
|
||||
<p style="margin:0 0 8px;font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px">Outcome — <b style="font-weight:600;color:var(--warn)">no match</b></p>
|
||||
<p style="margin:0 0 8px">We couldn’t match ZIP <code style="font-family:var(--font-mono)">89001</code> to a California district.</p>
|
||||
<a href="#" class="view">Pick a district manually →</a> · <a href="#" class="view">Try a full address →</a>
|
||||
</div>
|
||||
<div class="candidates" role="note" hidden data-outcome="out-of-state">
|
||||
<p style="margin:0 0 8px;font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px">Outcome — <b style="font-weight:600;color:var(--danger)">out of state</b></p>
|
||||
<p style="margin:0">This ZIP isn’t in California. This tool covers only the CA state legislature.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- =========== Personalized view (state=personal / anon) =========== -->
|
||||
<div id="personal-view">
|
||||
<!-- Controls: same as anon; personal ranking is on by default for logged-in -->
|
||||
<section class="controls" aria-label="Filters">
|
||||
<label>Search
|
||||
<input type="search" placeholder="bill title, author, keyword… ⌘K" aria-label="Search bills">
|
||||
</label>
|
||||
<label>Chamber<select><option>Both</option><option>Assembly</option><option>Senate</option></select></label>
|
||||
<label>Date range<select><option>Upcoming</option><option>This week</option><option>This month</option><option>All</option></select></label>
|
||||
<label>Sort<select id="sort"><option>Earliest</option><option>Latest</option><option>Relevance</option></select></label>
|
||||
</section>
|
||||
|
||||
<!-- PERSONAL BAND: floated, top N, meaning-cued, with reveal-why -->
|
||||
<section class="band" id="band" aria-label="Relevant to you">
|
||||
<div class="bandhead">
|
||||
<h2>Relevant to you</h2>
|
||||
<span class="count" id="band-count">6 bills</span>
|
||||
<button type="button" class="allpill" id="showall">Show all 6</button>
|
||||
</div>
|
||||
<!-- A floated-by-legislator bill (success-cued left bar) -->
|
||||
<article class="row relevant leg">
|
||||
<div class="chamber asm" title="Assembly"><span class="sr">Assembly</span>A<br>AS</div>
|
||||
<div class="blnum"><a target="_blank" rel="noopener" href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260AB28">AB 28</a><small>A · Schiavo</small></div>
|
||||
<div class="body">
|
||||
<p class="title">Waste: requires statewide recycling standards and reporting</p>
|
||||
<div class="meta"><time datetime="09:30">9:30am</time> · <span>Committee of Resources and Water</span> · <span>S. Capitol, Rm 444</span></div>
|
||||
<div class="tags"><span class="tag on">Waste <span class="n">· 42</span></span><span class="tag">Environment</span></div>
|
||||
<div class="reason">
|
||||
<span class="legmark">● Your legislator</span>
|
||||
<span class="tagmark">● Topic: Waste</span>
|
||||
<span class="whywrap">
|
||||
<button class="whybtn" type="button">Why is this here? ▸</button>
|
||||
<span class="why-pop" role="dialog" aria-label="Why this bill is relevant">
|
||||
<h4>Why this surfaced</h4>
|
||||
<ul>
|
||||
<li>Your watched legislator: <code>M. Schiavo (A-14)</code> — author of this bill.</li>
|
||||
<li>Topic match: <code>Waste</code> is one of your opted-in topics.</li>
|
||||
</ul>
|
||||
<p style="margin:8px 0 0;color:var(--muted)">Either match alone floats a bill; both raises its position.</p>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="side"><span class="where">Rm 444</span><a class="view" target="_blank" rel="noopener" href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260AB28">View →</a></div>
|
||||
</article>
|
||||
|
||||
<!-- A floated-by-topic-only bill (accent-cued left bar = tag match, no legislator match) -->
|
||||
<article class="row relevant">
|
||||
<div class="chamber sen" title="Senate"><span class="sr">Senate</span>S<br>SE</div>
|
||||
<div class="blnum"><a target="_blank" rel="noopener" href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260SB795">SB 795</a><small>S · Riu</small></div>
|
||||
<div class="body">
|
||||
<p class="title">Health: establishes a community health worker program</p>
|
||||
<div class="meta"><time>10:00am</time> · <span>Committee of Health</span> · <span>S. Capitol, Rm 1340</span></div>
|
||||
<div class="tags"><span class="tag on">Health <span class="n">· 214</span></span><span class="tag">Housing</span></div>
|
||||
<div class="reason">
|
||||
<span class="tagmark">● Topic: Health</span>
|
||||
<span class="whywrap">
|
||||
<button class="whybtn" type="button">Why is this here? ▸</button>
|
||||
<span class="why-pop" role="dialog" aria-label="Why this bill is relevant">
|
||||
<h4>Why this surfaced</h4>
|
||||
<ul><li>Topic match: <code>Health</code> is one of your opted-in topics.</li></ul>
|
||||
<p style="margin:8px 0 0;color:var(--muted)">No legislator match — floated by topic only.</p>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="side"><span class="where">Rm 1340</span><a class="view" target="_blank" rel="noopener" href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260SB795">View →</a></div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<div class="grid">
|
||||
<!-- MAIN: full queue, grouped by day; floated bills keep a "Relevant" marker -->
|
||||
<div>
|
||||
<section aria-label="Events on September 7, 2026">
|
||||
<div class="dayhead"><h3>Mon, Sep 7, 2026</h3><span class="count">14 items</span></div>
|
||||
<div class="rows">
|
||||
<article class="row">
|
||||
<div class="chamber asm" title="Assembly"><span class="sr">Assembly</span>A<br>AS</div>
|
||||
<div class="blnum"><a target="_blank" rel="noopener" href="https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260AB28">AB 28</a><small>A · Schiavo</small></div>
|
||||
<div class="body">
|
||||
<p class="title">Waste: requires statewide recycling standards</p>
|
||||
<div class="meta"><time datetime="09:30">9:30am</time> · <span>Committee of Resources and Water</span> · <span>Rm 444</span></div>
|
||||
<div class="reason"><span class="legmark">● Your legislator</span>
|
||||
<span class="whywrap"><button class="whybtn" type="button">Why?</button>
|
||||
<span class="why-pop"><ul><li>Author <code>M. Schiavo</code> is watched</li></ul></span></span></div>
|
||||
<div class="tags"><span class="tag on">Waste</span></div>
|
||||
</div>
|
||||
<div class="side"><span class="where">Rm 444</span><a class="view" href="#" target="_blank">View →</a></div>
|
||||
</article>
|
||||
<article class="row">
|
||||
<div class="chamber asm" title="Assembly"><span class="sr">Assembly</span>A<br>AS</div>
|
||||
<div class="blnum"><a target="_blank" rel="noopener" href="#">AB 300</a><small>A · Chen</small></div>
|
||||
<div class="body">
|
||||
<p class="title">Education: modernizes K-12 career-technical standards</p>
|
||||
<div class="meta"><time>1:30pm</time> · <span>Committee of Education</span> · <span>Rm 1080</span></div>
|
||||
<div class="tags"><span class="tag">Education <span class="n">· 188</span></span></div>
|
||||
</div>
|
||||
<div class="side"><span class="where">Rm 1080</span><a class="view" href="#" target="_blank">View →</a></div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- ASIDE: manage personalization -->
|
||||
<aside id="prefs" aria-label="Your preferences">
|
||||
<section class="card">
|
||||
<h3>Watchlist</h3><p class="sub">Legislators whose authorship or committee activity surfaces their bills.</p>
|
||||
<div class="watch">
|
||||
<div class="who"><b>M. Schiavo</b><small>Assembly D-14 · D · Resources & Water</small></div>
|
||||
<label class="toggle"><input type="checkbox" checked data-leg aria-label="Watch M. Schiavo"><span class="knob"></span></label>
|
||||
<span class="stat on">Watching</span>
|
||||
</div>
|
||||
<div class="watch">
|
||||
<div class="who"><b>R. Riu</b><small>Senate D-08 · R · Health</small></div>
|
||||
<label class="toggle"><input type="checkbox" data-leg aria-label="Watch R. Riu"><span class="knob"></span></label>
|
||||
<span class="stat off">Not watched</span>
|
||||
</div>
|
||||
<a href="#" style="display:inline-block;margin-top:8px;font-size:13px">+ Find another legislator</a>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>Topics you follow</h3><p class="sub">Subject-matter (from bill analysis). Bills in these topics float up.</p>
|
||||
<div class="opt" role="group" aria-label="Topics you follow">
|
||||
<button class="optchip on" type="button" data-topic><span class="box" aria-hidden="true">✓</span>Waste <span class="n">· 42</span></button>
|
||||
<button class="optchip on" type="button" data-topic><span class="box" aria-hidden="true">✓</span>Water <span class="n">· 63</span></button>
|
||||
<button class="optchip on" type="button" data-topic><span class="box" aria-hidden="true">✓</span>Health <span class="n">· 214</span></button>
|
||||
<button class="optchip" type="button" data-topic><span class="box"></span>Housing <span class="n">· 97</span></button>
|
||||
<button class="optchip" type="button" data-topic><span class="box"></span>Education <span class="n">· 188</span></button>
|
||||
</div>
|
||||
<a href="#" style="display:inline-block;margin-top:8px;font-size:12px">See all 206 topics →</a>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>Zone</h3>
|
||||
<p class="sub" style="margin:0">ZIP <b>90210</b> → Assembly D-14 · Senate D-08. A ZIP can span more than one district — <a href="#">verify by address →</a></p>
|
||||
</section>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
CA Legislature · Your dashboard — a free public service. Senate data pending today. · <a href="#">Accessibility</a> · <a href="#">Privacy</a> · <a href="#">How “upcoming” is computed</a>
|
||||
</footer>
|
||||
|
||||
<span class="wf-note">wireframe · 02 logged-in dashboard</span>
|
||||
|
||||
<script>
|
||||
// --- Wireframe-only demo interactivity: proves the states & the "float on change" behavior.
|
||||
const body=document.body, personal=document.getElementById('personal-view');
|
||||
const setup=document.getElementById('setup');
|
||||
const live=document.querySelector('.live');
|
||||
const modeBtns=[...document.querySelectorAll('.modebar button')];
|
||||
function setState(s){
|
||||
body.dataset.state=s;
|
||||
modeBtns.forEach(b=>b.setAttribute('aria-pressed', b.dataset.set===s));
|
||||
const isSetup=s==='setup';
|
||||
setup.hidden=!isSetup;
|
||||
personal.hidden=isSetup;
|
||||
document.getElementById('ub-personal').style.display = s==='anon' ? 'none':'';
|
||||
document.querySelector('.usermenu').style.display = s==='anon' ? 'none':'';
|
||||
document.querySelector('h1.page').textContent = s==='anon' ? 'Upcoming legislation' : 'Your dashboard';
|
||||
live.textContent = s==='anon' ? 'Anonymous — personal view is off. Sign in for a personalized dashboard.'
|
||||
: s==='setup' ? 'Set your ZIP to find your legislators and topics.'
|
||||
: '6 bills relevant to you are showing above the full list.';
|
||||
}
|
||||
modeBtns.forEach(b=>b.addEventListener('click',()=>setState(b.dataset.set)));
|
||||
|
||||
// Opt-in / watch toggles: optimistic + announce + "re-rank" feedback (the float model in miniature)
|
||||
function refresh(){
|
||||
const w=[...document.querySelectorAll('[data-leg]').filter(i=>i.checked)].length;
|
||||
const t=document.querySelectorAll('[data-topic].on').length;
|
||||
document.getElementById('ub-watch').textContent=w;
|
||||
document.getElementById('ub-topics').textContent=t;
|
||||
document.getElementById('band-count').textContent=(3+t)+' bills';
|
||||
}
|
||||
document.querySelectorAll('[data-leg]').forEach(i=>i.addEventListener('change',e=>{
|
||||
e.currentTarget.closest('.watch').querySelector('.stat').textContent = e.currentTarget.checked?'Watching':'Not watched';
|
||||
e.currentTarget.closest('.watch').querySelector('.stat').className='stat '+(e.currentTarget.checked?'on':'off');
|
||||
refresh(); live.textContent='Re-ranked — watchlist change applied.';
|
||||
}));
|
||||
document.querySelectorAll('[data-topic].on, [data-topic]:not(.on)').forEach(c=>c.addEventListener('click',()=>{
|
||||
const on=c.classList.toggle('on');
|
||||
c.querySelector('.box').textContent=on?'✓':'';
|
||||
c.querySelector('.box').setAttribute('aria-hidden', on?'true':'false');
|
||||
refresh(); live.textContent='Re-ranked — topic change applied.';
|
||||
}));
|
||||
// Wireframe-only: cycle the 4 ZIP resolve outcomes on the ZIP form.
|
||||
(() => {
|
||||
const btn = document.getElementById('btn-find');
|
||||
if (!btn) return;
|
||||
const panels = [document.querySelector('.candidates:not([data-outcome])'),
|
||||
...document.querySelectorAll('[data-outcome]')];
|
||||
let i = 0;
|
||||
btn.addEventListener('click', () => {
|
||||
panels.forEach((p, j) => { if (p) p.hidden = j !== i; });
|
||||
const cur = panels[i];
|
||||
if (cur) cur.scrollIntoView({behavior:'smooth', block:'nearest'});
|
||||
i = (i + 1) % panels.length;
|
||||
});
|
||||
})();
|
||||
refresh(); setState('personal');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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” & “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 & 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 & 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>
|
||||
Reference in new issue
Block a user