/* Shared chrome for the four static pages: home, alderpersons, city and
   elections. Everything here was previously copied into each page's inline
   <style>, which is how the nav reorder, the wordmark font and the red footer
   each needed the same edit in four files, and how one specificity bug came to
   exist independently in three.

   Page-specific styles stay inline in each page. Only what is genuinely common
   lives here. */

/* Chicago flag palette: the two light-blue bars and the red six-pointed stars.
   Light only, there is no theme toggle on these pages, and the maps they link
   to open light too. */
:root {
  /* The flag colours are fixed: they are the brand, and they are only ever a
     ground for white text or a border, so neither theme moves them. */
  --flag-blue: #41b6e6;
  --flag-red: #dc0032;
  /* --white is literal white, for text sitting on those two. What used to be
     --white for a surface is --surface, which is the token that flips. */
  --white: #ffffff;

  /* The flag red as TEXT. It cannot be --flag-red in the dark, where #dc0032
     on the dark surface measures 3.40:1 and fails; the dark value is the same
     red lifted with white until it clears AA. --accent-strong is the darker
     variant for small text on a tinted panel. */
  --accent: var(--flag-red);
  --accent-strong: #a8002a;
  --set-label: #0e6f96;

  --ink: #14161a;
  --muted: #5b6068;
  --hairline: #e4e6ea;
  --wash: #f7f8fa;
  --surface: #ffffff;
  --shadow: 0 1px 2px rgb(20 22 26 / 6%), 0 8px 24px rgb(20 22 26 / 6%);
  color-scheme: light;
}

/* Dark, in two places: what the system asks for unless a choice has been
   stored, and what the footer control asks for. Every pair below was measured
   against the surface it lands on, and the lowest of them is 5.18:1.
   The subtle fills are lighter than the page rather than darker, which is the
   only way round that reads as raised on a dark ground. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --accent: #ea6684;
    --accent-strong: #ef8ca3;
    --set-label: #7accee;
    --ink: #e9ebee;
    --muted: #a3a9b4;
    --hairline: #303640;
    --wash: #1d2127;
    --surface: #171a1f;
    --shadow: 0 1px 2px rgb(0 0 0 / 40%), 0 10px 30px rgb(0 0 0 / 45%);
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --accent: #ea6684;
  --accent-strong: #ef8ca3;
  --set-label: #7accee;
  --ink: #e9ebee;
  --muted: #a3a9b4;
  --hairline: #303640;
  --wash: #1d2127;
  --surface: #171a1f;
  --shadow: 0 1px 2px rgb(0 0 0 / 40%), 0 10px 30px rgb(0 0 0 / 45%);
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  /* DM Sans, with the previous system stack as the fallback so the page is
     readable before the webfont lands and if it never does. */
  font-family:
    "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
    sans-serif;
  line-height: 1.55;
  /* A short page (the City directory on its first tab, say) left the red
     footer band floating mid-screen with white below it. The column stretches
     to the viewport and main takes the slack, so the footer sits on the bottom
     edge and the empty space falls between the content and the footer, where
     it belongs. dvh rather than vh so a phone's collapsing toolbar does not
     leave a gap. */
  /* dvh, not vh, so a phone's collapsing toolbar does not leave a gap. */
  min-height: 100dvh;
}

/* Anchors the red band to the bottom of the viewport when a page is shorter
   than the screen, which is what left it floating mid-page with white beneath.
   `position: sticky` with `top: 100vh` does that without giving <body> a new
   formatting context: making body a flex or grid container both re-sized <main>
   to its content's max-content width (928px inside a 320px viewport, because
   .wrap's `margin: 0 auto` disables flex stretch), which killed the horizontal
   scrollers inside and dragged the page sideways. This cannot affect the
   horizontal axis at all. */
body > footer {
  position: sticky;
  top: 100vh;
}

a {
  color: inherit;
}

.wrap {
  max-width: 1040px;
  margin: 0 auto;
  padding: 0 20px;
}

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

header {
  border-bottom: 1px solid var(--hairline);
  background: var(--surface);
}

.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  /* .bar and .wrap are the same element, and this shorthand lands later, so it
     was overriding .wrap's `padding: 0 20px` and putting the header content
     flush against the screen edge. Invisible while the bar centred its
     contents; obvious once the wordmark moved to the left edge. */
  padding: 14px 20px;
}

.wordmark {
  display: flex;
  align-items: center;
  gap: 10px;
  /* 2px top and bottom: the mark and its 22px skyline came to 23px tall, a
     pixel under the 24px minimum for a tap target, on every page. */
  padding: 2px 0;
  text-decoration: none;
}

/* Big Shoulders Text is the typeface chicago.gov sets its headlines in, drawn
   for the city's design system, so the wordmark reads as Chicago rather than
   merely bold. Set in caps via text-transform rather than in the markup, so the
   page still says "Chipoli" to anything reading the text rather than the
   rendering. The fallback stack is deliberately condensed: dropping to a
   normal-width face would change the wordmark's footprint, not just its
   texture. */
.wordmark span {
  font-family: "Big Shoulders Text", "Arial Narrow", -apple-system,
    BlinkMacSystemFont, Helvetica, Arial, sans-serif;
  font-size: 1.42rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  line-height: 1;
  text-transform: uppercase;
}

/* the skyline is wide, so size it by height and let the width follow */
.wordmark img {
  height: 22px;
  width: auto;
  display: block;
}

/* A segmented control: one rounded track holding the five destinations, with
   the current page as a filled pill inside it. */
.tabs {
  position: relative;
  display: flex;
  gap: 2px;
  padding: 4px;
  background: var(--wash);
  border-radius: 999px;
}

/* The pill itself, moved by nav.js. Sized and placed in JS because the tabs
   are five different words: no CSS-only rule knows where the third one
   starts. */
.tabs .thumb {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 0;
  width: 0;
  border-radius: 999px;
  background: var(--flag-red);
  transform: translateX(0);
  pointer-events: none;
}

/* Only once nav.js has placed it, so a stylesheet without its script never
   paints a red bar at the left edge of the track. */
/* 0.28s: long enough to read as movement, short enough that the label the
   pill passes over is only briefly grey on red. */
.tabs[data-thumb] .thumb {
  transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1),
    width 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}

@media (prefers-reduced-motion: reduce) {
  .tabs[data-thumb] .thumb,
  .views[data-thumb] .thumb,
  .views[data-thumb] a {
    transition: none;
  }
}

/* The party badge that sits beside a name. Only ever shown where the office
   records one: Chicago's own elections are nonpartisan by law, so no
   alderperson, no citywide office and no school board seat carries a party,
   and none of those pages show a badge rather than guessing at one.

   An <abbr> rather than a <span>, because "D" is an abbreviation and the
   title is its expansion, which is what a screen reader and a long press both
   want. */
.party {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid var(--hairline);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  vertical-align: middle;
  white-space: nowrap;
}

.party--d {
  border-color: var(--flag-blue);
  color: var(--set-label);
}

.party--r {
  border-color: var(--flag-red);
  color: var(--accent-strong);
}

/* The City section's own nav: Government, Finance and the meetings calendar.
   Links rather than buttons, because each is a real URL; /city upgrades the
   two that are itself into an in page switch, and the calendar navigates. It
   lives here rather than in either page because both pages carry it and
   scripts/build-chrome.mjs syncs the one copy into them. */
.views {
  position: relative;
  display: inline-flex;
  gap: 4px;
  margin: 0 0 24px;
  padding: 4px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--wash);
}

/* The same pill as the header's, on the same track geometry. It slides
   between Government and Finance without a page load, and is handed across
   the navigation to and from the calendar the way the header's is. */
.views .thumb {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 0;
  width: 0;
  border-radius: 999px;
  background: var(--flag-red);
  transform: translateX(0);
  pointer-events: none;
}

.views[data-thumb] .thumb {
  transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1),
    width 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}

.views a {
  position: relative;
  padding: 7px 18px;
  border-radius: 999px;
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}

/* In step with the pill, and only once the pill exists. Switching the two
   labels the instant a section is picked left the one being left as grey on
   red and the one arriving as white on grey for the length of the slide;
   fading them on the same curve, the colour is always where the pill is. */
.views[data-thumb] a {
  transition: color 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}

.views a:hover {
  color: var(--ink);
}

.views a:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.views a[aria-current="page"] {
  background: var(--flag-red);
  color: var(--white);
}

/* Once the pill is placed it carries the red instead, so the two are never
   both painted. */
.views[data-thumb] a[aria-current="page"] {
  background: none;
}

.tabs a {
  position: relative;
  padding: 8px 15px;
  border-radius: 999px;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
}

/* Wide enough for words: the icon is redundant, so it is not rendered. */
.tabs a svg {
  display: none;
  width: 22px;
  height: 22px;
}

.menu-btn {
  display: none;
  appearance: none;
  border: 1px solid var(--hairline);
  border-radius: 9px;
  background: var(--surface);
  color: var(--ink);
  width: 40px;
  height: 38px;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}

.menu-btn svg { width: 20px; height: 20px; }
.menu-btn .cross { display: none; }
.menu-btn[aria-expanded="true"] .bars { display: none; }
.menu-btn[aria-expanded="true"] .cross { display: block; }

.tabs a:hover {
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  color: var(--ink);
}

/* White on --flag-red is 5.14:1, which clears AA. The background here is the
   no-script state: nav.js swaps it for the thumb, which is the same red in
   the same place, so nothing moves when the script takes over. */
.tabs a[aria-current="page"] {
  background: var(--flag-red);
  color: var(--white);
}

.tabs a[aria-current="page"]:hover {
  background: var(--flag-red);
}

.tabs[data-thumb] a[aria-current="page"] {
  background: none;
}

.tabs[data-thumb] a[aria-current="page"]:hover {
  background: none;
}

/* Ink rather than red: a red ring on the red pill is invisible. */
.tabs a:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* A red band closes every page, picking up the skyline mark's colour. White on
   --flag-red measures 5.14:1, which clears AA for body text. */
footer {
  background: var(--flag-red);
  color: #fff;
  padding: 0 0 26px;
  font-size: 0.85rem;
  /* flow-root, so the lookup card's negative top margin lifts the card out of
     the band. Without it that margin collapses through to <footer> itself and
     drags the whole red band up over the page's last section. */
  display: flow-root;
}

footer p {
  margin: 0;
}

/* ---------- the lookup card, lifted over the top of the band ---------- */

/* 44px of a roughly 200px card sits above the fold line, which is what makes
   it read as attached to the footer rather than as one more section above it.
   main.wrap reserves 56px below its content, so the lift never reaches the
   page's own text. The margin is set on .wrap rather than on the card because
   .wrap's `margin: 0 auto` shorthand would otherwise reset it. */
footer .foot-cta-wrap {
  margin-top: -44px;
  margin-bottom: 36px;
}

/* Same light blue ground and plain blue border as the ballot panel, so the two
   callouts on the site are one component rather than two. */
footer .foot-cta {
  padding: 26px 24px 28px;
  background: color-mix(in srgb, var(--flag-blue) 15%, var(--surface));
  border: 2px solid var(--flag-blue);
  border-radius: 18px;
  color: var(--ink);
  text-align: center;
}

/* The widget carries its own 56px band for the pages it used to sit on alone;
   inside the card the card's padding is the spacing. */
footer .foot-cta #find-reps {
  padding: 0;
}

/* ---------- the columns ---------- */

footer .foot-grid {
  display: grid;
  grid-template-columns: auto repeat(4, minmax(0, 1fr));
  gap: 30px 36px;
  align-items: start;
  text-align: left;
}

/* Stacked rather than side by side, unlike the header: the footer mark sits
   at the head of a column of columns, and a wide horizontal lockup pushed the
   first link column away from it. */
footer .foot-mark {
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: #fff;
  align-self: start;
}

footer .foot-mark img { height: 34px; }
footer .foot-mark span { font-size: 1.7rem; }

footer .foot-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Pure white, not a muted white: on --flag-red white measures 5.14:1 and
   anything softer drops under AA. These read as labels through case, size and
   letter-spacing instead of through colour. */
footer .foot-col h2 {
  margin: 0 0 10px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #fff;
}

/* Padding, not line-height: it is what makes each link a 24px tap target
   rather than a 17px line of text. */
footer .foot-col a {
  padding: 5px 2px;
  text-decoration: none;
}

footer .foot-col a:hover,
footer .foot-col a:focus-visible {
  text-decoration: underline;
}

/* The closing row: copyright and the theme control, on one line where there
   is room and stacked where there is not. A bar rather than a column, so it
   spans the band edge to edge instead of lining up with the link columns, and
   it carries its own side padding rather than .wrap's, whose auto margins this
   rule's own margin used to cancel. */
footer .foot-end {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 20px;
  margin: 30px 0 0;
  padding: 0 20px;
}

footer .foot-legal {
  margin: 0;
  font-size: 0.8rem;
}

/* The same segmented track as the header nav, in the band's own colours: a
   translucent white track, and the current theme as a solid white pill with
   red on it. White on --flag-red and --flag-red on white are both 5.14:1. */
footer .theme {
  display: flex;
  gap: 2px;
  padding: 3px;
  background: rgb(0 0 0 / 16%);
  border-radius: 999px;
}

footer .theme button {
  appearance: none;
  padding: 6px 14px;
  border: 0;
  border-radius: 999px;
  background: none;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 700;
  color: #fff;
  cursor: pointer;
}

footer .theme button[aria-pressed="true"] {
  background: var(--white);
  color: var(--flag-red);
}

footer .theme button:focus-visible {
  outline: 2px solid var(--white);
  outline-offset: 2px;
}

@media (max-width: 520px) {
  footer .foot-end {
    justify-content: center;
  }
}

/* Four columns need about 860px. Below that the mark takes a row of its own
   above a 2-up grid, and below 520px everything stacks. */
@media (max-width: 860px) {
  footer .foot-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  footer .foot-mark {
    grid-column: 1 / -1;
  }
}

/* Stacked in one column, so centred: a single left-aligned column against
   the full width of a phone screen reads as a mistake rather than as a grid
   that ran out of room. */
@media (max-width: 520px) {
  footer .foot-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 26px;
    justify-items: center;
    text-align: center;
  }

  footer .foot-col {
    align-items: center;
  }
}

footer a {
  color: #fff;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Below 720px the tabs move into a menu: wordmark on the left, button on the
   right, and the links drop down beneath the bar. Five icon-only tabs did fit,
   but a labelled list is easier to read and easier to hit than five glyphs.
   720 rather than the 600 this used to be: the segmented track is wider than
   five bare words, and between 600 and 700 it pushed past the wordmark and
   scrolled the page sideways. */
@media (max-width: 720px) {
  header {
    position: relative;
    /* The drawer is absolutely positioned inside the header, and without a
       z-index here it was only winning against unpositioned content. On the
       homepage .hero is `position: relative` for the flag stripes and comes
       later in the DOM, so at z-index auto it painted over the open menu: the
       drawer looked transparent and its links were not clickable. 50 clears
       the only other z-index on these pages, #results at 20. */
    z-index: 50;
  }

  .menu-btn {
    display: flex;
    flex: none;
  }

  .bar nav.tabs {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 2px;
    /* the segmented track is for a row of tabs; in a vertical drawer it would
       be a grey slab behind the whole menu */
    padding: 8px 14px 14px;
    background: var(--surface);
    border-radius: 0;
    border-bottom: 1px solid var(--hairline);
    box-shadow: var(--shadow);
  }

  .bar nav.tabs[data-open] {
    display: flex;
  }

  /* A vertical list: the thumb only knows how to slide sideways, so the row
     goes back to carrying its own background. */
  .bar nav.tabs .thumb {
    display: none;
  }

  .bar nav.tabs[data-thumb] a[aria-current="page"],
  .bar nav.tabs[data-thumb] a[aria-current="page"]:hover {
    background: var(--flag-red);
  }

  /* A row in the drawer rather than a tab in a track, but the current page is
     still the filled pill it is on the bar. */
  .bar nav.tabs a {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 11px 14px;
    border-radius: 999px;
    font-size: 1rem;
  }

  .bar nav.tabs a[aria-current="page"] {
    background: var(--flag-red);
    color: var(--white);
  }

  .bar nav.tabs a svg {
    display: block;
  }

  /* the label comes back: in a drawer there is room for the word */
  .bar nav.tabs a span {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    clip-path: none;
  }
}

/* "Last updated" under the heading on the sourced pages, added by
   /updated.js. Pulled up toward the heading it qualifies. */
.page-updated {
  margin: -0.35rem 0 1rem;
  font-size: 0.8rem;
  color: var(--muted);
}
