/* Lone Star Voter Guide — presentation only.

   Mobile first: every base rule targets a phone held in one hand, and
   min-width queries only ever add width, never rearrange meaning.

   The page has three densities, in this order, and the spacing scale exists
   to keep them apart: a heavy red hero, a run of quiet explanatory panels,
   and then the ballot itself — a long list that has to stay scannable for
   several hundred lines. */

:root {
  --bg: #f4f5f8;
  --surface: #ffffff;
  --surface-sunk: #eef0f5;
  --text: #141a2e;
  --muted: #545b70;
  --faint: #6f7588;
  --line: #dde0e8;
  --line-strong: #c3c8d4;
  --hairline: #eceef3;

  --accent: #002868;          /* Texas flag blue; 13:1 on --bg */
  --accent-dark: #001a45;
  --accent-deep: #00133a;
  --accent-soft: #eaeef6;
  --accent-line: #c7d0e2;

  /* The flag itself. Blue is also --accent; red is kept to the header stripe,
     the election-day tile, and a few calls to action, never candidate rows. */
  --flag-blue: #002868;
  --flag-red: #bf0a30;
  --flag-red-dark: #940826;

  --warn-bg: #fdf6e6;
  --warn-line: #d6a94a;
  --warn-accent: #9a6b0e;
  --warn-text: #4a3a12;

  /* Party colors carry no meaning on their own — every chip also states the
     party in words and stamps a distinctly shaped glyph. Color is the third
     signal, never the only one. */
  --rep: #8a1518;
  --rep-bg: #f9ecea;
  --dem: #164a80;
  --dem-bg: #eaf1f8;
  --lib: #7a5310;
  --lib-bg: #fbf2df;
  --grn: #1b5b37;
  --grn-bg: #e8f3ec;

  --serif: "Zilla Slab", Rockwell, "Roboto Slab", Georgia, serif;
  --sans: "Public Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;

  --r-sm: 6px;
  --r: 10px;
  --r-lg: 14px;

  /* Cards are lifted off the page instead of boxed in. Two layers: a tight
     contact shadow so edges read at all, and a wide soft one for depth. */
  --shadow: 0 1px 2px rgba(40, 26, 22, 0.05), 0 8px 20px -12px rgba(40, 26, 22, 0.22);
  --shadow-lift: 0 2px 4px rgba(40, 26, 22, 0.06), 0 14px 30px -14px rgba(40, 26, 22, 0.28);

  /* One spacing rhythm for the whole page. Panels sit a --gap apart;
     jurisdiction groups get --gap-group, which is deliberately much larger —
     that gap is the only thing separating one office's races from the next. */
  --gap: 28px;
  --gap-group: 56px;
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  color-scheme: light;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--accent);
}

p { margin: 0 0 12px; }
p:last-child { margin-bottom: 0; }

.wrap {
  max-width: 900px;
  margin: 0 auto;
  padding: 0 18px;
}

a {
  color: var(--accent);
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}

a:hover { color: var(--accent-dark); }

:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Shared eyebrow: small, tracked, uppercase. Used above every major heading
   so each section announces its kind before its name. */
.eyebrow {
  margin: 0 0 8px;
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--faint);
}

/* ==========================================================================
   Header — laid out as the Texas flag. A blue hoist carries the lone star,
   the name, and the menu; beside it (below it on a phone) a white stripe
   holds the page title and a red stripe holds the one thing to do here:
   the address lookup. Pages without a lookup keep a thin red stripe so the
   flag still reads.
   ========================================================================== */

.site-header {
  display: grid;
  grid-template-columns: 1fr;
  background: var(--flag-blue);
  color: #fff;
}

.hoist {
  display: flex;
  flex-direction: column;
  padding: 14px 18px;
  background: var(--flag-blue);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  color: #fff;
  text-decoration: none;
}

.brand:hover { color: #fff; }

.brand-star {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
}

.brand-name {
  font-family: var(--serif);
  font-weight: 700;
  font-size: 1.15rem;
  line-height: 1.1;
}

.brand-name small {
  display: block;
  margin-top: 3px;
  font-family: var(--sans);
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.75);
}

/* The big star only appears once the hoist becomes its own column. */
.hoist-star { display: none; }

.stripes { display: grid; }

.stripe-white {
  padding: 28px 18px 26px;
  background: #fff;
  color: var(--text);
}

.stripe-inner { max-width: 660px; }

.stripe-white .eyebrow {
  margin-bottom: 10px;
  color: var(--flag-red);
}

.site-header h1 {
  margin: 0 0 10px;
  font-size: clamp(2.2rem, 9vw, 3.2rem);
  line-height: 1.02;
  letter-spacing: -0.01em;
  color: var(--flag-blue);
  text-wrap: balance;
}

.mission {
  margin: 0;
  max-width: 46ch;
  font-size: 1.02rem;
  line-height: 1.5;
  color: var(--muted);
}

.stripe-red {
  background: var(--flag-red);
  color: #fff;
}

.stripe-thin { height: 12px; }

/* ---------- The lookup, living in the red stripe ----------
   .site-header .lookup outranks the plain .panel/.lookup card rules further
   down, including their wider-screen padding. */

.site-header .lookup {
  margin: 0;
  padding: 22px 18px 26px;
  background: var(--flag-red);
  border-radius: 0;
  box-shadow: none;
}

.site-header .lookup h2 {
  margin: 0 0 12px;
  font-size: 1.4rem;
  color: #fff;
}

.site-header .lookup-form label { color: rgba(255, 255, 255, 0.88); }

.site-header .lookup-row input {
  background: #fff;
  border: 2px solid #fff;
}

.site-header .lookup-row input:focus-visible {
  outline: 3px solid var(--flag-blue);
  outline-offset: 0;
}

.site-header .lookup-row button {
  font-weight: 700;
  background: var(--flag-blue);
}

.site-header .lookup-row button:hover:not(:disabled) { background: var(--accent-dark); }

.site-header .lookup-row button:focus-visible,
.site-header .brand:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 2px;
}

.site-header .lookup-privacy {
  background: rgba(0, 0, 0, 0.16);
  color: rgba(255, 255, 255, 0.92);
}

.site-header .lookup-privacy strong { color: #fff; }
.site-header .lookup-privacy code { background: rgba(255, 255, 255, 0.16); }

.coverage {
  margin: 14px 0 0;
  padding: 10px 14px;
  max-width: 62ch;
  border-left: 4px solid rgba(255, 255, 255, 0.6);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: rgba(0, 0, 0, 0.16);
  font-size: 0.9rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.92);
}

.coverage strong { color: #fff; }

/* Status and the matched-precinct panel keep their own light backgrounds, so
   they take dark text back from the header. */
.site-header .lookup-status { color: var(--muted); }
.site-header .lookup-status-warn { color: var(--warn-text); }
.site-header .lookup-status-error { color: var(--accent-dark); }
.site-header .lookup-result { color: var(--text); }

@media (min-width: 620px) {
  .stripe-white { padding: 36px 28px 30px; }
  .site-header .lookup { padding: 26px 28px 30px; }
}

@media (min-width: 900px) {
  .site-header { grid-template-columns: minmax(300px, 1fr) 2fr; }

  .hoist { padding: 24px 28px 30px; }

  .hoist-star {
    display: block;
    width: 58%;
    max-width: 180px;
    margin: auto;
    padding-block: 24px;
  }

  .stripe-white { padding: 44px 44px 36px; }
  .site-header .lookup { padding: 30px 44px 34px; }
  .stripe-thin { height: 18px; padding: 0; }
}


/* ---------- Masthead + navigation ----------
   A hamburger at every width: the links stay collapsed behind the button on
   desktop as on a phone. The button is the single source of state
   (aria-expanded); .is-open on the nav is only ever derived from it. */

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.masthead .eyebrow { margin-bottom: 0; }

.nav-toggle {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  padding: 9px 14px;
  font: inherit;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: #fff;
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.42);
  border-radius: var(--r-sm);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.nav-toggle:hover { background: rgba(0, 0, 0, 0.3); }

/* The red band swallows a red focus ring, so the hero's controls take a white
   one instead. */
.nav-toggle:focus-visible,
.site-nav a:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 2px;
}

/* Three bars from one element: the middle is the span, the outer two its
   pseudo-elements. Open, the middle drops out and the others cross. */
.nav-bars,
.nav-bars::before,
.nav-bars::after {
  display: block;
  width: 18px;
  height: 2px;
  background: #fff;
  border-radius: 2px;
  transition: transform 0.16s ease, top 0.16s ease, background-color 0.16s ease;
}

.nav-bars {
  position: relative;
}

.nav-bars::before,
.nav-bars::after {
  content: "";
  position: absolute;
  left: 0;
}

.nav-bars::before { top: -6px; }
.nav-bars::after { top: 6px; }

.nav-toggle[aria-expanded="true"] .nav-bars { background: transparent; }

.nav-toggle[aria-expanded="true"] .nav-bars::before {
  top: 0;
  transform: rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-bars::after {
  top: 0;
  transform: rotate(-45deg);
}

.site-nav { display: none; }
.site-nav.is-open { display: block; }

.site-nav ul {
  list-style: none;
  margin: 16px 0 2px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: rgba(0, 0, 0, 0.18);
  border-radius: var(--r-sm);
}

.site-nav a {
  display: block;
  min-height: 44px;
  padding: 11px 13px;
  border-radius: var(--r-sm);
  color: #fff;
  font-weight: 600;
  font-size: 0.98rem;
  text-decoration: none;
}

.site-nav a:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.14);
}

/* The current page is marked by weight and a held highlight, not by colour
   alone. */
.site-nav a[aria-current="page"] {
  background: rgba(255, 255, 255, 0.18);
  font-weight: 700;
}

/* ==========================================================================
   Page body rhythm
   ========================================================================== */

.page { padding: var(--gap) 0 0; }

.panel { margin: 0 0 var(--gap); }

.panel > h2 {
  margin: 0 0 8px;
  font-size: 1.3rem;
}

/* ---------- How it works ---------- */

.steps {
  list-style: none;
  counter-reset: step;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 16px;
}

.steps li {
  counter-increment: step;
  position: relative;
  padding-left: 44px;
  min-height: 32px;
}

.steps li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 1px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.step-title {
  display: block;
  font-weight: 600;
  font-size: 0.98rem;
  line-height: 1.35;
}

.step-body {
  display: block;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.5;
}

/* ---------- Section divider ----------
   Used where two unrelated forms share a page: the rule breaks the rhythm and
   the note names what comes next, so the second form is read as a new ask
   rather than as more of the first one. */

.section-divider {
  margin: var(--gap-group) 0 10px;
  border: 0;
  border-top: 1px solid var(--line-strong);
}

.section-divider-note {
  margin: 0 0 14px;
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--faint);
}

/* ---------- Email signup ----------
   Tinted, not white: it must never be mistaken for the address lookup. */

.signup {
  padding: 22px 20px;
  background: var(--accent-soft);
  border-radius: var(--r);
  box-shadow: var(--shadow);
}

.signup h2 {
  margin: 0 0 6px;
  font-size: 1.28rem;
}

.signup-intro {
  margin: 0 0 16px;
  font-size: 0.95rem;
  line-height: 1.5;
  max-width: 56ch;
  color: var(--muted);
}

.signup .embeddable-buttondown-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.signup .embeddable-buttondown-form label {
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}

.signup .embeddable-buttondown-form input[type="email"] {
  font: inherit;
  min-width: 0;
  min-height: 48px;
  padding: 12px 14px;
  border: 1px solid var(--accent-line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text);
}

.signup .embeddable-buttondown-form input[type="submit"] {
  font: inherit;
  font-weight: 600;
  min-height: 48px;
  padding: 12px 22px;
  border: 0;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  white-space: nowrap;
  -webkit-appearance: none;
  appearance: none;
}

.signup .embeddable-buttondown-form input[type="submit"]:hover { background: var(--accent-dark); }

.signup .embeddable-buttondown-form p {
  margin: 0;
  font-size: 0.76rem;
  color: var(--faint);
}

.signup .embeddable-buttondown-form p a { color: var(--faint); }
.signup .embeddable-buttondown-form p a:hover { color: var(--accent); }

/* ---------- Data-status notice ---------- */

.banner {
  padding: 16px 18px;
  background: var(--warn-bg);
  border-left: 5px solid var(--warn-line);
  border-radius: 0 var(--r) var(--r) 0;
  color: var(--warn-text);
  font-size: 0.92rem;
  line-height: 1.55;
  box-shadow: var(--shadow);
}

.banner p { margin: 0 0 10px; }
.banner p:last-child { margin-bottom: 0; }

.banner-title {
  font-family: var(--sans);
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--warn-accent);
}

.banner a { color: var(--warn-accent); }

/* ---------- Address lookup ---------- */

.lookup {
  background: var(--surface);
  border-radius: var(--r);
  padding: 22px 20px;
  box-shadow: var(--shadow);
}

.lookup h2 {
  margin: 0 0 8px;
  font-size: 1.32rem;
}

.lookup-intro {
  margin: 0 0 18px;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.55;
  max-width: 60ch;
}

.lookup-intro strong { color: var(--text); }

.lookup-form label {
  display: block;
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  margin-bottom: 7px;
}

.lookup-row {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.lookup-row input {
  flex: 1;
  min-width: 0;
  font: inherit;
  min-height: 48px;
  padding: 12px 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface-sunk);
  color: var(--text);
}

.lookup-row input::placeholder { color: #8d93a3; }

.lookup-row button {
  font: inherit;
  font-weight: 600;
  min-height: 48px;
  padding: 12px 22px;
  border: 0;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  white-space: nowrap;
}

.lookup-row button:hover:not(:disabled) { background: var(--accent-dark); }

.lookup-row button:disabled {
  opacity: 0.6;
  cursor: progress;
}

.lookup-privacy {
  margin: 16px 0 0;
  padding: 14px 16px;
  background: var(--surface-sunk);
  border-radius: var(--r-sm);
  font-size: 0.87rem;
  line-height: 1.55;
  color: var(--muted);
}

.lookup-privacy strong { color: var(--text); }

.lookup-privacy code,
.banner code {
  font-size: 0.88em;
  background: rgba(0, 0, 0, 0.05);
  padding: 1px 5px;
  border-radius: 4px;
  word-break: break-all;
}

/* ---------- Lookup status ---------- */

.lookup-status {
  margin-top: 14px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  background: var(--surface-sunk);
  font-size: 0.92rem;
  color: var(--muted);
}

.lookup-status-warn {
  background: var(--warn-bg);
  color: var(--warn-text);
  box-shadow: inset 4px 0 0 var(--warn-line);
  padding-left: 16px;
}

.lookup-status-error {
  background: var(--accent-soft);
  color: var(--accent-dark);
  font-weight: 500;
  box-shadow: inset 4px 0 0 var(--accent);
  padding-left: 16px;
}

/* ---------- Matched precinct panel ---------- */

.lookup-result {
  margin-top: 18px;
  border-radius: var(--r);
  background: var(--accent-soft);
  padding: 18px 18px 16px;
  box-shadow: inset 5px 0 0 var(--accent);
}

.ballot-head { margin-bottom: 2px; }

.ballot-precinct-label {
  margin: 0;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
}

.ballot-precinct {
  margin: 2px 0 0;
  font-family: var(--serif);
  font-size: 2.2rem;
  font-weight: 700;
  line-height: 1.05;
  color: var(--accent);
  letter-spacing: -0.02em;
}

.ballot-address {
  margin: 5px 0 0;
  font-size: 0.88rem;
  color: var(--muted);
}

.ballot-why {
  margin: 16px 0 10px;
  font-size: 0.93rem;
  font-weight: 500;
}

.district-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--accent-line);
}

.district-list li {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 10px 0;
  border-bottom: 1px solid var(--accent-line);
}

.district-label {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.district-value { font-weight: 600; }

.district-unknown {
  font-weight: 400;
  font-style: italic;
  color: var(--muted);
}

.district-note {
  font-size: 0.84rem;
  color: var(--warn-text);
  background: var(--warn-bg);
  box-shadow: inset 3px 0 0 var(--warn-line);
  padding: 4px 10px;
  margin-top: 5px;
  border-radius: 0 4px 4px 0;
}

.ballot-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 16px;
}

.ballot-actions button {
  font: inherit;
  font-size: 0.93rem;
  font-weight: 600;
  min-height: 44px;
  padding: 10px 18px;
  border-radius: var(--r-sm);
  cursor: pointer;
  border: 0;
}

.ballot-toggle {
  background: var(--accent);
  color: #fff;
}

.ballot-toggle:hover { background: var(--accent-dark); }

.ballot-clear {
  background: var(--surface);
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--accent-line);
}

.ballot-clear:hover {
  color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* ==========================================================================
   Landing page

   Everything between the address field and the race list on a first visit.
   The list itself is not on the page yet, so these panels carry the whole
   first screen: what the lookup is for, when to vote, where the data came
   from, and what is missing from it.
   ========================================================================== */

/* ---------- First-load gate ----------
   Stands in the slot the race list will occupy. The red top edge ties it to
   the lookup above it: same decision, second half of it. */

.gate {
  background: var(--surface);
  border-radius: var(--r);
  border-top: 4px solid var(--accent);
  padding: 22px 20px;
  box-shadow: var(--shadow);
}

.gate h2 {
  margin: 0 0 10px;
  font-size: 1.25rem;
}

.gate p {
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.55;
  max-width: 60ch;
}

.gate strong { color: var(--text); }

.gate-action { margin: 18px 0 4px; }

/* A button, not an anchor: it reveals content rather than navigating. Styled
   as a link so it reads as the quieter second option next to "Find my races",
   but sized to the 44px touch target every other control on the page keeps. */
.gate-link {
  font: inherit;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  display: inline-block;
  min-height: 44px;
  padding: 10px 0;
  border: 0;
  background: none;
  color: var(--accent);
  text-align: left;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

.gate-link:hover {
  color: var(--accent-dark);
  text-decoration-thickness: 2px;
}

.gate-hint {
  margin: 0;
  color: var(--faint);
  font-size: 0.85rem;
  line-height: 1.5;
}

/* The revealed list. No display of its own, so [hidden] keeps working. */
.browse:focus { outline: none; }

/* ---------- Key dates ---------- */

.dates {
  background: var(--surface);
  border-radius: var(--r);
  padding: 22px 20px;
  box-shadow: var(--shadow);
}

.dates h2 {
  margin: 0 0 14px;
  font-size: 1.25rem;
}

.date-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
}

.date-list li {
  display: flex;
  gap: 14px;
  padding: 14px 16px;
  background: var(--surface-sunk);
  border-radius: var(--r-sm);
}

/* Fixed-width date column so the two rows line up their titles regardless of
   how long the date reads. */
.date-when {
  flex: 0 0 4.4rem;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.date-month {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.11em;
  color: var(--faint);
}

.date-day {
  font-family: var(--serif);
  font-size: 1.45rem;
  font-weight: 700;
  line-height: 1;
  color: var(--accent);
}

.date-title {
  display: block;
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.3;
}

.date-body {
  display: block;
  margin-top: 3px;
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.5;
}

/* The registration deadline is a rule, not a date on the calendar above it,
   so it sits outside the list and is tinted to say so. */
.date-note {
  margin: 16px 0 0;
  padding: 12px 14px;
  background: var(--accent-soft);
  border-radius: var(--r-sm);
  color: var(--accent-dark);
  font-size: 0.87rem;
  line-height: 1.55;
}

.date-note strong { color: var(--accent-deep); }

/* ---------- Data provenance ---------- */

.provenance {
  background: var(--surface);
  border-radius: var(--r);
  padding: 22px 20px;
  box-shadow: var(--shadow);
}

.provenance h2 {
  margin: 0 0 14px;
  font-size: 1.25rem;
}

.prov-list {
  margin: 0;
  display: grid;
  gap: 14px;
}

.prov-item {
  padding: 14px 16px;
  background: var(--surface-sunk);
  border-left: 3px solid var(--accent-line);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}

/* The number is the headline: it is the thing a reader can go and count. */
.prov-item dt {
  margin: 0 0 5px;
  font-family: var(--serif);
  font-size: 1.08rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--text);
}

.prov-item dd {
  margin: 0;
  color: var(--muted);
  font-size: 0.89rem;
  line-height: 1.55;
}

.prov-meta {
  display: block;
  margin-top: 7px;
  font-size: 0.83rem;
  color: var(--faint);
}

.prov-meta code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.92em;
  word-break: break-all;
}

/* ---------- Coverage and gaps ---------- */

.scope {
  background: var(--surface);
  border-radius: var(--r);
  padding: 22px 20px;
  box-shadow: var(--shadow);
}

.scope h2 {
  margin: 0 0 14px;
  font-size: 1.25rem;
}

.scope-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 14px;
}

/* Marker shape carries the meaning as well as the color: a check for what is
   here, a dash for what is not. */
.scope-list li {
  position: relative;
  padding-left: 32px;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.55;
}

.scope-list li::before {
  position: absolute;
  left: 0;
  top: 1px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  font-weight: 700;
}

.scope-yes::before {
  content: "\2713";
  background: var(--grn-bg);
  color: var(--grn);
}

.scope-no::before {
  content: "\2013";
  background: var(--surface-sunk);
  color: var(--faint);
}

.scope-list strong { color: var(--text); }

/* ---------- Where to find endorsements ---------- */

.endorsements {
  background: var(--surface);
  border-radius: var(--r);
  padding: 22px 20px;
  box-shadow: var(--shadow);
}

.endorsements h2 {
  margin: 0 0 10px;
  font-size: 1.25rem;
}

.endorsements-intro {
  margin: 0 0 16px;
  color: var(--muted);
  font-size: 0.94rem;
  line-height: 1.6;
  max-width: 66ch;
}

.endorsement-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 10px;
}

/* Each entry names the organization and then its host, so the destination is
   visible on paper and to anyone who cannot hover the link. */
.endorsement-list li {
  padding: 12px 14px;
  background: var(--surface-sunk);
  border-radius: var(--r-sm);
  font-size: 0.94rem;
  line-height: 1.5;
}

.endorsement-host {
  display: block;
  margin-top: 2px;
  color: var(--faint);
  font-size: 0.86rem;
}

.endorsements-note {
  margin: 16px 0 0;
  color: var(--faint);
  font-size: 0.86rem;
  line-height: 1.55;
  max-width: 66ch;
}

/* ---------- About page prose ----------
   Also the one-line pointer to the about page that stands in for the moved
   blocks on the guide. */

.about {
  background: var(--surface);
  border-radius: var(--r);
  padding: 22px 20px;
  box-shadow: var(--shadow);
}

.about h2 {
  margin: 0 0 10px;
  font-size: 1.25rem;
}

.about p,
.about ul {
  margin: 0 0 12px;
  color: var(--muted);
  font-size: 0.94rem;
  line-height: 1.6;
  max-width: 66ch;
}

.about ul { padding-left: 1.25em; }
.about li + li { margin-top: 6px; }

.about > :last-child { margin-bottom: 0; }

.about strong { color: var(--text); }

/* ==========================================================================
   Filter bar

   A labelled panel sitting in the normal flow above the results.
   ========================================================================== */

.controls {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin: 0 0 6px;
  padding: 16px;
  background: var(--surface);
  border-radius: var(--r);
  box-shadow: var(--shadow);
}

.control {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.control-wide { grid-column: 1 / -1; }

.control label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.11em;
  color: var(--faint);
}

.control select,
.control input,
.control button {
  font: inherit;
  font-size: 0.94rem;
  min-height: 46px;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: inherit;
  max-width: 100%;
  min-width: 0;
}

.control select {
  -webkit-appearance: none;
  appearance: none;
  padding-right: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%235d574f' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 11px;
}

.control button {
  cursor: pointer;
  background: var(--surface-sunk);
  border-color: var(--line-strong);
  color: var(--muted);
  font-weight: 600;
  font-size: 0.88rem;
  white-space: nowrap;
  width: 100%;
}

.control button:hover {
  color: var(--accent);
  border-color: var(--accent);
}

/* ---------- Filter feedback ---------- */

.filter-note {
  margin: 14px 0 0;
  padding: 11px 14px;
  background: var(--accent-soft);
  border-radius: var(--r-sm);
  color: var(--accent-dark);
  font-size: 0.85rem;
  line-height: 1.5;
  font-weight: 500;
}

/* Count on the left, the print action on the right: the button belongs next
   to the number it will put on paper, not up in the filter bar. */
.result-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  margin: 14px 2px 30px;
}

.print-button {
  flex: 0 0 auto;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  min-height: 40px;
  padding: 9px 15px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--muted);
  white-space: nowrap;
}

.print-button:hover {
  color: var(--accent);
  border-color: var(--accent);
}

/* Exists only on paper — see the print stylesheet at the end of this file. */
.print-only { display: none; }

.result-count {
  margin: 0;
  color: var(--faint);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* ==========================================================================
   Results — jurisdiction groups

   The big gap between groups is doing real work: it is the only cue that
   one office's races have ended and another's have begun.
   ========================================================================== */

.jurisdiction {
  margin: 0 0 var(--gap-group);
}

.jurisdiction:last-child { margin-bottom: 0; }

.jurisdiction-head {
  margin-bottom: 18px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}

.jurisdiction-head h2 {
  margin: 4px 0 0;
  font-size: 1.55rem;
  line-height: 1.1;
}

.badge {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--faint);
}

.badge-school { color: var(--accent); }

/* ---------- Race cards ---------- */

.race {
  background: var(--surface);
  border-radius: var(--r);
  padding: 16px 16px 6px;
  margin-bottom: 12px;
  box-shadow: var(--shadow);
}

.race:last-child { margin-bottom: 0; }

.race-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin-bottom: 12px;
}

/* The largest thing in the list, by a clear margin: a race name has to be
   findable while scrolling past a hundred of them. */
.race-head h3 {
  margin: 0;
  flex: 1 1 12rem;
  font-size: 1.24rem;
  line-height: 1.2;
  color: var(--text);
  letter-spacing: -0.01em;
}

.election-date {
  flex: 0 0 auto;
  color: var(--faint);
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  white-space: nowrap;
}

/* No candidate from the selected party: the race stays on the page — the
   absence is information — but it recedes and says why. */
.race-unmatched {
  background: var(--surface-sunk);
  box-shadow: none;
}

.race-unmatched .race-head h3 { color: var(--muted); }

.race-note {
  flex: 0 0 100%;
  margin-top: 2px;
  color: var(--accent-dark);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* ---------- Office explanations ---------- */

/* A race title that has an explanation behind it is still, first, the race
   title: same size, same weight, same color as one that does not. The button
   is stripped back to the heading it replaced, and the only thing marking it
   is the glyph at the end. Titles that match no office stay plain <h3> text,
   so the two sit side by side in a list without the explained ones reading
   as more important. */
.office-toggle {
  display: inline;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-align: left;
  cursor: pointer;
}

.office-toggle-text {
  text-decoration: underline dotted var(--line-strong);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

.office-toggle:hover .office-toggle-text {
  text-decoration-color: var(--accent);
}

/* Sized and spaced as its own tap target rather than as punctuation: on a
   phone the whole title line is tappable, but the glyph is what says so. */
.office-toggle-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15em;
  height: 1.15em;
  margin-left: 0.4em;
  border-radius: 50%;
  background: var(--surface-sunk);
  border: 1px solid var(--line-strong);
  color: var(--muted);
  font-size: 0.68em;
  font-weight: 700;
  line-height: 1;
  vertical-align: 0.18em;
}

.office-toggle:hover .office-toggle-icon {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent-dark);
}

.office-toggle[aria-expanded="true"] .office-toggle-icon {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* Full width of the race card, below the whole title line. Sunk rather than
   raised: this is a footnote to the race, not a second card inside it.
   No display of its own, so [hidden] keeps working. */
.office-panel {
  flex: 0 0 100%;
  margin-top: 10px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  border-left: 3px solid var(--accent-line);
  background: var(--surface-sunk);
}

.office-desc {
  margin: 0;
  color: var(--text);
  font-size: 0.9rem;
  line-height: 1.5;
}

/* A fact about this particular seat, not about the office — set apart from
   the description so the two are not read as one sentence. */
.office-note {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 0.86rem;
  font-style: italic;
  line-height: 1.45;
}

.office-law {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  margin: 10px 0 0;
  padding-top: 9px;
  border-top: 1px solid var(--line);
}

.office-law-label {
  color: var(--faint);
  font-size: 0.64rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

/* The longest label here runs past 50 characters, which is wider than a
   phone's content column: the link wraps inside itself rather than pushing
   the panel into a horizontal scroll. */
.office-law-link {
  min-width: 0;
  font-size: 0.82rem;
  font-weight: 600;
  overflow-wrap: break-word;
}

/* ---------- Candidate rows ---------- */

/* Rules go between rows, not above the first one. Sibling-matched rather
   than :first-of-type, because a row is a <details> when it has detail to
   open and a <div> when it does not — two element types in one list. */
.candidate + .candidate {
  border-top: 1px solid var(--hairline);
}

.candidate-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  padding: 11px 0;
  list-style: none;
}

/* A candidate with sourced detail is a <details>; one without is a plain
   row. The chevron only ever appears where there is something to open. */
.candidate-row::-webkit-details-marker { display: none; }
.candidate-row::marker { content: ""; }

details.candidate > .candidate-row {
  cursor: pointer;
  padding-right: 26px;
  position: relative;
}

details.candidate > .candidate-row::after {
  content: "";
  position: absolute;
  right: 4px;
  top: 50%;
  width: 9px;
  height: 9px;
  margin-top: -6px;
  border-right: 2px solid var(--faint);
  border-bottom: 2px solid var(--faint);
  transform: rotate(45deg);
  transition: transform 0.15s ease;
}

details.candidate[open] > .candidate-row::after {
  margin-top: -2px;
  transform: rotate(225deg);
}

details.candidate > .candidate-row:hover .candidate-name { color: var(--accent); }

.candidate-name {
  font-size: 0.98rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text);
  flex: 1 1 auto;
  min-width: 0;
}

/* Off-party candidates are pushed back, never hidden — held high enough
   that the names stay readable to anyone looking past the highlight. */
.candidate-dim { opacity: 0.45; }

.candidate-match .candidate-name { color: var(--accent-dark); }

/* ---------- Party chips ----------
   Filled, labelled, and shaped. The glyph's outline differs per party
   (square, circle, hexagon, diamond) so the chips stay distinguishable
   in greyscale, at a glance, and to anyone who does not see the hue. */

.party {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  padding: 3px 10px 3px 3px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  background: var(--surface-sunk);
  color: var(--muted);
}

.party-glyph {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 21px;
  height: 21px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0;
  color: #fff;
  background: var(--muted);
}

.party-republican { background: var(--rep-bg); color: var(--rep); }
.party-republican .party-glyph { background: var(--rep); border-radius: 4px; }

.party-democratic { background: var(--dem-bg); color: var(--dem); }
.party-democratic .party-glyph { background: var(--dem); border-radius: 50%; }

.party-libertarian { background: var(--lib-bg); color: var(--lib); }
.party-libertarian .party-glyph {
  background: var(--lib);
  clip-path: polygon(26% 0, 74% 0, 100% 50%, 74% 100%, 26% 100%, 0 50%);
}

.party-green { background: var(--grn-bg); color: var(--grn); }
.party-green .party-glyph {
  width: 23px;
  height: 23px;
  background: var(--grn);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}

/* Nonpartisan office: no party, so no hue and no glyph — the one chip in the
   row that is deliberately not color-coded, because a color here would read as
   a fifth party. Restates the neutral ground explicitly rather than leaning on
   .party's default, and takes back the left padding the missing glyph held. */
.party-nonpartisan {
  padding-left: 10px;
  background: var(--surface-sunk);
  color: var(--muted);
}

/* ---------- Unopposed ---------- */

.marker-unopposed {
  flex: 0 0 auto;
  padding: 3px 9px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--line-strong);
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  white-space: nowrap;
}

/* ---------- Expanded candidate detail ---------- */

.candidate-detail {
  padding: 2px 0 16px;
}

.detail { margin: 0 0 16px; }
.detail:last-child { margin-bottom: 0; }

.detail-label {
  margin: 0 0 8px;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--faint);
}

.item-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.item-list li {
  padding: 10px 14px;
  margin-bottom: 8px;
  background: var(--surface-sunk);
  border-radius: var(--r-sm);
  font-size: 0.92rem;
  line-height: 1.5;
}

.item-list li:last-child { margin-bottom: 0; }

.item-name { font-weight: 600; }

.item-meta {
  color: var(--muted);
  font-size: 0.85rem;
}

.item-note {
  display: block;
  color: var(--muted);
  font-size: 0.85rem;
}

.source-link {
  display: inline-block;
  margin-top: 4px;
  font-size: 0.82rem;
  font-weight: 600;
}

.amount {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

/* ---------- Empty / loading states ---------- */

.status {
  padding: 40px 20px;
  text-align: center;
  color: var(--muted);
  background: var(--surface);
  border-radius: var(--r);
  box-shadow: var(--shadow);
}

.status-error {
  color: var(--accent-dark);
  background: var(--accent-soft);
  box-shadow: inset 5px 0 0 var(--accent);
  text-align: left;
}

/* ---------- Sourcing note ---------- */

.sourcing {
  margin: var(--gap-group) 0 0;
  padding: 22px 20px;
  background: var(--surface);
  border-radius: var(--r);
  box-shadow: var(--shadow);
}

.sourcing h2 {
  margin: 0 0 10px;
  font-size: 1.28rem;
}

.sourcing p {
  margin: 0;
  color: var(--muted);
  font-size: 0.94rem;
  line-height: 1.6;
  max-width: 66ch;
}

/* ---------- Contact form ----------
   Controls are deliberately identical to the address lookup's: same 48px floor,
   same radius, same sunk fill, so the two forms on the site read as one kit. */

.contact {
  background: var(--surface);
  border-radius: var(--r);
  padding: 22px 20px;
  box-shadow: var(--shadow);
}

.contact h2 {
  margin: 0 0 8px;
  font-size: 1.32rem;
}

.contact-intro {
  margin: 0 0 20px;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.55;
  max-width: 60ch;
}

.contact-intro strong { color: var(--text); }

.contact-form {
  display: grid;
  gap: 18px;
}

.contact-form .field {
  display: grid;
  gap: 7px;
}

.contact-form label {
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}

.contact-form input,
.contact-form textarea {
  width: 100%;
  min-width: 0;
  font: inherit;
  min-height: 48px;
  padding: 12px 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface-sunk);
  color: var(--text);
}

.contact-form textarea {
  /* Vertical only: a textarea dragged wider breaks the column on a phone. */
  resize: vertical;
  line-height: 1.55;
  min-height: 150px;
}

.field-note {
  margin: 0;
  font-size: 0.82rem;
  color: var(--faint);
}

.contact-submit {
  justify-self: start;
  font: inherit;
  font-weight: 600;
  min-height: 48px;
  padding: 12px 26px;
  border: 0;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.contact-submit:hover { background: var(--accent-dark); }

/* Bot bait. Not .visually-hidden: that keeps the field in the accessibility
   tree, where a screen reader would read out a question no person should
   answer. This one is gone for everybody who is real. */
.honeypot { display: none; }

/* ---------- Footer ---------- */

.site-footer {
  margin-top: 48px;
  padding: 26px 0 44px;
  background: var(--surface);
  border-top: 1px solid var(--line);
  color: var(--faint);
  font-size: 0.85rem;
}

.site-footer p { margin: 0 0 4px; }

.footer-name {
  font-family: var(--serif);
  font-weight: 700;
  font-size: 1.05rem;
  line-height: 1.2;
  color: var(--accent);
  margin-bottom: 8px;
}

.footer-links {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin: 12px 0;
  padding: 0;
}

.footer-links a {
  display: inline-block;
  /* A comfortable tap target without pushing the links apart visually. */
  padding: 6px 0;
  font-weight: 600;
}

/* ==========================================================================
   Wider screens — more air, never a different page.
   ========================================================================== */

@media (min-width: 620px) {
  :root {
    --gap: 36px;
    --gap-group: 80px;
  }


  .page { padding-top: 40px; }

  .steps {
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
  }

  .signup,
  .lookup,
  .contact,
  .gate,
  .dates,
  .provenance,
  .scope,
  .endorsements,
  .about,
  .sourcing { padding: 28px 30px; }

  /* Two dates side by side; the provenance entries pair off the same way. Both
     lists are exactly two items, so the row always fills. */
  .date-list,
  .prov-list { grid-template-columns: 1fr 1fr; }

  .date-list li { padding: 16px 18px; }

  .gate h2,
  .dates h2,
  .provenance h2,
  .scope h2,
  .endorsements h2,
  .about h2 { font-size: 1.35rem; }

  .banner { padding: 20px 24px; font-size: 0.95rem; }

  .signup .embeddable-buttondown-form {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }

  .signup .embeddable-buttondown-form label { flex: 0 0 100%; }
  .signup .embeddable-buttondown-form input[type="email"] { flex: 1 1 15rem; }
  .signup .embeddable-buttondown-form input[type="submit"] { flex: 0 0 auto; }
  .signup .embeddable-buttondown-form p { flex: 0 0 100%; }

  .lookup-row {
    flex-direction: row;
    align-items: center;
  }

  .district-list li {
    flex-direction: row;
    align-items: baseline;
    gap: 12px;
    flex-wrap: wrap;
  }

  .district-label { flex: 0 0 13rem; }

  .district-note {
    flex-basis: 100%;
    margin-left: 13rem;
  }

  .controls {
    /* The last column sizes to its content so the Order select can show
       "Grouped by jurisdiction" in full rather than clipping it. */
    grid-template-columns: repeat(3, 1fr) auto;
    align-items: end;
    padding: 18px 20px;
  }

  .control-wide { grid-column: auto; }
  .control-search { grid-column: span 3; }
  .control-reset { grid-column: span 1; }

  .jurisdiction-head h2 { font-size: 1.95rem; }

  .race {
    padding: 20px 24px 8px;
    margin-bottom: 14px;
  }

  .race-head h3 { font-size: 1.42rem; }

  .candidate-name { font-size: 1.02rem; }

  .candidate-row { padding: 13px 0; }
}

/* ==========================================================================
   Lone Star touches below the header. Kept to a few places on purpose: the
   flag belongs to the chrome, and candidate rows stay neutral.
   ========================================================================== */

/* Key dates as calendar tear-offs: blue for early voting, red for election day. */
.date-list li {
  gap: 0;
  padding: 0;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
}

.date-when {
  flex: 0 0 5.2rem;
  align-items: center;
  justify-content: center;
  padding: 12px 6px;
  text-align: center;
  background: var(--flag-blue);
}

.date-list li:last-child .date-when { background: var(--flag-red); }

.date-month { color: rgba(255, 255, 255, 0.85); }

.date-day {
  font-size: 1.5rem;
  color: #fff;
  font-variant-numeric: tabular-nums;
}

.date-what { padding: 14px 16px; }

.date-title {
  font-family: var(--serif);
  font-size: 1.12rem;
  font-weight: 700;
}

/* Race cards get a blue cap so a long ballot reads as a stack of cards. */
.race { border-top: 4px solid var(--flag-blue); }

/* The sourcing pledge is the site's promise, so it gets the flag's blue. */
.sourcing {
  background: var(--flag-blue);
  box-shadow: none;
}

.sourcing h2 { color: #fff; }

.sourcing h2::after {
  content: "";
  display: block;
  width: 48px;
  height: 5px;
  margin-top: 12px;
  background: var(--flag-red);
}

.sourcing p,
.sourcing li { color: rgba(255, 255, 255, 0.88); }

.sourcing strong { color: #fff; }

.sourcing a,
.sourcing a:hover { color: #fff; }

.signup {
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: none;
}

.signup .embeddable-buttondown-form input[type="submit"] { background: var(--flag-red); }
.signup .embeddable-buttondown-form input[type="submit"]:hover { background: var(--flag-red-dark); }

/* Footer: deep navy with a flag stripe across the top. */
.site-footer {
  position: relative;
  padding-top: 32px;
  background: var(--accent-dark);
  border-top: 0;
  color: rgba(255, 255, 255, 0.78);
}

.site-footer::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 6px;
  background:
    linear-gradient(90deg, var(--flag-blue) 33.333%, transparent 33.333%),
    linear-gradient(180deg, #fff 50%, var(--flag-red) 50%);
}

.footer-name { color: #fff; }

.site-footer a,
.site-footer a:hover { color: #fff; }


@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition-duration: 0.01ms !important; }
}


/* ==========================================================================
   Print — the ballot, and nothing else.

   Paper gets one job: the races currently on screen, in the order they are
   currently in, with each race's candidates, party, and unopposed marker.
   Everything that exists to help someone navigate the site — hero, filters,
   signup, banner, footer, and the sourced detail behind each candidate row —
   is furniture here, so it comes off. Single column, black on white, no
   shadows and no tinted panels: it has to survive a cheap printer.
   ========================================================================== */

@media print {
  /* Sized to be read, not just to fit: 10pt base with 11pt race names. Two
     columns on the ballot buy back the width that larger type costs, so a
     60-race ballot still lands on about two sheets. Margins are the narrowest
     most consumer printers will render without clipping. */
  @page {
    margin: 11mm;
  }

  /* One sweep to flatten every tinted panel, chip, and shadow the screen
     design leans on. Structure below is then rebuilt in plain black. */
  *,
  *::before,
  *::after {
    background: transparent !important;
    box-shadow: none !important;
    color: #000 !important;
    text-shadow: none !important;
  }

  html {
    font-size: 10pt;
    scroll-behavior: auto;
  }

  body {
    background: #fff;
  }

  /* Everything that is not the ballot. */
  .site-header,
  .panel,
  .controls,
  .filter-note,
  .result-bar,
  .sourcing,
  .site-footer {
    display: none !important;
  }

  .print-only { display: block; }

  /* The contact page has no ballot to print, so the sweep above would leave it
     blank. Give it back its prose — the form itself is useless on paper. */
  .page-contact .panel,
  .page-contact .sourcing { display: block !important; }
  .page-contact .contact-form,
  .page-contact .embeddable-buttondown-form,
  .page-contact .section-divider,
  .page-contact .section-divider-note { display: none !important; }

  /* Same for the about and sources pages: no ballot, only prose, so give their
     panels back. */
  .page-about .panel,
  .page-about .sourcing,
  .page-sources .panel,
  .page-sources .sourcing { display: block !important; }

  .wrap,
  .page {
    max-width: none;
    width: auto;
    margin: 0;
    padding: 0;
  }

  /* ---------- Print header ---------- */

  .print-header {
    margin: 0 0 6pt;
    padding: 0 0 3pt;
    border-bottom: 0.75pt solid #000;
    break-after: avoid;
    page-break-after: avoid;
  }

  .print-title {
    margin: 0 0 1pt;
    font-family: var(--serif);
    font-size: 11pt;
    font-weight: 700;
    line-height: 1.1;
  }

  .print-meta {
    margin: 0;
    font-size: 7pt;
    line-height: 1.25;
  }

  /* The one line that says the sheet is a slate and not the full field. It
     outranks the precinct and the race count, so it is sized above them. */
  .print-filter {
    font-size: 9pt;
    font-weight: 700;
  }

  /* ---------- Races ---------- */

  /* Two columns: at 10pt a single full-width measure would run to four or five
     sheets, and a race line is short enough that half the page is a generous
     measure for it. Every race already carries break-inside: avoid, which the
     column breaker honours the same way the page breaker does. */
  #results {
    column-count: 2;
    column-gap: 14pt;
  }

  .jurisdiction {
    margin: 0 0 7pt;
  }

  .jurisdiction-head {
    margin: 0 0 2pt;
    padding: 0;
    border: 0;
    border-bottom: 0.5pt solid #000;
    break-after: avoid;
    page-break-after: avoid;
  }

  .jurisdiction-head h2 {
    font-size: 9pt;
    line-height: 1.15;
  }

  .badge { display: none !important; }

  /* A race is a single block on paper: never split a race name from its
     candidates across a page break. */
  .race {
    margin: 0 0 6pt;
    padding: 0;
    border: 0;
    border-radius: 0;
    break-inside: avoid;
    page-break-inside: avoid;
  }

  .race-head {
    display: block;
    margin: 0;
  }

  /* The race name is the only thing separating one block from the next, so it
     keeps its weight as well as its size. */
  .race-head h3 {
    font-size: 11pt;
    font-weight: 700;
    line-height: 1.15;
  }

  /* One election, printed once in the header. */
  .election-date { display: none !important; }

  /* On paper the title is a title again — there is nothing to tap, so the
     disclosure marker goes and the button prints as the heading text it
     holds. An explanation the reader opened before printing is not carried
     onto the sheet: this is a ballot to vote from, and a page of them is
     already two sheets without the footnotes. */
  .office-toggle-icon { display: none !important; }
  .office-panel { display: none !important; }

  .office-toggle {
    font: inherit;
    color: inherit;
  }

  .office-toggle-text { text-decoration: none; }

  /* The absence of a pick is the whole reason this race is still on the sheet,
     so the note takes the slot the candidate's name would have occupied:
     same indent, same size, italic so it does not read as a person's name. */
  .race-note {
    display: block;
    margin: 0;
    padding: 0 0 0 9pt;
    font-size: 10pt;
    font-style: italic;
    font-weight: 400;
    letter-spacing: 0;
    line-height: 1.2;
    text-transform: none;
  }

  /* ---------- Candidate lines ---------- */

  /* Slate print: with a party selected the sheet is a card to carry into the
     booth, so it drops the other parties' candidates outright and leaves one
     name per race. The screen dims them; a dimmed name on paper just looks
     like a bad printer, and a voter reading down a column does not want to
     re-apply the filter by eye. */
  .candidate-dim { display: none !important; }

  .candidate {
    display: block;
    opacity: 1 !important;
    border: 0;
  }

  .candidate + .candidate { border-top: 0; }

  /* Endorsements and donations stay off the sheet, and so does the disclosure
     arrow that would have opened them. */
  .candidate-detail { display: none !important; }
  details.candidate > .candidate-row::after { display: none !important; }

  .candidate-row {
    display: block;
    padding: 0 0 0 9pt;
    font-size: 10pt;
    line-height: 1.2;
  }

  .candidate-name {
    font-size: inherit;
    font-weight: 600;
  }

  /* Chips become plain running text: "Jane Doe — Republican · Unopposed". */
  .party,
  .marker-unopposed {
    display: inline;
    padding: 0;
    border-radius: 0;
    font-size: inherit;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
  }

  /* Non-breaking spaces: a collapsible space inside generated content is not
     reliably kept, and these separators must not lose their air. */
  .party::before { content: "\00a0\2014\00a0"; }
  .marker-unopposed::before { content: "\00a0\00b7\00a0"; }

  /* The glyph is the party's first letter again, doubled up once the chip is
     flattened to text. */
  .party-glyph { display: none !important; }

  /* "No races match the current filters" is worth printing — a blank sheet is
     not. */
  .status {
    padding: 0;
    font-size: 9pt;
  }

  /* Sits below both columns, full width, and only has content on a slate
     print. Empty on an unfiltered sheet, where it collapses to nothing. */
  .print-footer {
    margin: 8pt 0 0;
    padding: 3pt 0 0;
    border-top: 0.75pt solid #000;
    font-size: 8pt;
    line-height: 1.3;
    break-inside: avoid;
    page-break-inside: avoid;
  }

  .print-footer:empty {
    display: none !important;
  }
}
