/* ==========================================================================
   STYLES — layout and components. Values come from tokens.css.
   ========================================================================== */

/* --- Base / reset --- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

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

img { max-width: 100%; height: auto; display: block; }

h1, h2, h3 { font-family: var(--font-heading); line-height: 1.2; margin: 0 0 var(--space-sm); }
h1 { font-size: var(--font-size-h1); }
h2 { font-size: var(--font-size-h2); }
h3 { font-size: var(--font-size-h3); }
p  { margin: 0 0 var(--space-sm); }

a { color: var(--color-primary); text-underline-offset: 0.15em; }
a:hover { color: var(--color-primary-dark); }

/* Visible keyboard focus everywhere */
:focus-visible {
  outline: 3px solid var(--color-highlight);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}

/* --- Accessibility helpers --- */
.skip-link {
  position: absolute;
  left: var(--space-sm);
  top: -10rem;
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-highlight);
  color: var(--color-text);
  font-weight: 700;
  z-index: 100;
}
.skip-link:focus { top: var(--space-sm); }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* --- Layout --- */
.container {
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--space-md);
}

.section { padding-block: var(--space-lg); }
.section--alt { background: var(--color-surface); }
.section--candidates { background: var(--candidates-bg); }

/* --- Header --- */
.site-header {
  position: sticky;                /* stays pinned to the top while scrolling */
  top: 0;
  z-index: 10;
  background: var(--header-bg);
  color: var(--header-text);
  box-shadow: 0 2px 8px rgb(0 0 0 / 0.25);
}
/* Keep in-page jumps (like "Skip to main content") from hiding under the sticky header */
html { scroll-padding-top: 5rem; }
.site-header .container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding-block: var(--space-sm);
}
.site-logo {
  color: inherit;
  font-weight: 800;
  font-size: 1.375rem;
  text-decoration: none;
}

/* --- Hero (above the fold): text + call to action beside the district map --- */
.hero {
  background: linear-gradient(135deg, var(--hero-bg-start), var(--hero-bg-end));
  color: var(--hero-text);
  padding-block: var(--space-lg);
}
/* Hero spans --hero-width of the window (set in tokens.css) instead of the normal container */
.hero .container { max-width: var(--hero-width); padding-inline: 0; }
.hero__layout { display: grid; gap: var(--space-lg); align-items: center; }
/* Stacked (phones / narrow windows): headline, then the map, then the text, then the button */
@media (max-width: 59.99rem) {
  .hero__layout { gap: 0; }
  .hero__text { display: contents; }       /* lets the map slot in between the headline and the text */
  .hero__map { order: 1; margin-block: var(--space-xs) var(--space-md); }
  .hero__text > p { order: 2; }
  .hero-cta { order: 3; justify-self: start; }
}
@media (min-width: 60rem) {
  /* Side by side: both columns share one height, so the map panel's top lines up with the
     headline and its bottom with the bottom of the call-to-action button */
  .hero__layout { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: stretch; }
  .hero__text { display: flex; flex-direction: column; }
  .hero__text .hero-cta { margin-top: auto; }
  .hero__text > p:last-of-type { margin-bottom: var(--space-sm); }
  .hero__map { display: flex; flex-direction: column; }
  .hero__map .district-map { margin-block: auto; }   /* map centered in the panel, credit at the bottom */
}
.hero h1 { font-weight: 500; font-size: clamp(2rem, 3.3vw, 3.25rem); }  /* scales with the half-width column */
.hero h1 strong { font-weight: 800; }
.hero p { font-size: 1.125rem; }

/* The big "donate to all" call to action (colors in tokens.css: --cta-*) */
.hero-cta {
  display: inline-block;
  align-self: flex-start;       /* sized to its text, lined up with the paragraphs */
  max-width: 100%;
  margin-top: var(--space-xs);
  padding: 0.875rem 1.75rem;
  border-radius: 0.75rem;
  background: linear-gradient(180deg, var(--cta-bg-start), var(--cta-bg-end));
  color: var(--cta-text);
  font-size: clamp(1.125rem, 1.4vw, 1.5rem);
  font-weight: 800;
  line-height: 1.3;
  letter-spacing: 0.04em;
  text-align: center;
  text-transform: uppercase;    /* shown in all caps; the HTML text stays normal case for screen readers */
  text-decoration: none;
  /* depth: a darker "edge" under the button plus a soft drop shadow */
  box-shadow: 0 6px 0 var(--cta-edge), 0 10px 18px rgb(0 0 0 / 0.35);
  transition: transform 0.12s, box-shadow 0.12s;
}
.hero-cta:hover,
.hero-cta:focus-visible {
  color: var(--cta-text);
  transform: translateY(-2px);
  box-shadow: 0 8px 0 var(--cta-edge), 0 14px 22px rgb(0 0 0 / 0.38);
}
.hero-cta:active {               /* pressed: sinks onto its edge */
  transform: translateY(5px);
  box-shadow: 0 1px 0 var(--cta-edge), 0 3px 8px rgb(0 0 0 / 0.3);
}

/* Map panel in the hero: light background so district colors read clearly */
.hero__map {
  padding: var(--space-md);
  border-radius: var(--radius);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: 0 4px 14px rgb(0 0 0 / 0.25);
}
.hero__map .district-map { margin-inline: auto; }
.hero__map p { font-size: 1rem; }               /* undo the larger intro-paragraph size */
.hero__map .map-credit { font-size: 0.75rem; }

/* --- Buttons --- */
.button {
  display: inline-block;
  padding: 0.75rem 1.5rem;
  border-radius: var(--radius);
  background: var(--color-primary);
  color: var(--color-on-primary);
  font-weight: 700;
  text-decoration: none;
  border: 2px solid transparent;
}
.button:hover { background: var(--color-primary-dark); color: var(--color-on-primary); }
.button--light { background: var(--color-surface); color: var(--color-primary-dark); }
.button--light:hover { background: var(--color-bg); color: var(--color-primary-dark); }

/* --- Cards & grids --- */
.grid {
  display: grid;
  gap: var(--space-md);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
}

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--space-md);
}

/* --- Candidate cards --- */
.candidate-card__bio { font-size: 1rem; }
.candidate-card__donate {
  display: inline-block;
  align-self: flex-start;
  margin-bottom: var(--space-sm);
  padding: 0.625rem 1.5rem;
  border-radius: 999px;
  background: var(--color-donate);
  color: var(--color-on-primary);
  font-weight: 700;
  text-decoration: none;
  transition: background 0.15s;
}
.candidate-card__donate:hover,
.candidate-card__donate:focus-visible {
  background: var(--color-donate-hover);
  color: var(--color-on-primary);
}

.candidate-card { overflow: hidden; display: flex; flex-direction: column; }
/* Full-width photo at the top of the card, cropped square around the face.
   Adjust a single photo's crop with "photoPosition" in districts.json. */
.candidate-card__photo-frame {
  display: block;
  width: calc(100% + 2 * var(--space-md));
  margin: calc(-1 * var(--space-md)) calc(-1 * var(--space-md)) var(--space-md);
}
.candidate-card__photo {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: center 20%;
}
.candidate-card__photo--placeholder {
  display: grid;
  place-items: center;
  background: var(--map-featured);
  color: var(--color-primary-dark);
  font-size: 4rem;
  font-weight: 800;
}
.candidate-card h3 { margin-bottom: var(--space-xs); }
/* Candidate names link to their campaign site but look like plain headings (no hover change) */
.candidate-card h3 a,
.candidate-card h3 a:hover { color: inherit; text-decoration: none; }
.candidate-card__district {
  font-weight: 700;
  padding-top: var(--space-xs);
  border-top: 1px solid var(--color-border);
}
/* --- Footer --- */
.site-footer {
  background: var(--footer-bg);
  color: var(--footer-text);
  padding-block: var(--space-lg);
  font-size: 0.95rem;
}
.site-footer a { color: inherit; }

/* --- District map --- */
.district-map svg { width: 100%; height: auto; display: block; }
.district-map path {
  fill: var(--map-fill);
  stroke: var(--map-border);
  stroke-width: 0.8;
  stroke-linejoin: round;
  transition: fill 0.15s;
}
.district-map path.is-featured { fill: var(--map-featured); cursor: pointer; }
.district-map path.is-flashing { fill: var(--map-flash); }  /* hover and selected below still win */
.district-map path.is-fading { transition: fill var(--map-fade, 1s) ease-in-out; }  /* slow fade for the flash only */
.district-map path.is-featured:hover,   /* only candidate districts react to hover */
.district-map path.is-featured:focus-visible { fill: var(--map-hover); }
.district-map path.is-selected { fill: var(--map-selected); }
.district-map path:focus-visible { outline: none; stroke: var(--color-highlight); stroke-width: 3; }
.district-map__labels text {
  font: 700 14px var(--font-body);
  fill: var(--color-text);
  text-anchor: middle;
  dominant-baseline: central;
  pointer-events: none;
  paint-order: stroke;
  stroke: var(--color-surface);
  stroke-width: 3px;
}
.district-map { position: relative; width: 100%; max-width: var(--map-max-width); }
/* Mini profile that pops up beside each flashing district (js: MAP_FLASH.showPeek) */
.map-peek {
  position: absolute;
  z-index: 2;
  max-width: 15rem;
  padding: 0.375rem 0.625rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  box-shadow: var(--shadow);
  font-size: 0.85rem;
  line-height: 1.2;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--map-fade, 1s) ease-in-out;
}
.map-peek.is-visible { opacity: 1; }
.map-peek.is-quick { transition-duration: 0.15s; }  /* hover and clicks: fast fade */
.map-peek__ld { padding-right: 1.5rem; }          /* room for the close button */
.map-peek__close {
  position: absolute;
  top: 0.125rem;
  right: 0.25rem;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--color-donate);
  font: 600 1.5rem/1 system-ui, -apple-system, "Segoe UI", Arial, sans-serif;  /* Josefin draws × very small */
  cursor: pointer;
  pointer-events: auto;                            /* the rest of the pop-up ignores the mouse */
}
.map-peek__close:hover { background: rgb(197 61 61 / 0.12); color: var(--color-donate-hover); }
.map-peek:not(.is-visible) .map-peek__close { pointer-events: none; }  /* not clickable while hidden */
.map-peek__ld {
  margin: 0 0 0.25rem;
  color: var(--color-text-muted);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.05em;
}
.map-peek__row { display: flex; align-items: center; gap: 0.4rem; font-weight: 700; white-space: nowrap; }
.map-peek__row + .map-peek__row { margin-top: 0.25rem; }
.map-peek__race + .map-peek__race {            /* districts with two races: a thin divider between them */
  margin-top: 0.375rem;
  padding-top: 0.375rem;
  border-top: 1px solid var(--color-border);
}
.map-peek__row--opponent { font-weight: 500; color: var(--color-text-muted); }
.map-peek__avatar {                              /* grey placeholder circle for the Republican */
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  flex: none;
  border-radius: 999px;
  background: #c4c9d1;
  color: #ffffff;
  font-size: 0.75rem;
  font-weight: 800;
}
.map-peek__text { display: flex; flex-direction: column; }
.map-peek__result { color: var(--color-text-muted); font-size: 0.75rem; font-weight: 500; }
.map-peek__row img { width: 1.75rem; height: 1.75rem; flex: none; border-radius: 999px; object-fit: cover; object-position: center 20%; }
.map-credit { margin: var(--space-sm) 0 0; color: var(--color-text-muted); font-size: 0.75rem; }

/* --- Candidate carousel (phones only) ---
   Wider screens: a normal grid, with the arrows and counter hidden.
   Narrow screens: one card at a time, swipe or use the arrows in the margins. */
.carousel__arrow,
.carousel__counter { display: none; }

@media (max-width: 40rem) {
  .section { padding-block: var(--space-md); }   /* less vertical padding between sections on phones */
  .section--candidates .container { padding-inline: var(--space-xs); }
  .carousel {
    display: grid;
    grid-template-columns: 2.25rem minmax(0, 1fr) 2.25rem;
    column-gap: 0.25rem;
  }
  .carousel__track {
    display: flex;
    gap: var(--space-sm);
    overflow-x: auto;
    overflow-y: hidden;               /* height is set by script to fit the current card */
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    align-items: start;
  }
  .carousel__track::-webkit-scrollbar { display: none; }
  .carousel__track > .card { flex: 0 0 100%; scroll-snap-align: start; }
  .carousel__arrow {
    display: grid;
    place-items: center;
    align-self: start;
    position: sticky;                 /* arrows stay in view while reading a long bio */
    top: calc(50vh - 1.125rem);
    width: 2.25rem;
    height: 2.25rem;
    border: 0;
    border-radius: 999px;
    background: var(--color-primary);
    color: var(--color-on-primary);
    font: 700 1.75rem/1 var(--font-body);
    cursor: pointer;
  }
  .carousel__arrow:disabled { opacity: 0.3; cursor: default; }
  .carousel__counter {
    display: block;
    grid-column: 1 / -1;
    margin: var(--space-sm) 0 0;
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.95rem;
  }
}
