/* ============================================================================
   styles.css — Visual design for the Vermont Candidate Guide
   ============================================================================

   STRUCTURE OF THIS FILE
     1. Design tokens (colors, spacing, type) — change look-and-feel here
     2. Base + accessibility helpers
     3. Address lookup
     4. Results (district summary + race accordion)
     5. Party styling (encodes the brief's color decision)

   This is a STARTING skeleton. The full visual build against the mockup
   happens in Step 6. Tokens are pulled from the mockup (the teal Submit
   button, the party header colors) so we build on the real palette, not
   generic placeholders.
   ============================================================================ */


/* 1. DESIGN TOKENS ---------------------------------------------------------
   Named values used everywhere else. A teammate can adjust the palette here
   without hunting through the file. */
:root {
  /* Brand */
  --color-action:        #177a88;   /* teal — AA-compliant with white text (5.0:1) */
  --color-action-hover:  #135f6b;   /* darker teal for hover */
  --color-accent:        #1a8a9c;   /* lighter teal for non-text accents (markers, tints) */
  --color-text:          #1a1a1a;
  --color-text-muted:    #5a5a5a;
  --color-bg:            #ffffff;
  --color-border:        #cccccc;
  --color-link:          #1a6f9c;

  /* Party colors (see config.js PARTY_STYLES + brief Decision Log) */
  --color-republican:    #d23b3b;   /* red */
  --color-democratic:    #2b6fd2;   /* blue */
  --color-progressive:   #1a1a1a;   /* black (white text) — Progressive AND every
                                       other non-D/R party (decision 2026-10-02) */

  /* Spacing scale */
  --space-xs:  4px;
  --space-sm:  8px;
  --space-md:  16px;
  --space-lg:  24px;
  --space-xl:  40px;

  /* Type */
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --radius:    4px;
}


/* 2. BASE + ACCESSIBILITY HELPERS ------------------------------------------ */
* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--color-text);
  background: var(--color-bg);
  line-height: 1.5;
}

.app {
  max-width: 720px;
  margin: 0 auto;
  padding: var(--space-sm);
}

/* Visible focus for keyboard users — never remove this without a replacement. */
:focus-visible {
  outline: 3px solid var(--color-action);
  outline-offset: 2px;
}

/* Hides content visually but keeps it for screen readers (e.g. section headings). */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Respect users who prefer reduced motion. */
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}


/* 3. ADDRESS LOOKUP -------------------------------------------------------- */
.lookup__label {
  display: block;
  font-weight: 600;
  margin-bottom: var(--space-xs);
}

.lookup__row {
  display: flex;
  gap: var(--space-sm);
}

.lookup__input {
  flex: 1;
  padding: var(--space-sm) var(--space-md);
  font-size: 1rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.lookup__submit {
  padding: var(--space-sm) var(--space-lg);
  font-size: 1rem;
  font-weight: 600;
  color: #fff;
  background: var(--color-action);
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
}
.lookup__submit:hover { background: var(--color-action-hover); }

.lookup__help {
  margin: var(--space-sm) 0 0;
  font-size: 0.9rem;
  color: var(--color-text-muted);
}

/* Autocomplete suggestion list */
.suggestions {
  list-style: none;
  margin: var(--space-xs) 0 0;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  max-height: 260px;
  overflow-y: auto;
  background: #fff;
}
.suggestions[hidden] { display: none; }

.suggestions__item {
  padding: var(--space-sm) var(--space-md);
  cursor: pointer;
  border-bottom: 1px solid var(--color-border);
}
.suggestions__item:last-child { border-bottom: none; }
/* Highlighted via keyboard (ArrowUp/Down) or hover — same visual treatment so
   mouse and keyboard users see the same active row. */
.suggestions__item.is-active,
.suggestions__item:hover {
  background: #eef4f6; /* light tint of the teal action color */
}


/* 4. RESULTS --------------------------------------------------------------- */
.results { margin-top: var(--space-lg); }

/* Loading / error / empty text states (plain sentences set via textContent). */
.results__failure,
.results__empty {
  padding: var(--space-md);
  background: #fbf4f4;
  border-left: 3px solid var(--color-republican);
  color: var(--color-text);
}

/* --- Summary row ---
   Your Address alone on the first row; Your Districts + Your Polling Place
   side by side beneath it (mockup general_01; both elections since
   2026-09-29). flex-basis: 100% forces the address onto its own line; the
   other two share the next line and stack on narrow screens via flex-wrap. */
.summary-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xl);
  margin-bottom: var(--space-lg);
}
.summary-row .address-summary { flex-basis: 100%; }
/* Polling Place takes whatever width is left beside Districts, wrapping a long
   name (e.g. "Sustainability Academy/ Lawrence Barnes School") onto two lines
   rather than dropping below Districts. The min-width is the point at which
   it gives up and stacks underneath instead — i.e. on phones. */
.summary-row .poll-place { flex: 1 1 0; min-width: 12rem; }
.districts, .address-summary { min-width: 0; }

.summary__title,
.results__title,
.race-group__title {
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 0.8rem;
  color: var(--color-text-muted);
  margin: 0 0 var(--space-sm);
}
.districts__list {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px var(--space-sm);
}
.districts__label { font-weight: 400; color: var(--color-text-muted); }
.districts__value { margin: 0; font-weight: 700; }

.address-summary__value { margin: 0; font-weight: 700; }

/* --- Your Polling Place block --- */
.poll-place__name { margin: 0; font-weight: 700; }
.poll-place__address { margin: 2px 0 0; }

/* Dotted underline + help cursor on address-specific location names (tweak #3).
   The tooltip text is provided via the title attribute in render.js. */
.location-name {
  border-bottom: 1px dotted currentColor;
  cursor: help;
}

/* --- Party ballot filter (tweak #7) --- */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-lg);
}
.filter-bar__label {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}
.filter-bar__btn {
  padding: 4px var(--space-md);
  font: inherit;
  font-size: 0.85rem;
  background: #fff;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  cursor: pointer;
  color: var(--color-text);
}
.filter-bar__btn:hover { border-color: var(--color-text-muted); }
.filter-bar__btn.is-active {
  border-color: var(--color-text);
  font-weight: 700;
}
/* When an active filter button carries a party color class, make it solid. */
.filter-bar__btn.is-active.party--republican  { background: var(--color-republican);  color:#fff; border-color: var(--color-republican); }
.filter-bar__btn.is-active.party--democratic  { background: var(--color-democratic);  color:#fff; border-color: var(--color-democratic); }
.filter-bar__btn.is-active.party--progressive { background: var(--color-progressive); color:#fff; border-color: var(--color-progressive); }

/* --- All Races header: title left, controls + legend stacked top-right --- */
.results__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-md);
  margin-bottom: var(--space-sm);
}
.results__controls-wrap {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}
.results__controls { display: flex; gap: var(--space-md); }
/* Incumbent legend, right-aligned under the controls (tweak #1). */
.results__legend {
  margin: 0;
  font-size: 0.8rem;
  color: var(--color-text-muted);
}

/* A button styled to read as a text link (used for expand/collapse all). */
.linklike {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: 0.85rem;
  color: var(--color-link);
  text-decoration: underline;
  cursor: pointer;
}
.linklike:hover { color: var(--color-action-hover); }

/* --- A level section (Statewide / Legislative / County-wide) --- */
.race-group { margin-bottom: var(--space-lg); }
.race-group__title {
  color: var(--color-text);
  font-size: 0.95rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0;
  padding-bottom: var(--space-xs);
  border-bottom: 2px solid var(--color-text);
}

/* --- A single collapsible race --- */
.race { border-bottom: 1px solid var(--color-border); }

.race__toggle {
  width: 100%;
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  padding: var(--space-sm) 0;
  background: none;
  border: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
  color: var(--color-text);
}
.race__marker {
  flex: none;
  width: 1em;
  color: var(--color-action);
  font-weight: 700;
}
.race__office { font-weight: 600; }
.race__detail { color: var(--color-text-muted); }

.race__panel { padding: 0 0 var(--space-md) calc(1em + var(--space-sm)); }
.race__panel[hidden] { display: none; }
.race__empty,
.race__panel .race__empty { color: var(--color-text-muted); font-style: italic; }

/* Editorial annotations at the bottom of an expanded race, below candidates.
   Each item on its own line; a rule above separates them from the candidates. */
.annotations {
  margin: var(--space-md) 0 0;
  padding-top: var(--space-sm);
  border-top: 1px solid var(--color-border);
}
.annotations__item {
  margin: 0 0 var(--space-xs);
  font-size: 0.9rem;
  line-height: 1.4;
}
.annotations__item:last-child { margin-bottom: 0; }
.annotations__link { color: var(--color-link); }
.annotations__link:hover { text-decoration: underline; }


/* 5. PARTY GROUPS + CANDIDATES --------------------------------------------- */

/* Party header bar. The color classes below match config.js PARTY_STYLES;
   styleForParty() (labels.js) returns the right one, and every party other
   than Democratic/Republican/Progressive gets .party--default — styled the
   same white-on-black as Progressive. */
.party { margin: var(--space-sm) 0 var(--space-md); }
.party__header {
  display: inline-block;
  padding: 2px var(--space-sm);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-radius: 2px;
  margin-bottom: var(--space-sm);
}
.party--republican { background: var(--color-republican); color: #fff; }
.party--democratic { background: var(--color-democratic); color: #fff; }
.party--progressive { background: var(--color-progressive); color: #fff; }
/* Default — every party other than Democratic, Republican (and Progressive,
   which already looks like this): Independent, Freedom and Unity, Peace and
   Justice, typos, anything new. Same white-on-black bar as Progressive
   (decision 2026-10-02; until then these were plain text with no bar). */
.party--default { background: var(--color-progressive); color: #fff; }

.party__candidates { display: flex; flex-direction: column; gap: var(--space-sm); }

/* Fusion header (e.g. DEM/PROG): one badge of adjoining colored segments,
   one per party in the order filed — [DEMOCRATIC][PROGRESSIVE]. The badge
   itself is just a frame; each segment carries its own party color class. */
.party__header--fusion {
  display: inline-flex;
  padding: 0;
  overflow: hidden;           /* keeps the rounded corners on the end segments */
}
.party__segment { padding: 2px var(--space-sm); }


/* --- One candidate row --- */
/* --- One candidate row ---
   DESKTOP: name (+ town) on the left, campaign link right-aligned on the same
   line — matching the mockup.
   MOBILE: see the media query below. The link always sits directly under the
   name, left-aligned. Without that, `space-between` + `flex-wrap` made the link
   land beside the name for short names/URLs and beneath it for long ones —
   an inconsistent position that depended on text length. */
.candidate {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
}
.candidate__main { display: flex; align-items: baseline; gap: var(--space-sm); }
.candidate__name { font-weight: 600; }
.candidate__town { font-size: 0.85rem; color: var(--color-text-muted); }

.candidate__link {
  color: var(--color-link);
  text-decoration: none;
  white-space: nowrap;
}
.candidate__link:hover { text-decoration: underline; }
.candidate__link-icon { margin-left: 2px; font-size: 0.85em; }

/* MOBILE candidate layout.
   Stack the campaign link directly beneath the name, left-aligned, with tight
   vertical spacing — so its position never depends on how long the name or URL
   happens to be. `align-items: flex-start` left-aligns the stacked children;
   the row's `gap` is overridden to a small value so the link hugs the name. */
@media (max-width: 560px) {
  .candidate {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;              /* tight: link sits just under the name */
    flex-wrap: nowrap;
  }
  .candidate__link {
    /* Long URLs must wrap rather than overflow the narrow screen. */
    white-space: normal;
    overflow-wrap: anywhere;
  }
}


/* 5a. GENERAL-ELECTION MODE + SHARED PHASE 2 LOOK -------------------------
   The race chips only appear in general mode (config.js ELECTION_MODE). The
   "Learn more" heading (mockups general_02/03) is used by both elections. */

/* "Show races:" chip filter, under the All Races header (general mode). */
.race-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-lg);
}
.race-chips__label {
  font-size: 0.9rem;
  color: var(--color-text-muted);
}
.race-chips__chip {
  padding: 4px var(--space-md);
  font: inherit;
  font-size: 0.9rem;
  background: #fff;
  color: var(--color-text);
  border: 1px solid var(--color-text-muted);
  border-radius: var(--radius);
  cursor: pointer;
}
.race-chips__chip:hover { border-color: var(--color-text); }
.race-chips__chip[hidden] { display: none; }
/* A chosen chip (or "All" when nothing is chosen): tinted + darker border. */
.race-chips__chip.is-active {
  background: #e3ebee;
  border-color: var(--color-text);
  font-weight: 700;
}
.race-chips__more { color: var(--color-link); }

/* "Learn more" heading above race annotations (both elections) — same style
   as the other small uppercase labels ("Your Districts", etc.). */
.annotations__title {
  margin: 0 0 var(--space-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 0.8rem;
  color: var(--color-text-muted);
}


/* Ballot-question proposals (e.g. Constitutional Amendments; mockup
   general_03): each title is a bold toggle at the candidate level, revealing
   the official text beneath it. pre-line keeps the text's own paragraph
   breaks without allowing any HTML. */
.proposals { display: flex; flex-direction: column; gap: var(--space-sm); margin: var(--space-sm) 0 var(--space-md); }
.proposal__toggle {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  width: 100%;
  padding: 0;
  background: none;
  border: none;
  font: inherit;
  font-weight: 700;
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
}
.proposal__toggle:hover .proposal__title { text-decoration: underline; }
.proposal__text { margin: var(--space-xs) 0 0 calc(1em + var(--space-sm)); }
.proposal__text[hidden] { display: none; }
.proposal__body { margin: 0; white-space: pre-line; line-height: 1.55; }


/* 5b. CANDIDATE SURVEY (Phase 2) -------------------------------------------
   Only candidates WITH a survey get these classes; Phase 1 candidates use the
   plain .candidate row above, untouched. Layout follows mockup general_02:
   +/− marker left of the name, questions indented beneath in bold, each with
   its own +/− toggle, and the AI-disclosure sentence in italics at the end. */

/* The +/− marker on candidate and question toggles — same look as the race
   rows' marker, so every expandable thing in the tool reads the same way. */
.survey-marker {
  flex: none;
  width: 1em;
  color: var(--color-action);
  font-weight: 700;
}

/* The name/town area becomes a button. Reset button styling so it looks like
   the Phase 1 name line, just with a marker in front. */
.candidate__toggle {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  padding: 0;
  background: none;
  border: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.candidate__toggle:hover .candidate__name { text-decoration: underline; }

/* Candidate photo (decision 2026-10-02, mockup option B): a small round
   portrait between the +/− marker and the name, only for survey candidates
   with a photo. The source images are 100x100, shown at 32px so they stay
   sharp on high-density (retina) screens. In rows WITH a photo, items are
   vertically centered so the name sits at the photo's middle; rows without a
   photo keep the original text alignment. */
.candidate__photo {
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  background: #e3ebee;   /* light tint while the image loads */
}
.candidate__toggle--photo { align-items: center; }

/* The expanded panel: indented to line up with the name (past the marker). */
.survey {
  margin: var(--space-sm) 0 var(--space-xs) calc(1em + var(--space-sm));
  padding-bottom: var(--space-md);
  border-bottom: 1px solid var(--color-border);
}
.survey[hidden] { display: none; }

/* Bio lines ("Age: 42"), styled like the Your Districts list. */
.survey__bio {
  margin: 0 0 var(--space-md);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px var(--space-sm);
  font-size: 0.9rem;
}
.survey__bio-label { color: var(--color-text-muted); }
.survey__bio-label::after { content: ":"; }
.survey__bio-value { margin: 0; }

.survey__questions { display: flex; flex-direction: column; gap: var(--space-sm); }

/* A question: bold, full text, with its own marker. */
.survey__question {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  width: 100%;
  padding: 0;
  background: none;
  border: none;
  font: inherit;
  font-weight: 700;
  line-height: 1.35;
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
}
.survey__question:hover .survey__question-text { text-decoration: underline; }

/* The answer, indented under the question text. pre-line keeps the
   candidate's own paragraph breaks without allowing any HTML. */
.survey__answer { margin: var(--space-xs) 0 0 calc(1em + var(--space-sm)); }
.survey__answer[hidden] { display: none; }
.survey__response { margin: 0; white-space: pre-line; }
.survey__no-response { margin: 0; font-style: italic; color: var(--color-text-muted); }

/* "Show all responses" (decisions 2026-10-02: layout "V3"; link style).
   Looks exactly like the "Expand races / Collapse races" controls — it uses
   their .linklike class — so it reads as a familiar text link rather than a
   new kind of control.
   DESKTOP: a line of its own after the name/website row (flex-basis 100% +
   order 3 push it onto its own line; the website stays on the right).
   PHONES (see below): right under the name, with the website link below it.
   The vertical padding gives a comfortable tap area (and visible space from
   the website link) without changing how it looks. */
.show-all {
  order: 3;
  flex-basis: 100%;
  margin: 0 0 0 calc(1em + var(--space-sm)); /* line up past the +/− */
}
.show-all__btn { padding: 4px 0; }
/* The row's 16px gap is meant for name-to-website spacing; when the link
   wraps onto its own line it would also add 16px ABOVE it. Keep only the
   horizontal gap for these rows, so the link sits just under the name. */
.candidate--expandable { row-gap: 0; }
@media (max-width: 560px) {
  .show-all { order: 0; margin: 2px 0 4px calc(1em + var(--space-sm)); }
}

/* MOBILE: the campaign link stacks under the name (see the Phase 1 mobile
   rule above). For survey candidates, indent it past the +/− marker so it
   lines up with the name instead of the marker. */
@media (max-width: 560px) {
  .candidate--expandable .candidate__link { margin-left: calc(1em + var(--space-sm)); }
}

/* A candidate who got the survey but answered nothing (decision 2026-09-29):
   no toggle, just an italic note beside the town. The row is indented by the
   width of the +/− marker so names still line up with the expandable
   candidates around it; the note wraps under the name on narrow screens. */
.candidate--no-survey { padding-left: calc(1em + var(--space-sm)); }
.candidate--no-survey .candidate__main { flex-wrap: wrap; column-gap: var(--space-sm); }
.candidate__no-survey {
  font-size: 0.85rem;
  font-style: italic;
  color: var(--color-text-muted);
}

/* Candidate- and editor-written text can contain long unbreakable strings —
   a pasted URL in a survey answer, "Principal/Superintendent/Commissioner" —
   which would otherwise push the page wider than a phone screen (found in real
   data, 2026-10-02). Let such strings break wherever needed. */
.survey__response,
.survey__bio-value,
.proposal__body,
.annotations__item { overflow-wrap: anywhere; }

/* The AI-disclosure sentence: standalone, italic, after the questions. */
.survey__ai {
  margin: var(--space-md) 0 0;
  font-style: italic;
  font-size: 0.95rem;
}


/* 6. ACCESSIBLE-VERSION LINK ----------------------------------------------- */
.accessible-link {
  margin-top: var(--space-xl);
  font-size: 0.9rem;
}
.accessible-link a { color: var(--color-link); }
