/* ── The next-city vote (/vote) ──────────────────────────────────────────
   Dark ink scope like the landing page: tokens.css + base.css + landing.css
   carry the palette, buttons, forms and the paper card; this file adds the
   page's own pieces — the map stage, the stats strip, the board, the live
   feed, the prize, the FAQ and the two dialogs. The vote card (its panels,
   the picker, the checklist, the favorites board) lives in vote-card.css,
   which /vote loads beside this file. No new palette.

   The map is the page's main view (PRD-28 §2.1a). On a phone the page is one
   column: the hero, the map full-bleed under it, and the cards riding up
   over the map's bottom edge. From 960px the map holds the left side,
   sticky under the site header, while the column on the right scrolls. */

.vote-body {
  display: block;
  padding: calc(var(--site-header-h) + clamp(1rem, 4vh, 2.5rem)) 0 2.5rem;
}

.vote-page {
  --vote-gutter: 1rem;
  /* How far the cards ride up over the map's bottom edge on a phone. */
  --stage-overlap: 2rem;
  display: block;
  max-width: none;
  width: 100%;
  text-align: left;
}

.vote-column {
  position: relative;
  z-index: 1;
  max-width: 40rem;
  margin: calc(-1 * var(--stage-overlap)) auto 0;
  padding: 0 var(--vote-gutter);
}

.vote-column > section {
  width: 100%;
}

/* The app-download block closes the scrolling column, above the grid
   footer. landing.css styles its badges; the column gives it its width
   and rhythm. */
.vote-column > .app-block {
  width: 100%;
  margin-top: 2.25rem;
  text-align: center;
}

.vote-page > .site-footer {
  max-width: 40rem;
  margin: 3rem auto 0;
  padding: 0 var(--vote-gutter);
}

/* ── Hero: the homepage's old one (PRD-59 §4) ──────────────────────────
   One column below 880 px (text, then tally), 7/5 from 880 px. The tally
   is the old homepage's card on its data-tally-* hooks; its text reads
   --page-ink rather than --paper, so it survives the light page ground.
   The tally's total line is the page's one count of the numbers. */

.vote-hero {
  margin: 0 0 1.25rem;
  padding: 0 var(--vote-gutter);
  text-align: center;
}

.vote-hero-grid {
  display: grid;
  gap: 2rem;
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
  max-width: 64rem;
  margin: 0 auto;
}

.vote-hero-text {
  min-width: 0;
}

.vote-hero-eyebrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin: 0 0 0.8rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-text);
}

.pulse-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse-dot 2s ease-in-out infinite;
}

@keyframes pulse-dot {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
}

.vote-hero h1 {
  margin: 0.4rem 0 0.75rem;
  font-size: clamp(1.75rem, 6vw, 2.8rem);
  line-height: 1.1;
}

.vote-hero h1 .accent {
  color: var(--accent-text);
}

.vote-lede {
  max-width: 36rem;
  margin: 0 auto 1rem;
}

.vote-referrer {
  margin: -0.5rem 0 1rem;
  color: var(--accent-text);
  font-weight: 600;
}

.vote-hero-cta {
  min-width: 14rem;
}

/* The live tally. The rows reserve their height, so the board arriving
   moves nothing. Row classes are the leaderboard's (.board-* above), with
   the card-in-card flattened back to plain rows. */

.tally {
  min-width: 0;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: 1.1rem 1.25rem;
  min-height: 19rem;
  text-align: left;
}

.tally-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  margin-bottom: 0.35rem;
}

.tally-head h2 {
  margin: 0;
  font-size: 1.05rem;
}

.tally-live {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.tally-live .live-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--brand-green);
  animation: pulse-dot 2s ease-in-out infinite;
}

#tally-total {
  margin: 0 0 0.8rem;
  color: var(--muted);
  font-size: 0.9rem;
}

#tally-total strong {
  color: var(--page-ink);
  font-size: 1.15rem;
}

.tally-empty {
  margin: 0;
  color: var(--muted);
}

.tally .board {
  min-height: 9rem;
}

.tally .board-row {
  padding: 0;
  border: 0;
  background: transparent;
  grid-template-columns: 2.2rem minmax(0, 1fr) auto;
  column-gap: 0.6rem;
}

.tally .board-rank {
  font-family: var(--font-mono);
  font-size: 0.8rem;
}

.tally .board-city {
  font-size: 0.92rem;
  color: var(--page-ink);
}

.tally .board-votes {
  font-size: 0.85rem;
  color: var(--page-ink);
  font-variant-numeric: tabular-nums;
}

.tally .board-bar {
  height: 4px;
  margin-top: 0.3rem;
  background: var(--line-soft);
}

.tally .board-bar i {
  background: var(--accent);
}

.tally .board-delta {
  display: none;
}

.tally .board-row--mine {
  box-shadow: none;
}

.tally .board-row--mine .board-city,
.tally .board-row--mine .board-votes,
.tally .board-row--mine .board-rank {
  color: var(--accent-text);
}

.tally-foot {
  margin: 0.9rem 0 0.3rem;
  font-size: 0.82rem;
  color: var(--muted);
}

.tally-more {
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--page-ink);
}

@media (min-width: 880px) {
  .vote-hero {
    text-align: left;
  }

  .vote-hero-grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  }

  .vote-hero-eyebrow {
    justify-content: flex-start;
  }

  .vote-lede {
    margin: 0 0 1rem;
  }
}

/* ── The map stage ───────────────────────────────────────────────────── */

/* z-index 0 keeps MapLibre's own layers (its controls sit at z-index 2)
   inside the stage, under the cards that overlap it. */
.vote-stage {
  position: relative;
  z-index: 0;
  height: clamp(320px, 58vh, 560px);
  background: var(--map-land);
  border-block: 1px solid var(--line-soft);
  overflow: hidden;
}

/* The strip the cards cover is no place for the attribution. */
.vote-stage .maplibregl-ctrl-bottom-left,
.vote-stage .maplibregl-ctrl-bottom-right {
  bottom: var(--stage-overlap);
}

.vote-map {
  position: absolute;
  inset: 0;
}

/* The toolbar floats over the map's top left; the zoom buttons own the
   right. Pointer events pass through its empty space to the map. */
.map-toolbar {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  right: 3.75rem;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.5rem;
  pointer-events: none;
}

.map-toolbar > * {
  pointer-events: auto;
}

.map-views {
  display: inline-flex;
  padding: 3px;
  border-radius: 999px;
  background: rgba(1, 11, 27, 0.86);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-pop);
}

.map-views[hidden] {
  display: none;
}

.map-view {
  min-height: 36px;
  max-width: 12rem;
  padding: 0.35rem 0.9rem;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background 150ms ease,
    color 150ms ease;
}

.map-view:hover {
  color: var(--paper);
}

.map-view[aria-pressed="true"] {
  background: var(--accent);
  color: var(--ink);
}

.map-view:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 2px;
}

.map-chip {
  margin: 0;
  padding: 0.4rem 0.75rem;
  border-radius: 999px;
  background: rgba(1, 11, 27, 0.86);
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 600;
}

.map-chip[hidden] {
  display: none;
}

/* A view with nothing on it yet says so, low over the map. */
.map-note {
  position: absolute;
  left: 50%;
  bottom: calc(var(--stage-overlap) + 2.25rem);
  z-index: 2;
  width: max-content;
  max-width: calc(100% - 2rem);
  margin: 0;
  padding: 0.6rem 0.9rem;
  transform: translateX(-50%);
  border-radius: var(--r-control);
  background: rgba(1, 11, 27, 0.9);
  border: 1px solid var(--line);
  color: var(--paper);
  font-size: 0.85rem;
  font-weight: 600;
  text-align: center;
  text-wrap: balance;
}

.map-note[hidden] {
  display: none;
}

/* MapLibre's own controls, in the night scope. */
.vote-map .maplibregl-ctrl-group {
  background: var(--card);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-pop);
}

.vote-map .maplibregl-ctrl-group button + button {
  border-top-color: var(--line);
}

.vote-map .maplibregl-ctrl-group button .maplibregl-ctrl-icon {
  filter: invert(1);
}

.vote-map .maplibregl-ctrl-attrib {
  background: rgba(1, 11, 27, 0.8);
  color: var(--muted);
}

.vote-map .maplibregl-ctrl-attrib a {
  color: var(--muted);
}

.vote-map .maplibregl-ctrl-attrib-button {
  filter: invert(1);
  background-color: transparent;
}

.vote-map .maplibregl-cooperative-gesture-screen {
  background: rgba(1, 11, 27, 0.72);
  color: var(--paper);
  font-size: 1rem;
  font-weight: 600;
}

@media (min-width: 960px) {
  .vote-body {
    padding: var(--site-header-h) 0 0;
  }

  .vote-page {
    --vote-gutter: 2rem;
    --stage-overlap: 0px;
    --vote-col: clamp(25rem, 36vw, 33rem);
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--vote-col);
    grid-template-rows: auto 1fr auto;
    align-items: start;
    min-height: calc(100dvh - var(--site-header-h));
  }

  /* The hero is a full-width band above the sticky-map grid. */
  .vote-hero {
    grid-column: 1 / -1;
    grid-row: 1;
    max-width: none;
    margin: 0;
    padding: 2rem var(--vote-gutter);
  }

  .vote-hero h1 {
    font-size: clamp(1.9rem, 2.6vw, 2.4rem);
  }

  /* Every row, footer included: a sticky grid item sticks for the length of
     its grid container, not its own area, so the footer lives beside the
     map rather than under it, and the map never scrolls away. */
  .vote-stage {
    grid-column: 1;
    grid-row: 2 / -1;
    position: sticky;
    top: var(--site-header-h);
    height: calc(100dvh - var(--site-header-h));
    border-block: 0;
    border-right: 1px solid var(--line-soft);
  }

  .vote-column {
    grid-column: 2;
    grid-row: 2;
    max-width: none;
    margin: 0;
    padding: 0.25rem var(--vote-gutter) 2.5rem;
  }

  .vote-page > .site-footer {
    grid-column: 2;
    grid-row: 3;
    max-width: none;
    margin: 0;
    padding: 1.5rem var(--vote-gutter) 2rem;
    border-top: 1px solid var(--line-soft);
    text-align: left;
  }

  .map-toolbar {
    top: 1rem;
    left: 1rem;
  }

  /* No WebGL, or the basemap failed: the column takes the page back. */
  .vote-page:has(> .vote-stage[hidden]) {
    grid-template-columns: minmax(0, 40rem);
    justify-content: center;
  }

  .vote-page:has(> .vote-stage[hidden]) > * {
    grid-column: 1;
  }

  .vote-page:has(> .vote-stage[hidden]) > .vote-column {
    grid-row: 2;
  }
}

/* No map on a phone either: the cards stop reaching up for it. */
.vote-page:has(> .vote-stage[hidden]) > .vote-column {
  margin-top: 0;
}

/* ── Sections ────────────────────────────────────────────────────────── */

.vote-section {
  margin: 2.25rem 0 0;
}

.vote-section h2,
.vote-card h2,
.picks-card h2 {
  margin: 0.25rem 0 0.75rem;
  font-size: 1.4rem;
}

.vote-section-lede {
  color: var(--muted);
  margin: 0 0 0.75rem;
}



/* ── The board ───────────────────────────────────────────────────────── */

.board {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.6rem;
}

.board-row {
  display: grid;
  grid-template-columns: 2.6rem minmax(0, 1fr) auto;
  grid-template-areas:
    "rank main votes"
    "rank main delta";
  align-items: center;
  column-gap: 0.75rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-control);
  background: var(--card);
}

.board-row--mine {
  border-color: var(--accent);
  box-shadow: inset 3px 0 0 var(--accent);
}

.board-rank {
  grid-area: rank;
  font-weight: 800;
  color: var(--muted);
}

.board-row--mine .board-rank {
  color: var(--accent);
}

.board-main {
  grid-area: main;
  min-width: 0;
}

.board-city {
  display: block;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.board-bar {
  height: 6px;
  margin-top: 0.4rem;
  border-radius: 999px;
  background: var(--well);
  overflow: hidden;
}

.board-bar i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--info);
  transition: width 400ms ease;
}

.board-row--mine .board-bar i {
  background: var(--accent);
}

.board-votes {
  grid-area: votes;
  font-weight: 700;
  text-align: right;
  white-space: nowrap;
}

.board-delta {
  grid-area: delta;
  font-size: 0.75rem;
  color: var(--muted);
  text-align: right;
  white-space: nowrap;
}

.board-more {
  margin-top: 0.75rem;
  color: var(--paper);
}

/* ── Map popups (a dot's city, a pin's place) ────────────────────────── */

.vote-popup .maplibregl-popup-content {
  background: var(--card);
  color: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 0.55rem 0.8rem;
  font-size: 0.85rem;
  font-weight: 600;
  box-shadow: var(--shadow-pop);
}

.vote-popup .maplibregl-popup-close-button {
  color: var(--muted);
  font-size: 1.1rem;
  padding: 0 0.4rem;
}

.vote-popup.maplibregl-popup-anchor-bottom .maplibregl-popup-tip {
  border-top-color: var(--card);
}

.vote-popup.maplibregl-popup-anchor-top .maplibregl-popup-tip {
  border-bottom-color: var(--card);
}

.vote-popup.maplibregl-popup-anchor-left .maplibregl-popup-tip {
  border-right-color: var(--card);
}

.vote-popup.maplibregl-popup-anchor-right .maplibregl-popup-tip {
  border-left-color: var(--card);
}

.vote-popup-body {
  display: grid;
  gap: 0.2rem;
  padding-right: 1rem;
}

.vote-popup-title {
  font-size: 0.95rem;
}

.vote-popup-line {
  color: var(--muted);
  font-weight: 500;
}

.vote-popup-btn {
  justify-self: start;
  margin-top: 0.4rem;
  padding: 0.4rem 0.75rem;
  border: 0;
  border-radius: var(--r-control);
  background: var(--accent);
  color: var(--ink);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}

.vote-popup-btn:hover {
  background: var(--accent-soft);
}

.vote-popup-btn:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 2px;
}

/* A favorite place's pin: its vote count in a disc; yours in the accent. */
.pin {
  display: grid;
  place-items: center;
  min-width: 30px;
  height: 30px;
  padding: 0 0.4rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--info);
  color: var(--ink);
  font: inherit;
  font-size: 0.78rem;
  font-weight: 800;
  line-height: 1;
  box-shadow: 0 4px 12px -2px rgba(1, 11, 27, 0.6);
  cursor: pointer;
  transition: transform 150ms ease;
}

.pin--mine {
  background: var(--accent);
}

.pin:hover,
.pin--active {
  transform: scale(1.18);
  z-index: 1;
}

.pin--active {
  border-color: var(--paper);
}

.pin:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 2px;
}

/* ── The live feed ───────────────────────────────────────────────────── */

.live-dot {
  display: inline-block;
  width: 0.55rem;
  height: 0.55rem;
  margin-right: 0.3rem;
  border-radius: 50%;
  background: var(--faint);
  vertical-align: middle;
}

.live-dot.is-live {
  background: var(--accent);
  animation: live-pulse 1.8s ease-in-out infinite;
}

@keyframes live-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(255, 159, 67, 0.55);
  }
  50% {
    box-shadow: 0 0 0 6px rgba(255, 159, 67, 0);
  }
}

.feed {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.feed-row {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.65rem 0.9rem;
  border-radius: var(--r-control);
  background: var(--card);
  border: 1px solid var(--line-soft);
}

.feed-row--new {
  animation: feed-in 420ms ease-out;
}

@keyframes feed-in {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.feed-text {
  min-width: 0;
}

.feed-time {
  flex: none;
  font-size: 0.75rem;
  color: var(--muted);
  white-space: nowrap;
  padding-top: 0.15rem;
}



/* ── The prize + FAQ ─────────────────────────────────────────────────── */

.vote-prize {
  margin-top: 2.25rem;
}

.web-link--ink {
  color: var(--ink);
}

.vote-faq details {
  border-top: 1px solid var(--line-soft);
  padding: 0.75rem 0;
}

.vote-faq details:last-of-type {
  border-bottom: 1px solid var(--line-soft);
}

.vote-faq summary {
  cursor: pointer;
  font-weight: 700;
}

.vote-faq summary:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

.vote-faq p {
  color: var(--muted);
  margin: 0.5rem 0 0;
}

/* ── Dialogs (paper scope, like .stage-card) ─────────────────────────── */

.vote-dialog {
  width: min(28rem, calc(100vw - 2rem));
  margin: auto;
  padding: 1.5rem;
  border: 0;
  border-radius: var(--r-card);
  background: var(--paper);
  color: var(--ink);
  color-scheme: light;
  --muted: var(--ink-muted);
  --faint: var(--ink-faint);
  --line: var(--paper-line);
  --line-soft: var(--paper-line-soft);
  --well: var(--paper-well);
  --focus-ring: var(--ink);
  box-shadow: var(--shadow-pop);
}

.vote-dialog::backdrop {
  background: rgba(11, 11, 12, 0.7);
}

.vote-dialog h2 {
  margin: 0 0 0.5rem;
  font-size: 1.3rem;
}

.share-caption {
  margin: 0 0 1rem;
  padding: 0.75rem 0.9rem;
  border-left: 3px solid var(--accent);
  background: var(--paper-well);
  border-radius: 0 var(--r-control) var(--r-control) 0;
  font-size: 0.9rem;
}

.share-buttons {
  display: grid;
  gap: 0.5rem;
}

.share-note {
  margin: -0.15rem 0 0.2rem;
}

.share-fallback {
  margin-top: 0.5rem;
}

.dialog-actions {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 1rem;
}

/* ── Dialogs as bottom sheets below 768 px (PRD-32 §7) ─────────────────
   The same treatment the landing's check dialog gets in home.css: the
   full-width sheet with a drag-handle decoration, safe-area padding and
   no slide under reduced motion (there is no entrance animation at all). */

@media (max-width: 767px) {
  .vote-dialog {
    width: 100%;
    max-width: 100%;
    margin: auto 0 0;
    max-height: 92dvh;
    padding-bottom: calc(1.5rem + env(safe-area-inset-bottom));
    border-radius: 16px 16px 0 0;
  }

  .vote-dialog::before {
    content: "";
    display: block;
    width: 40px;
    height: 4px;
    margin: 0 auto 1rem;
    border-radius: 2px;
    background: var(--paper-line);
  }
}

/* ── Light mode (PRD-59 §4, Rolling R2) ─────────────────────────────────
   Opt-in through `theme-auto` on the body: the page follows the device
   while :root stays dark. The tally's text already reads --page-ink and
   the vote card, the dialogs and the badges are paper-scoped, so what
   remains is the page ground, the header, the hover labels that went
   white on navy, the card and row edges on white, and the map, which
   keeps its night style in both modes (decision 8). */

@media (prefers-color-scheme: light) {
  body.vote-body {
    background: var(--page);
    color: var(--page-ink);
  }

  /* The header follows the page (R2 decision 1). */
  body.vote-body .site-header {
    background: var(--page);
    color: var(--page-ink);
    color-scheme: light;
  }

  body.vote-body .site-header .logo {
    background-image: url("/img/brand/wordmark-navy.svg");
  }

  /* The signed-in face is a white disc: give it a navy edge on white. */
  body.vote-body .site-account[data-account="in"] .site-account__face {
    border-color: var(--page-ink);
  }

  /* Paper cards on a white page read by a hairline (R2). */
  body.vote-body .vote-card,
  body.vote-body .picks-card,
  body.vote-body .vote-prize {
    border: 1px solid var(--line);
  }

  /* Rows and sections keep their edges on white. */
  body.vote-body .board-row,
  body.vote-body .feed-row {
    border-color: var(--line);
  }

  body.vote-body .vote-faq details {
    border-color: var(--line);
  }

  /* Resting labels that were white on navy go navy on white. */
  body.vote-body .board-more {
    color: var(--page-ink);
  }

  /* Hover labels that went white on navy go navy on white. */
  body.vote-body .site-footer a:hover,
  body.vote-body .site-footer a:focus-visible,
  body.vote-body .web-link:hover,
  body.vote-body .web-link:focus-visible {
    color: var(--page-ink);
  }

  /* The map keeps its night style: pin the subtree tokens it reads back
     to the campaign dark values, so the flipped page roles never reach
     the toolbar, the controls, the note or the popups. */
  body.vote-body .vote-stage {
    --card: #131b24;
    --line: #38434d;
    --line-soft: #242e37;
    --muted: #b0b8bc;
    --faint: #8a9399;
    --well: #010b1b;
  }
}

/* ── Motion + small screens ──────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .pulse-dot,
  .tally-live .live-dot,
  .live-dot.is-live,
  .feed-row--new,
  .pick-row--flash {
    animation: none;
  }

  .board-bar i,
  .tasks-meter i,
  .pin {
    transition: none;
  }
}

@media (max-width: 480px) {
  .board-row {
    grid-template-columns: 2.2rem minmax(0, 1fr) auto;
    padding: 0.6rem 0.7rem;
  }
}

