Files
2026-09-06 10:18:26 -07:00

446 lines
31 KiB
HTML
Raw Permalink 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>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&nbsp;90210</span><span class="sep">·</span>Districts <b>A-14 &nbsp;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 &amp; 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 &amp; 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>