/* ====================================================
   VOTER CHOICE · Pass C styles
   ====================================================
   Loaded AFTER prototype.css so all overrides win without
   touching the original sheet. Each block is namespaced
   (dl-, poll-, rn-, hiw-, sx-, gf-, nc-, err-, sp-).
   ==================================================== */

/* ============ Accessibility primitives ============ */
:focus-visible {
  outline: 2px solid var(--civic);
  outline-offset: 2px;
  border-radius: 4px;
}
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0ms !important;
    transition-duration: 0ms !important;
    scroll-behavior: auto !important;
  }
}
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 9999;
  background: var(--ink);
  color: var(--paper-2);
  padding: 10px 14px;
  font-family: var(--mono);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  border-radius: 0 0 6px 0;
}
.skip-link:focus {
  left: 0;
}

/* ============ NAV chrome ============ */
.app-nav .nav-right {
  display: flex;
  align-items: center;
  gap: 10px;
}
.app-nav .lang {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.app-nav .lang .lang-pip {
  color: var(--ink-3);
  transition: color 0.15s ease;
}
.app-nav .lang .lang-pip.on {
  color: var(--ink);
  font-weight: 600;
}
.app-nav .lang .lang-sep {
  color: var(--ink-3);
}
.app-nav .lang:hover {
  border-color: var(--ink-2);
}
.app-nav .nav-cog {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    color 0.15s ease;
}
.app-nav .nav-cog:hover {
  color: var(--ink);
  border-color: var(--ink-2);
}

/* ============ Resume nudge ============ */
.resume-nudge {
  margin-top: 22px;
  max-width: 560px;
  padding: 18px 20px 20px;
  border: 1px solid var(--civic-soft);
  background: linear-gradient(
    180deg,
    oklch(0.97 0.018 170) 0%,
    var(--paper-2) 60%
  );
  border-radius: 10px;
  box-shadow: var(--shadow-soft);
}
.resume-nudge .rn-badge {
  display: inline-block;
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--civic);
  margin-bottom: 8px;
}
.resume-nudge .rn-headline {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 22px;
  margin: 0 0 8px;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.resume-nudge .rn-sub {
  margin: 0 0 14px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink-2);
}
.resume-nudge .rn-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.resume-nudge .rn-resume {
  background: var(--civic);
  color: var(--paper-2);
  border: 0;
  border-radius: 8px;
  padding: 11px 18px;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
}
.resume-nudge .rn-resume:hover {
  background: var(--civic-2);
}
.resume-nudge .rn-over {
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: 11px 16px;
  font-size: 13.5px;
  color: var(--ink-2);
  cursor: pointer;
}
.resume-nudge .rn-over:hover {
  border-color: var(--ink-2);
  color: var(--ink);
}

/* ============ How it works ============ */
.hiw {
  border-top: 1px solid var(--rule-2);
  border-bottom: 1px solid var(--rule-2);
  padding: 72px 56px;
  background: var(--paper-2);
}
.hiw-inner {
  max-width: 1280px;
  margin: 0 auto;
}
.hiw-head {
  margin-bottom: 44px;
  max-width: 720px;
}
.hiw-head h2 {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 42px;
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin: 0 0 14px;
}
.hiw-sub {
  font-family: var(--serif);
  font-size: 18px;
  color: var(--ink-2);
  margin: 0;
}
.hiw-steps {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
}
.hiw-step {
  border-top: 1px solid var(--ink);
  padding-top: 18px;
}
.hiw-step .hiw-num {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  color: var(--civic);
  margin-bottom: 14px;
}
.hiw-step-ttl {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0 0 10px;
  color: var(--ink);
}
.hiw-step-desc {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--ink-2);
  margin: 0;
  text-wrap: pretty;
}
@media (max-width: 900px) {
  .hiw {
    padding: 56px 24px;
  }
  .hiw-head h2 {
    font-size: 32px;
  }
  .hiw-steps {
    grid-template-columns: 1fr;
    gap: 28px;
  }
}

/* ============ DeadlineMeter ============ */
.dl-meter {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: 8px;
  overflow: hidden;
}
.dl-row {
  display: grid;
  grid-template-columns: 14px 1fr auto;
  gap: 12px;
  padding: 12px 14px;
  background: var(--paper-2);
  align-items: center;
}
/* Stacked variant: badge drops below label/date so the label
   column gets full width. PollingInfoCard opts into this because
   the workspace rail is ~280px wide and the inline badge truncates
   the label mid-word. */
.dl-meter.stacked .dl-row {
  grid-template-columns: 14px 1fr;
  grid-template-rows: auto auto;
  row-gap: 6px;
}
.dl-meter.stacked .dl-status {
  grid-column: 2 / -1;
  justify-self: start;
}
.dl-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--rule);
}
.dl-row.green .dl-dot {
  background: oklch(0.62 0.13 145);
}
.dl-row.yellow .dl-dot {
  background: oklch(0.78 0.13 90);
}
.dl-row.red .dl-dot {
  background: var(--vote-red);
}
.dl-row.passed .dl-dot {
  background: var(--ink-3);
}
.dl-text {
  min-width: 0;
}
.dl-lab {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink);
  line-height: 1.3;
}
.dl-date {
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  margin-top: 3px;
}
.dl-status {
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 4px 8px;
  border-radius: 999px;
  white-space: nowrap;
}
.dl-row.green .dl-status {
  background: oklch(0.94 0.04 145);
  color: oklch(0.34 0.1 145);
}
.dl-row.yellow .dl-status {
  background: oklch(0.95 0.05 90);
  color: oklch(0.4 0.1 90);
}
.dl-row.red .dl-status {
  background: oklch(0.94 0.04 28);
  color: oklch(0.42 0.16 28);
}
.dl-row.passed .dl-status {
  background: var(--tag-bg);
  color: var(--ink-3);
}

/* ============ PollingInfoCard ============ */
.poll-card {
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 16px 16px 12px;
  box-shadow: var(--shadow-soft);
}
.poll-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 14px;
}
.poll-card-eyebrow {
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--civic);
  margin-bottom: 4px;
}
.poll-card h3 {
  margin: 0;
  font-family: var(--serif);
  font-weight: 600;
  font-size: 19px;
  letter-spacing: -0.01em;
}
.poll-card-toggle {
  background: transparent;
  border: 0;
  color: var(--ink-2);
  cursor: pointer;
  font-size: 14px;
  padding: 4px 8px;
}
.poll-card-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 16px;
  margin-bottom: 14px;
}
.poll-cell .k {
  font-family: var(--mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
  margin-bottom: 2px;
}
.poll-cell .v {
  font-size: 13px;
  color: var(--ink);
  line-height: 1.4;
}
.poll-cell.wide {
  grid-column: 1 / -1;
}
.poll-card-deadlines {
  margin-bottom: 12px;
}
.poll-card-actions {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  padding: 10px 0 6px;
  border-top: 1px solid var(--rule-2);
}
.poll-card-actions .poll-link {
  font-size: 12.5px;
  color: var(--civic);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.poll-card-actions .poll-link:hover {
  color: var(--civic-2);
}
.poll-card-foot small {
  font-family: var(--mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-3);
}

/* ============ Settings drawer ============ */
.sx-overlay {
  position: fixed;
  inset: 0;
  background: oklch(0.18 0.018 240 / 0.32);
  z-index: 1000;
  display: flex;
  justify-content: flex-end;
  animation: sx-fade 0.15s ease-out;
}
@keyframes sx-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
.sx-drawer {
  width: 100%;
  max-width: 440px;
  background: var(--paper);
  border-left: 1px solid var(--rule);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  animation: sx-slide 0.18s ease-out;
}
@keyframes sx-slide {
  from {
    transform: translateX(8px);
    opacity: 0.4;
  }
  to {
    transform: none;
    opacity: 1;
  }
}
.sx-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 24px 12px;
  border-bottom: 1px solid var(--rule-2);
}
.sx-head h2 {
  margin: 0;
  font-family: var(--serif);
  font-weight: 600;
  font-size: 22px;
  letter-spacing: -0.015em;
}
.sx-x {
  background: transparent;
  border: 0;
  font-size: 24px;
  cursor: pointer;
  color: var(--ink-2);
  padding: 0 6px;
  line-height: 1;
}
.sx-x:hover {
  color: var(--ink);
}
.sx-section {
  padding: 22px 24px;
  border-bottom: 1px solid var(--rule-2);
}
.sx-section-ttl {
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
  margin: 0 0 12px;
}
.sx-help {
  font-size: 12.5px;
  color: var(--ink-3);
  line-height: 1.5;
  margin: 0 0 12px;
}
.sx-lang-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.sx-lang-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 8px;
  text-align: left;
  cursor: pointer;
  font-size: 13.5px;
  color: var(--ink);
}
.sx-lang-opt:hover {
  border-color: var(--ink-2);
}
.sx-lang-opt.on {
  border-color: var(--civic);
  background: linear-gradient(180deg, oklch(0.96 0.025 170), var(--paper-2));
}
.sx-lang-opt .sx-lang-flag {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  background: var(--ink);
  color: var(--paper-2);
  padding: 4px 7px;
  border-radius: 4px;
}
.sx-byok-input {
  display: flex;
  gap: 8px;
}
.sx-byok-input input {
  flex: 1;
  border: 1px solid var(--rule);
  background: var(--paper-2);
  padding: 11px 14px;
  font-family: var(--mono);
  font-size: 13px;
  border-radius: 6px;
  color: var(--ink);
  outline: none;
}
.sx-byok-input input:focus {
  border-color: var(--civic);
}
.sx-btn {
  border: 0;
  padding: 10px 16px;
  border-radius: 6px;
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
  white-space: nowrap;
}
.sx-btn.primary {
  background: var(--civic);
  color: var(--paper-2);
}
.sx-btn.primary:hover {
  background: var(--civic-2);
}
.sx-btn.primary:disabled {
  background: var(--rule);
  color: var(--ink-3);
  cursor: not-allowed;
}
.sx-btn.danger {
  background: transparent;
  border: 1px solid oklch(0.85 0.08 28);
  color: var(--vote-red);
}
.sx-btn.danger:hover {
  background: oklch(0.96 0.04 28);
}
.sx-byok-saved {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.sx-byok-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 14px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 6px;
}
.sx-byok-lab {
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
}
.sx-byok-mask {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink);
  background: var(--tag-bg);
  padding: 4px 8px;
  border-radius: 4px;
}
.sx-status {
  margin-top: 10px;
  padding: 10px 12px;
  font-size: 13px;
  border-radius: 6px;
}
.sx-status.ok {
  background: oklch(0.94 0.04 145);
  color: oklch(0.34 0.1 145);
}
.sx-status.error {
  background: oklch(0.94 0.05 28);
  color: oklch(0.4 0.14 28);
}
.sx-data-actions {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 4px;
}
.sx-row-btn {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  background: transparent;
  border: 1px solid var(--rule-2);
  border-radius: 6px;
  padding: 11px 14px;
  font-size: 13.5px;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
}
.sx-row-btn:hover {
  border-color: var(--ink-2);
}
.sx-row-btn .arr {
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: 14px;
}
.sx-row-btn.danger {
  color: var(--vote-red);
  border-color: oklch(0.9 0.04 28);
}
.sx-row-btn.danger:hover {
  background: oklch(0.97 0.025 28);
  border-color: var(--vote-red);
}
.sx-foot {
  padding: 18px 24px 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.sx-foot-link {
  font-size: 12.5px;
  color: var(--civic);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ============ Error views (geocode + no-contested) ============ */
.gf-wrap,
.nc-wrap {
  min-height: calc(100vh - 64px);
  display: grid;
  place-items: start center;
  padding: 56px 24px;
  background: var(--paper);
}
.gf-card,
.nc-card {
  width: 100%;
  max-width: 640px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 36px 36px 32px;
  box-shadow: var(--shadow-card);
}
.gf-eyebrow,
.nc-eyebrow {
  display: inline-block;
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--vote-red);
  padding: 4px 8px;
  background: oklch(0.96 0.04 28);
  border-radius: 4px;
  margin-bottom: 16px;
}
.nc-eyebrow {
  color: var(--civic);
  background: oklch(0.94 0.04 170);
}
.gf-card h2,
.nc-card h2 {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 32px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 14px;
}
.gf-body,
.nc-body {
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-2);
  margin: 0 0 22px;
}
.gf-attempted {
  background: var(--paper);
  border: 1px solid var(--rule-2);
  border-radius: 6px;
  padding: 12px 14px;
  margin-bottom: 22px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.gf-attempted .lab {
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
}
.gf-attempted code {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink);
}
.gf-actions,
.nc-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 18px;
  align-items: center;
}
.gf-primary,
.nc-primary {
  background: var(--civic);
  color: var(--paper-2);
  border: 0;
  border-radius: 8px;
  padding: 12px 20px;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  white-space: nowrap;
}
.gf-secondary,
.nc-back,
.nc-upload,
.err-primary,
.err-secondary {
  white-space: nowrap;
}
.gf-primary:hover,
.nc-primary:hover {
  background: var(--civic-2);
}
.gf-primary:disabled,
.nc-primary:disabled {
  background: var(--rule);
  color: var(--ink-3);
  cursor: not-allowed;
}
.gf-secondary,
.nc-back {
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: 12px 18px;
  font-size: 13.5px;
  color: var(--ink-2);
  cursor: pointer;
}
.gf-secondary:hover,
.nc-back:hover {
  border-color: var(--ink-2);
  color: var(--ink);
}
.gf-tip {
  font-size: 13px;
  color: var(--ink-3);
  margin: 14px 0 0;
  padding: 12px 14px;
  background: var(--paper);
  border-radius: 6px;
  border-left: 3px solid var(--gold);
  line-height: 1.55;
}
.gf-tip code {
  font-family: var(--mono);
  font-size: 12px;
  background: var(--tag-bg);
  padding: 2px 5px;
  border-radius: 3px;
}
.nc-links {
  list-style: none;
  padding: 0;
  margin: 0 0 22px;
  display: grid;
  gap: 8px;
}
.nc-links a {
  display: block;
  padding: 12px 14px;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--paper);
  font-weight: 500;
  font-size: 14px;
  color: var(--civic);
}
.nc-links a:hover {
  border-color: var(--civic);
  background: oklch(0.97 0.018 170);
}
.nc-paste {
  display: block;
  margin-bottom: 18px;
}
.nc-paste span {
  display: block;
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
  margin-bottom: 8px;
}
.nc-paste textarea {
  width: 100%;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: 12px 14px;
  font-family: var(--serif);
  font-size: 14px;
  resize: vertical;
  outline: none;
  min-height: 160px;
}
.nc-paste textarea:focus {
  border-color: var(--civic);
}
.nc-upload {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--civic);
  cursor: pointer;
  padding: 12px 0;
  display: inline-flex;
  align-items: center;
}
.nc-upload input {
  display: none;
}
.nc-upload:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.nc-privacy {
  margin: 6px 0 0;
  font-size: 12.5px;
  color: var(--ink-3);
  font-style: italic;
}

/* ============ Generic error banner ============ */
.err-banner {
  display: grid;
  grid-template-columns: 28px 1fr auto;
  gap: 12px;
  padding: 14px 16px;
  border-radius: 8px;
  align-items: flex-start;
  background: oklch(0.96 0.04 75);
  border: 1px solid oklch(0.86 0.08 75);
}
.err-banner.error {
  background: oklch(0.96 0.04 28);
  border-color: oklch(0.84 0.1 28);
}
.err-icon {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-weight: 700;
  font-size: 14px;
  background: var(--gold);
  color: var(--ink);
}
.err-banner.error .err-icon {
  background: var(--vote-red);
  color: var(--paper-2);
}
.err-title {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  margin-bottom: 4px;
}
.err-text {
  font-size: 13.5px;
  color: var(--ink-2);
  line-height: 1.5;
  margin-bottom: 10px;
}
.err-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.err-primary {
  background: var(--ink);
  color: var(--paper-2);
  border: 0;
  border-radius: 6px;
  padding: 8px 14px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.err-secondary {
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 8px 14px;
  font-size: 12.5px;
  color: var(--ink-2);
  cursor: pointer;
}
.err-close {
  background: transparent;
  border: 0;
  color: var(--ink-3);
  cursor: pointer;
  font-size: 18px;
  padding: 0 6px;
  line-height: 1;
}
.msg.ai-error .bubble {
  background: transparent;
  padding: 0;
  border: 0;
}

/* ============ Static info pages ============ */
.sp-wrap {
  min-height: calc(100vh - 64px);
  padding: 56px 32px 96px;
  background: var(--paper);
}
.sp-inner {
  max-width: 720px;
  margin: 0 auto;
}
.sp-back {
  background: transparent;
  border: 0;
  color: var(--civic);
  font-size: 13.5px;
  padding: 0 0 16px;
  cursor: pointer;
}
.sp-back:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.sp-kicker {
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--civic);
  margin-bottom: 10px;
}
.sp-mast h1 {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 48px;
  line-height: 1;
  letter-spacing: -0.025em;
  margin: 0 0 32px;
  text-wrap: balance;
}
.sp-meta {
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
  margin-bottom: 24px;
}
.sp-mast .dek {
  font-family: var(--serif);
  font-size: 17px;
  line-height: 1.5;
  color: var(--ink-3);
  margin: -18px 0 32px;
  max-width: 640px;
}
.sp-prose {
  font-family: var(--serif);
  font-size: 17px;
  line-height: 1.65;
  color: var(--ink);
}
.sp-prose h2 {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 24px;
  margin: 40px 0 14px;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.sp-prose p {
  margin: 0 0 16px;
}
.sp-prose ul {
  margin: 0 0 16px;
  padding-left: 22px;
}
.sp-prose li {
  margin-bottom: 8px;
}
.sp-prose a {
  color: var(--civic);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.sp-prose code {
  font-family: var(--mono);
  font-size: 14px;
  background: var(--tag-bg);
  padding: 2px 6px;
  border-radius: 4px;
}
@media (max-width: 700px) {
  .sp-mast h1 {
    font-size: 36px;
  }
  .sp-prose {
    font-size: 15.5px;
  }
  .gf-card,
  .nc-card {
    padding: 24px;
  }
  .gf-card h2,
  .nc-card h2 {
    font-size: 26px;
  }
}

/* ============ PAC gloss → footnote treatment ============
   Override prototype.css. Was rendering at body size and reading as
   primary content; should read as a definition footnote: tiny mono
   prefix, serif italic body, muted, set off by a hairline + left
   indent that visually pulls it out of the chart-reading flow.

   No max-width — the footnote spans the funding section's full
   width so it doesn't leave huge dead space on wide screens. */
.cv2-pac-gloss {
  font-family: var(--serif);
  font-style: italic;
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-3);
  margin: 12px 0 0;
  padding: 10px 0 0 14px;
  border-top: 1px solid var(--rule-2);
  border-left: 2px solid var(--rule-2);
  max-width: none;
  text-wrap: pretty;
}
.cv2-pac-gloss b {
  font-family: var(--mono);
  font-style: normal;
  font-weight: 700;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-2);
  margin-right: 2px;
}

/* ============ PollingStatusBar (replaces rail card) ============
   Slim strip directly under app nav. Full bleed, sticky on scroll,
   collapses to a one-liner, expands to a four-cell panel. */
.poll-bar {
  position: sticky;
  top: 0;
  z-index: 50;
  background: oklch(0.97 0.018 170);
  border-bottom: 1px solid var(--rule);
}
.poll-bar.open {
  background: var(--paper-2);
}
.poll-bar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 16px;
  padding: 10px 24px;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--ink);
}
.poll-bar-inner:hover {
  background: oklch(0.94 0.025 170);
}
.poll-bar.open .poll-bar-inner:hover {
  background: var(--paper);
}
.pb-left,
.pb-right {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.pb-left {
  flex: 1 1 auto;
  overflow: hidden;
}
.pb-right {
  flex: 0 0 auto;
}
.pb-pin {
  display: inline-flex;
  color: var(--civic);
  flex: 0 0 14px;
}
.pb-name {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pb-sep {
  color: var(--ink-3);
}
.pb-precinct {
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  white-space: nowrap;
}
.pb-count {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--paper-2);
  color: var(--ink-2);
  white-space: nowrap;
  border: 1px solid var(--rule);
}
.pb-count-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ink-3);
}
.pb-count.green .pb-count-dot {
  background: oklch(0.62 0.13 145);
}
.pb-count.yellow .pb-count-dot {
  background: oklch(0.78 0.13 90);
}
.pb-count.red .pb-count-dot {
  background: var(--vote-red);
}
.pb-count.passed .pb-count-dot {
  background: var(--ink-3);
}
.pb-toggle {
  font-size: 12px;
  color: var(--civic);
  white-space: nowrap;
}

/* ============ Expanded panel under the bar ============ */
.poll-bar-panel {
  border-top: 1px solid var(--rule-2);
  background: var(--paper-2);
  padding: 16px 24px 18px;
}
/* Primary actions row — promoted to the top of the panel so the
   user sees the "act on this" controls before scanning the data.
   Earlier version buried these at the bottom. */
.pbp-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding-bottom: 14px;
  margin-bottom: 18px;
  border-bottom: 1px solid var(--rule-2);
}
.pbp-act {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: var(--paper);
  border: 1px solid var(--rule);
  padding: 8px 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition:
    border-color 0.15s ease,
    color 0.15s ease,
    background 0.15s ease;
}
.pbp-act:hover {
  border-color: var(--civic);
  color: var(--civic);
  background: oklch(0.97 0.018 170);
}
.pbp-act-ico {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--civic);
  color: var(--paper-2);
  font-size: 10px;
  font-weight: 700;
  flex: 0 0 18px;
}
.pbp-source {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-3);
}
.pbp-grid {
  display: grid;
  grid-template-columns: 1.4fr 0.9fr 1fr 1.6fr;
  gap: 28px;
  align-items: flex-start;
}
.pbp-cell {
  min-width: 0;
}
.pbp-k {
  font-family: var(--mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
  margin-bottom: 6px;
}
.pbp-v {
  font-size: 14px;
  line-height: 1.4;
  color: var(--ink);
}
.pbp-sub {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 6px;
  line-height: 1.4;
}
.pbp-link {
  display: inline-block;
  margin-top: 8px;
  font-size: 12.5px;
  color: var(--civic);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.pbp-deadlines .dl-meter {
  margin-top: 2px;
}

/* ============ Mobile ============ */
@media (max-width: 900px) {
  .poll-bar-inner {
    padding: 10px 16px;
    gap: 12px;
    flex-wrap: wrap;
  }
  .pb-right {
    width: 100%;
    justify-content: space-between;
  }
  .pbp-grid {
    grid-template-columns: 1fr 1fr;
    gap: 18px;
  }
  .pbp-deadlines {
    grid-column: 1 / -1;
  }
  .pbp-source {
    width: 100%;
    margin-left: 0;
  }
}
@media (max-width: 540px) {
  .poll-bar-inner {
    padding: 10px 14px;
  }
  .pb-left {
    flex-wrap: wrap;
    gap: 6px;
  }
  .pb-precinct,
  .pb-sep {
    display: none;
  }
  .pbp-grid {
    grid-template-columns: 1fr;
    gap: 16px;
  }
  .poll-bar-panel {
    padding: 14px 14px 14px;
  }
  .pbp-act {
    width: 100%;
    justify-content: center;
  }
}

/* ============ Mobile chat header restructure ============
   The repo's mobile rule packed [back] [title] [Blind][Skip][Compare]
   into a single 3-col grid (40px 1fr auto). The right column got
   crushed and the title wrapped to multiple lines per word. Restack:
     row 1 = back + title (title takes remaining width, wraps OK)
     row 2 = action chips in a horizontal row, full bleed
   Inherits, overrides only the parts we need. */
@media (max-width: 767px) {
  .ws-chat .head {
    grid-template-columns: 40px 1fr !important;
    grid-template-rows: auto auto !important;
    row-gap: 10px !important;
  }
  .ws-chat .head .ws-mobile-back {
    grid-column: 1;
    grid-row: 1;
  }
  .ws-chat .head .title {
    grid-column: 2;
    grid-row: 1;
    text-align: left !important;
    min-width: 0;
    line-height: 1.2;
  }
  .ws-chat .head .h-act {
    grid-column: 1 / -1;
    grid-row: 2;
    display: flex !important;
    gap: 6px;
    flex-wrap: wrap;
  }
  .ws-chat .head .h-act > button {
    flex: 1 1 0;
    min-width: 0;
    min-height: 36px;
    justify-content: center;
  }
}

/* ============ See all votes — bridge button ============
   Sits between the alignment scores and the funding chart so the
   "evidence" CTA is next to its semantic neighbor (the record
   summary), not buried at the bottom of the card. */
.cv2-see-all-bridge {
  padding: 14px 24px 14px;
  margin-top: -4px;
  margin-bottom: 14px;
  display: flex;
  justify-content: center;
}
/* Cap the pill width so it sits as a centered chip with real
   margins on all four sides — not a full-bleed bar pretending
   to be a button. */
.cv2-see-all-inline {
  max-width: 320px;
}
/* Was: tiny underlined text button — practically invisible. Now: a
   subtle pill-button that reads as "the action neighboring the
   evidence." Civic-tinted but not the primary CTA (the Pick button
   downstream gets that). */
.cv2-see-all-inline {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: oklch(0.97 0.018 170);
  border: 1px solid var(--civic-soft);
  padding: 9px 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--civic);
  cursor: pointer;
  text-decoration: none;
  border-radius: 999px;
  min-height: 36px;
  white-space: nowrap;
  font-family: inherit;
}
.cv2-see-all-inline:hover {
  background: var(--civic);
  color: var(--paper-2);
  border-color: var(--civic);
}
.cv2-see-all-inline:disabled {
  background: transparent;
  color: var(--ink-3);
  cursor: not-allowed;
  border-color: var(--rule);
}
@media (max-width: 600px) {
  .cv2-see-all-bridge {
    padding: 14px 18px;
    justify-content: center;
  }
  .cv2-see-all-inline {
    width: auto;
    max-width: 280px;
    min-width: 180px;
    justify-content: center;
    min-height: 44px;
    font-size: 14px;
  }
}

/* ============ Handoff modal mobile scroll ============
   The "Take your research with you" modal is taller than the
   viewport on phones — the footer text gets cut off below the
   safe-area inset. Cap height at viewport - inset, scroll body,
   pad bottom past the iOS home indicator. */
@media (max-width: 767px) {
  .be-modal {
    max-height: calc(100vh - 16px) !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    padding-bottom: calc(32px + env(safe-area-inset-bottom, 0px)) !important;
  }
}
Bumps
  small
  touch
  targets
  to
  44×44
  minimum
  and
  restacks
  rows
  that
  overflow
  at
  narrow
  widths.
  Scoped
  to
  ≤640px
  so
  the
  desktop
  layout
  (which is dense by design)
  is
  untouched.
  */
  @media
  (max-width: 640px) {
  /* ─── Issue ranking row ─── */
  .theme-row {
    /* Mobile layout: just two columns — drag handle on the left,
       full body on the right. The body holds title + quotes;
       Rename/Remove sit below it. The serif rank pill is dropped
       (rank is implied by row order on a phone). */
    grid-template-columns: 44px 1fr;
    column-gap: 12px;
    row-gap: 8px;
    padding: 16px 0;
  }
  /* The ord wrapper now holds only the big drag handle. Hide the
     arrow up/down buttons on mobile — drag-handle is the primary
     reorder affordance; keyboard users still get arrows on desktop. */
  .theme-row .ord {
    display: flex !important;
    flex-direction: column !important;
    align-items: stretch !important;
    width: 44px;
    margin: 0;
    grid-row: 1;
    grid-column: 1;
  }
  .theme-row .ord .drag-handle {
    width: 44px !important;
    height: 56px !important;
    background: var(--paper) !important;
    border: 1px solid var(--rule) !important;
    border-radius: 6px;
  }
  .theme-row .ord .ord-arrows {
    display: none;
  }
  /* Hide the giant serif rank — column gone, body takes the slot */
  .theme-row .rank {
    display: none;
  }

  .theme-row .body {
    grid-column: 2;
    grid-row: 1 / 3;
  }

  /* RENAME / REMOVE — promote from 9.5px stacked text to a proper
     bottom action row with adequate hit targets. */
  .theme-row .acts {
    grid-column: 2;
    grid-row: 2;
    flex-direction: row;
    justify-content: flex-start;
    gap: 14px;
    padding-top: 6px;
    border-top: 1px dashed var(--rule-2);
  }
  .theme-row .acts button {
    font-size: 11px;
    padding: 8px 0;
    min-height: 32px;
    text-align: left;
  }
  .theme-row .nm {
    font-size: 17px;
    line-height: 1.25;
  }
  .theme-row .nm input.name-edit {
    min-width: 0;
    width: 100%;
  }

  /* ─── Lock-in footer ─── */
  .themes-card .th-foot {
    flex-direction: column-reverse; /* primary CTA visually on top */
    align-items: stretch;
    gap: 8px;
  }
  .themes-card .th-foot .lock,
  .themes-card .th-foot .secondary {
    width: 100%;
    justify-content: center;
    text-align: center;
    padding: 14px 16px;
    font-size: 15px;
    min-height: 48px;
  }

  /* ─── Cold-open submit row ─── */
  /* Make sure the "let AI read" CTA hits 44px on small screens
     (the coldopen textarea is already full-width). */
  .coldopen .co-actions button,
  .coldopen .co-submit {
    min-height: 48px;
    width: 100%;
  }

  /* ─── General: prevent any narrow buttons from sneaking in ─── */
  .gf-actions,
  .nc-actions {
    flex-direction: column-reverse;
    align-items: stretch;
  }
  .gf-actions button,
  .nc-actions button,
  .nc-actions .nc-upload {
    width: 100%;
    justify-content: center;
    text-align: center;
    min-height: 48px;
  }
}

/* ─── Touch-friendly hit targets across surfaces (≤ tablet) ─── */
@media (max-width: 900px) and (pointer: coarse) {
  /* Apple HIG / Material both call 44×44 the minimum. */
  .app-nav .nav-cog,
  .app-nav .lang {
    min-height: 40px;
    min-width: 40px;
  }
  .sx-x {
    min-width: 40px;
    min-height: 40px;
  }
  .pbp-act {
    min-height: 40px;
  }
}

/* ============ Print sheet footer (missing in prototype.css) ============
   .print-foot renders the "Built with Voter Choice" block; .print-serial
   is the 3-up meta strip (Generated · Ref · Page). Without these rules
   the spans inline-flow and read as "Generated May 28 2026 at 10:54 AMRef · VC-…Page 1 of 1". */
.print-serial {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px dashed var(--rule);
  display: flex;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
}
.print-foot {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
  flex-wrap: wrap;
}

/* ============ Candidate-card action stacking ============
   The base layout in prototype.css uses `display: flex` for .cv2-actions
   and the existing mobile rule sets `grid-template-columns: 1fr` which
   no-ops against flex. Restate as flex-column + raise the breakpoint
   so it triggers at narrow workspace widths too. */
@media (max-width: 600px) {
  .cv2-actions {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }
  .cv2-actions .see,
  .cv2-actions .pick {
    width: 100%;
    justify-content: center;
    min-width: 0;
    order: initial; /* primary CTA first */
  }
  .cv2-actions .pick {
    order: 1;
  }
  .cv2-actions .see {
    order: 2;
  }
}

/* ============ Bring (accepted IDs) — list display ============ */
.pbp-bring-lead {
  display: block;
  font-size: 12px;
  color: var(--ink-3);
  margin-bottom: 4px;
}
.pbp-bring-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.pbp-bring-list li {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink);
  padding: 2px 0;
}
.pbp-bring-list li::before {
  content: "·";
  color: var(--ink-3);
  margin-right: 8px;
  font-weight: 700;
}
.pbp-bring-toggle {
  margin-top: 6px;
  background: transparent;
  border: 0;
  padding: 4px 0;
  font-size: 12px;
  color: var(--civic);
  cursor: pointer;
  font-family: inherit;
}
.pbp-bring-toggle:hover {
  color: var(--civic-2);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Print ballot ID list — same multi-ID treatment on paper. */
.cell-bring {
  grid-column: span 1;
}
.print-id-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--serif);
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink);
}
.print-id-list li {
  padding: 1px 0;
}
.print-id-list li::before {
  content: "· ";
  color: var(--ink-3);
}

/* ============ Drag handle & theme-row reorder visuals ============
   IssueRow now has TWO ord children: a drag handle (used on touch
   and mouse drag) and an up/down arrow group (used by keyboard
   users on desktop). On mobile we show the handle only. */
.theme-row .ord {
  align-items: center;
}
.theme-row .ord .drag-handle {
  width: 28px;
  height: 36px;
  background: transparent;
  border: 0;
  color: var(--ink-3);
  cursor: grab;
  display: grid;
  place-items: center;
  border-radius: 4px;
  touch-action: none; /* prevent scroll-fight during drag */
}
.theme-row .ord .drag-handle:hover {
  color: var(--ink);
  background: var(--tag-bg);
}
.theme-row .ord .drag-handle:active,
.theme-row.dragging .ord .drag-handle {
  cursor: grabbing;
  color: var(--civic);
}
.theme-row .ord .ord-arrows {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.theme-row.dragging {
  z-index: 5;
  position: relative;
  box-shadow: 0 8px 24px -10px oklch(0.18 0.018 240 / 0.25);
  background: var(--paper-2);
  border-radius: 8px;
  cursor: grabbing;
}
.theme-row.drop-target {
  outline: 2px dashed var(--civic);
  outline-offset: -4px;
  border-radius: 6px;
}

/* ============ Home page mobile ============ */
@media (max-width: 900px) {
  .hp-hero {
    padding: 48px 24px 40px;
    grid-template-columns: 1fr !important;
    gap: 36px;
  }
  /* .hp-stack (prototype.css) is a fixed 380px-wide decorative card-stack
     mockup, absolute-positioned inside .hp-preview and pixel-perfect ported
     from the desktop illustration — .hp-sheet's own `right: -6px` bleeds it
     a further 6px past .hp-stack's edge. Below ~900px the hero column no
     longer has 380px+ to give it, so the stack (and its own bleed) pushed
     the whole page ~19px past the viewport at narrow widths. The preview is
     aria-hidden (purely decorative — see App2's HomeView render), so
     clipping to .hp-preview's actual box removes the page-level overflow
     without touching the desktop-sized illustration itself. */
  .hp-preview {
    overflow: hidden;
  }
  .hp-hero h1 {
    font-size: 56px !important;
  }
  .hp-hero p.lede {
    font-size: 17px !important;
  }
}
@media (max-width: 540px) {
  .hp-hero {
    padding: 36px 18px 32px;
    gap: 28px;
  }
  .hp-hero h1 {
    font-size: 40px !important;
    line-height: 1 !important;
  }
  .hp-hero p.lede {
    font-size: 15.5px !important;
    line-height: 1.5 !important;
  }
  .addr-card {
    padding: 16px 16px 18px !important;
  }
  .addr-card label {
    flex-direction: column;
    align-items: flex-start !important;
    gap: 2px;
  }
  .addr-card .row {
    flex-direction: column;
    gap: 10px;
  }
  .addr-card input {
    width: 100%;
    font-size: 16px !important; /* avoid iOS zoom */
    min-height: 48px;
  }
  .addr-card .go {
    width: 100%;
    min-height: 48px;
    justify-content: center;
  }
  .addr-card .hint {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }
  .hiw {
    padding: 40px 18px !important;
  }
  .hiw-head h2 {
    font-size: 28px !important;
  }
}

/* ============ Cold-open mobile ============ */
@media (max-width: 640px) {
  .coldopen {
    padding: 24px 18px 32px !important;
  }
  .coldopen .co-context {
    font-size: 11.5px !important;
    line-height: 1.5;
  }
  /* Address pill at top — let the address wrap onto its own line so
     "<addr> · Harris County, TX-7 · 5 races" doesn't read as one
     ugly run-on string at narrow widths. */
  .coldopen .co-context b {
    display: block;
    margin-bottom: 4px;
  }
  .coldopen h2 {
    font-size: 26px !important;
    line-height: 1.15 !important;
  }
  .coldopen .co-sub {
    font-size: 14.5px !important;
  }

  .co-input textarea {
    min-height: 160px;
    font-size: 16px; /* avoid iOS zoom */
  }
  .co-input .row {
    flex-direction: column;
    align-items: stretch !important;
    gap: 12px;
  }
  .co-input .send {
    width: 100%;
    justify-content: center;
    min-height: 48px;
    font-size: 15px;
  }
  .co-input .hint {
    order: 2;
    font-size: 10.5px;
    line-height: 1.5;
    text-align: center;
  }
}

/* ============ Pick button centering ============
   Was justify-content: flex-end which pushed the only remaining
   action to the right edge — off-center on the candidate card. */
.cv2-actions {
  justify-content: center !important;
}
.cv2-actions .pick {
  min-width: 280px;
}
/* But on narrow phones, min-width: 280px makes the button overflow
   its card. Unset there and let it size to the container. */
@media (max-width: 600px) {
  .cv2-actions .pick {
    min-width: 0 !important;
  }
}

/* Gap between "See all votes" pill and the Money trail disclosure
   below it. Earlier they sat flush, which made the disclosure look
   like a continuation of the pill rather than a separate section. */
.cv2-see-all-bridge {
  margin-bottom: 14px;
}

/* ============ Disclosure header — mobile stack ============
   On mobile the title block (eyebrow + title + teaser) was sharing
   the row with the SHOW DETAILS chip, which pinched both columns
   awkwardly. Stack vertically: title block on top, action chip
   below as a full-width pill so the affordance is unambiguous. */
@media (max-width: 640px) {
  .cv2-disclose-toggle {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    padding: 16px 18px;
  }
  .cv2-disclose-chev {
    align-self: stretch;
    justify-content: center;
    padding: 10px 14px;
    background: var(--civic-soft);
    border-radius: 999px;
    min-height: 44px;
    text-align: center;
  }
  .cv2-disclose-summary {
    font-size: 14px !important;
  }
}

/* ============ Body text scale pass ============
   Bump small body text up to align with accessibility guidance
   for broad audiences (16-18px body, 14-16px secondary). We DON'T
   touch mono caps labels (those are tags, intentionally small) or
   the giant serif display sizes. */
.alignment-row .desc,
.cv2-iss-body p,
.cv2-iss-body li,
.cv2-funding p,
.cv2-money-legend > div,
.cv2-iss-narr,
.cmp-vote-narr,
.cv2-allocated-foot,
.av-vote .av-vote-narr,
.av-vote .av-vote-ttl {
  font-size: 15px !important;
  line-height: 1.55 !important;
}
.cv2-money-legend > div small {
  font-size: 12.5px !important;
}
.cv2-iss-head .lab {
  font-size: 16px !important;
  line-height: 1.3 !important;
}
.cv2-iss-head .pct {
  font-size: 30px !important;
}
.alignment-row .lab {
  font-size: 16px;
  line-height: 1.3;
}
.theme-row .quote {
  font-size: 14px !important;
  line-height: 1.55 !important;
}
.cv2-name {
  font-size: 22px !important;
}
.msg .bubble {
  font-size: 15.5px !important;
  line-height: 1.6 !important;
}
.msg .who {
  font-size: 12px !important;
}
.b-row .ttl {
  font-size: 16px !important;
}
.b-row .lab {
  font-size: 11.5px !important;
}
.pb-name {
  font-size: 14.5px !important;
}
.pbp-v {
  font-size: 15px !important;
  line-height: 1.5 !important;
}
.pbp-k {
  font-size: 11px !important;
}

/* ============ Whole-card drag on mobile ============
   Tap-and-hold anywhere on the issue card to drag, not just the
   grip handle. Desktop keeps handle-only drag so the row's text
   remains selectable. */
@media (max-width: 640px) {
  .theme-row {
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
    cursor: grab;
  }
  /* Grip becomes a visual marker only on mobile — row-level
     pointer events drive the drag. */
  .theme-row .ord .drag-handle {
    pointer-events: none;
  }
  /* But buttons and inputs inside the row STILL need pointer events,
     otherwise rename/remove become un-tappable. */
  .theme-row .acts button,
  .theme-row .edit-pencil,
  .theme-row input {
    pointer-events: auto;
    touch-action: auto;
  }
}

/* ============ Home page footer mobile stack ============
   The desktop grid (1fr auto auto) crushes "© 2026 · Gray Bird LLC"
   into a vertical character column at narrow widths. Stack to a
   single column on tablet & phone, center everything. */
@media (max-width: 900px) {
  .hp-foot {
    grid-template-columns: 1fr !important;
    gap: 20px !important;
    padding: 36px 24px !important;
    text-align: center;
    margin-top: 40px;
  }
  .hp-foot ul {
    justify-content: center !important;
    flex-wrap: wrap;
    row-gap: 12px !important;
  }
}
@media (max-width: 540px) {
  .hp-foot {
    padding: 28px 18px !important;
    gap: 16px !important;
  }
  .hp-foot ul {
    gap: 16px !important;
    font-size: 13.5px;
  }
}

/* ============ Cold-open context pill stack ============
   The `.co-context` is display:flex so address + "· Harris County
   · 5 races" sat in two side-by-side flex columns. Stack on mobile. */
@media (max-width: 640px) {
  .coldopen .co-context {
    flex-direction: column !important;
    align-items: flex-start !important;
    line-height: 1.6;
  }
  .coldopen .co-context::before {
    margin-bottom: 4px;
  }
}

/* ============ Themes-card lock-in footer — stronger stacking
   The desktop rule lives in prototype.css. Force the mobile stack
   with !important so column-reverse and full-width win cleanly. */
@media (max-width: 767px) {
  .themes-card .th-foot {
    flex-direction: column-reverse !important;
    align-items: stretch !important;
    gap: 8px !important;
  }
  .themes-card .th-foot .lock,
  .themes-card .th-foot .secondary {
    width: 100% !important;
    justify-content: center !important;
    text-align: center !important;
    padding: 14px 16px !important;
    font-size: 15px !important;
    min-height: 48px !important;
  }
}

/* ============ Theme-row body width + REMOVE on mobile ============
   The body cell was getting squeezed. Force min-width:0 so quote
   text can wrap, and bump REMOVE to a real touch-friendly chip. */
@media (max-width: 640px) {
  .theme-row .body {
    min-width: 0;
    width: 100%;
  }
  .theme-row .quotes {
    width: 100%;
  }
  .theme-row .quote {
    padding-left: 12px;
    padding-right: 0;
    width: 100%;
  }
  .theme-row .quote em {
    display: inline;
  }
  .theme-row .acts {
    border-top: 1px dashed var(--rule-2);
    margin-top: 6px;
    padding-top: 10px;
  }
  .theme-row .acts button.danger {
    font-size: 12.5px !important;
    padding: 10px 14px !important;
    min-height: 44px !important;
    border: 1px solid oklch(0.88 0.05 28) !important;
    border-radius: 999px !important;
    color: var(--vote-red) !important;
    background: transparent;
    text-align: center !important;
  }
  .theme-row .acts button.danger:hover {
    background: oklch(0.97 0.025 28);
  }
}

/* ============ Vote drilldown mobile redesign ============
   The default desktop layout puts bill-num + title in column 1 and
   the WITH YOU / AGAINST YOU badge in column 2. On phones that gives
   us a 3-line wrapped title fighting a vertical badge pill.
   On mobile, restructure to four stacked zones:
     1. metadata row — bill num + vote badge, both small pills inline
     2. bill title — bigger serif, full bleed
     3. date — small mono caps
     4. narrative + cite — clean reading column. */
@media (max-width: 640px) {
  .cv2-vote {
    padding: 14px 14px 12px !important;
  }
  .cv2-vote-head {
    grid-template-columns: 1fr !important;
    gap: 8px !important;
    margin-bottom: 8px !important;
  }
  /* Bill num + vote badge moved into ONE horizontal meta row */
  .cv2-vote-head .bill {
    order: 2;
    gap: 4px;
  }
  .cv2-vote-head .vote-badge,
  .cv2-vote-head .cv2-vote-align {
    order: 1;
    align-self: flex-start;
    margin: 0 0 0 0;
    /* Badge becomes a leading status pill — slightly bigger so it's
       glanceable as the verdict, not a small corner tag. */
    font-size: 11.5px !important;
    padding: 5px 10px !important;
  }
  /* Bill-num pill: mono caps in a small bordered chip up top */
  .cv2-vote-head .bill .num {
    display: inline-block;
    font-size: 10.5px !important;
    padding: 3px 7px;
    background: var(--tag-bg);
    border-radius: 4px;
    color: var(--ink-2);
    align-self: flex-start;
    margin-bottom: 4px;
    letter-spacing: 0.12em;
  }
  /* Bill title — let it own the row */
  .cv2-vote-head .bill .ttl {
    font-size: 17px !important;
    line-height: 1.25 !important;
  }
  /* Date moves below the title cluster, smaller */
  .cv2-vote-date {
    font-size: 10.5px !important;
    margin-bottom: 8px;
  }
  /* Narrative gets a comfortable reading size */
  .cv2-vote-narr {
    font-size: 14.5px !important;
    line-height: 1.55 !important;
  }
  /* Citation row stacks cleanly: chip + link on separate lines for
     thumb-friendly tapping. */
  .cv2-vote-cite {
    flex-wrap: wrap;
    gap: 8px !important;
  }
  .cv2-vote-cite .src-link {
    min-height: 36px;
    display: inline-flex;
    align-items: center;
  }
}

/* ============ Drilldown frame — give it a card identity on mobile
   The .cv2-iss-row.open already pulls margin: 0 -18px to bleed full
   width. Tighten the inner padding + add a subtle inset so the user
   reads it as "expanded context" rather than a wall of text. */
@media (max-width: 640px) {
  .cv2-iss-row.open {
    background: var(--paper) !important;
    border-top: 1px solid var(--rule-2);
    border-bottom: 1px solid var(--rule-2);
    padding: 14px 18px 16px !important;
  }
  .cv2-iss-body {
    padding: 0 !important;
  }
  /* "Why 20%?" header inside drilldown */
  .cv2-iss-narr-head {
    font-size: 16px !important;
  }
  .cv2-iss-narr-hint {
    font-size: 10.5px !important;
  }
}

/* ============ Section label hierarchy pass ============
   The user's complaint: section labels (Funding mix / Named issue
   PACs / Industry breakdown) at 13 px mono-caps were smaller than
   the body content under them, which inverted the visual
   hierarchy. Promote each section label to a 19 px serif title,
   keep the sub-caption italic & quiet underneath, and restore the
   PAC gloss to a small footnote treatment (my earlier generic
   .cv2-funding p rule had pulled it up to 15 px). */

/* Section titles (Funding mix, Named issue PACs, Industry
   breakdown) — promote to serif title that DOMINATES the body. */
.cv2-block-head .lab,
.cv2-named-pacs .lab,
.cv2-industry .lab {
  font-family: var(--serif) !important;
  font-weight: 600 !important;
  font-size: 19px !important;
  text-transform: none !important;
  letter-spacing: -0.005em !important;
  color: var(--ink) !important;
  line-height: 1.2 !important;
}
/* Subcaption ("by source type", "organized groups we've vetted…")
   sits beneath the title — quiet, italic, smaller, gray. */
.cv2-sub-lab {
  display: block !important;
  font-family: var(--serif) !important;
  font-style: italic !important;
  font-size: 12.5px !important;
  font-weight: 400 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--ink-3) !important;
  margin-top: 4px !important;
  line-height: 1.45 !important;
}

/* PAC gloss footnote — restore to a small italic serif footnote.
   The earlier global `.cv2-funding p` body-bump pulled this to
   15 px, which made it more prominent than the section title it
   sits under. It's a definition; it should read as a caption. */
.cv2-funding p.cv2-pac-gloss {
  font-family: var(--serif) !important;
  font-style: italic !important;
  font-size: 12.5px !important;
  line-height: 1.55 !important;
  color: var(--ink-3) !important;
  max-width: none;
  text-wrap: pretty;
}
.cv2-funding p.cv2-pac-gloss b {
  font-family: var(--mono) !important;
  font-style: normal !important;
  font-weight: 700 !important;
  font-size: 10.5px !important;
  text-transform: uppercase !important;
  letter-spacing: 0.14em !important;
  color: var(--ink-2) !important;
  margin-right: 2px;
}

/* Issue-PAC name + dollars (the row body) — bumped earlier to 15 px;
   keep that but tighten the relationship: the row's body text should
   read clearly as the CONTENT, the section title above it as the
   HEADER. Specifically, the inline-PAC names ("EMILY's List") were
   appearing similar in weight to the section header. Make the row
   name a step down from the section title. */
.cv2-pac-row .name {
  font-size: 16px !important;
  font-weight: 600 !important;
}
.cv2-pac-row .pct {
  font-size: 16px !important;
}
.cv2-pac-row .name small {
  font-size: 13px !important;
  font-style: italic !important;
  color: var(--ink-3) !important;
  display: block;
  margin-top: 4px;
  font-weight: 400 !important;
}

/* ============ Candidate card progressive disclosure ============
   Wraps Funding mix / Named PACs / Industry breakdown in one
   collapsible "Money trail" block. Default open on desktop
   (≥901px), closed on phones / tablets. The header has an eyebrow
   + title + inline summary so the user gets a teaser without
   expanding. */
.cv2-disclose {
  border-top: 1px solid var(--rule-2);
}
.cv2-disclose-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  padding: 18px 24px;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--ink);
  border-radius: 0;
}
.cv2-disclose-toggle:hover {
  background: var(--paper);
}
.cv2-disclose-lab {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.cv2-disclose-eyebrow {
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
}
.cv2-disclose-title {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 18px;
  letter-spacing: -0.005em;
  color: var(--ink);
}
.cv2-disclose-summary {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13.5px;
  color: var(--ink-3);
  line-height: 1.45;
  text-wrap: pretty;
}
/* Top line of the teaser — total raised + peer comparison. The
   amount gets ink-1 weight so it reads as the headline number;
   the peer comparison stays ink-3 as supporting context. */
.cv2-disclose-stat {
  font-size: 14.5px;
  color: var(--ink);
  line-height: 1.4;
}
.cv2-disclose-stat b {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 17px;
  color: var(--ink);
  margin-right: 4px;
}
.cv2-disclose-peer {
  color: var(--ink-3);
  font-size: 13px;
  margin-left: 2px;
}
/* Mix line — small donors · large donors · PACs */
.cv2-disclose-mix {
  font-size: 13px;
  color: var(--ink-3);
}
.cv2-disclose-issue-pacs {
  align-self: flex-start;
  display: inline-flex;
  padding: 4px 8px;
  border-radius: 999px;
  background: var(--civic-soft);
  color: var(--civic-2);
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1.25;
}
.cv2-disclose-arrow {
  font-size: 11px;
  display: inline-block;
}
.cv2-disclose.open .cv2-disclose-toggle {
  border-bottom: 1px dashed var(--rule-2);
}
.cv2-disclose-body > .cv2-funding {
  border-top: 0;
}
@media (max-width: 600px) {
  .cv2-disclose-toggle {
    padding: 16px 18px;
    min-height: 56px;
  }
}

/* ============ BudgetExhausted modal — prevent flex-collapse ============
   .be-modal is display:flex/column with max-height + overflow-y:auto.
   The portable-prompt textarea (240px) is a flex child with default
   flex-shrink:1, so once BYOK was added the total content exceeded
   the modal height and the prompt box collapsed to a sliver instead
   of the modal scrolling. Lock the key children so the modal scrolls
   and the prompt keeps its height. */
.be-modal > .be-prompt,
.be-modal > .be-extras,
.be-modal > .be-byok,
.be-modal > .be-head,
.be-modal > .be-lede,
.be-modal > .be-foot {
  flex-shrink: 0;
}
.be-prompt-text {
  min-height: 200px;
  white-space: pre-wrap;
  overflow-x: hidden;
  word-break: break-word;
}

/* Chatbot button 2-column grid — matches prototype's 2-button-per-row
   aesthetic when 4 chatbot buttons sit above a standalone download row. */
.be-extras--col {
  flex-direction: column;
}
.be-extras-bots {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.be-extras--col > .be-ext-btn {
  width: 100%;
}
@media (max-width: 640px) {
  .be-extras-bots {
    grid-template-columns: 1fr;
  }
}

/* ============ BudgetExhausted inline BYOK card ============
   Sits between the portable prompt and the action buttons inside
   the .be-modal. Styled to match the same paper-2 card pattern but
   set apart with a hairline rule above. The structure mirrors the
   SettingsPanel BYOK so a user who's seen one recognises the other. */
.be-byok {
  margin-top: 18px;
  padding-top: 22px;
  border-top: 1px solid var(--rule);
}
.be-byok-ttl {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 21px;
  letter-spacing: -0.015em;
  color: var(--ink);
  margin: 0 0 6px;
  line-height: 1.25;
}
.be-byok-sub {
  font-size: 14px;
  color: var(--ink-3);
  margin: 0 0 14px;
  line-height: 1.5;
}
.be-byok-getkey {
  display: inline-block;
  margin: 0 0 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--civic);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.be-byok-getkey:hover {
  color: var(--civic-2);
}
.be-byok-row {
  display: flex;
  gap: 10px;
  align-items: stretch;
}
.be-byok-input-wrap {
  flex: 1;
  position: relative;
  display: flex;
  align-items: stretch;
}
.be-byok-input-wrap input {
  flex: 1;
  background: var(--paper-2);
  border: 1.5px solid var(--civic);
  border-radius: 8px;
  padding: 13px 36px 13px 14px;
  font-family: var(--mono);
  font-size: 14px;
  color: var(--ink);
  outline: none;
}
.be-byok-input-wrap input:focus {
  border-color: var(--civic-2);
  box-shadow: 0 0 0 3px oklch(0.94 0.05 170);
}
.be-byok-icon {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  color: var(--ink-3);
}
.be-byok-save {
  background: var(--civic);
  color: var(--paper-2);
  border: 0;
  border-radius: 8px;
  padding: 12px 22px;
  font-weight: 600;
  font-size: 15px;
  cursor: pointer;
  white-space: nowrap;
}
.be-byok-save:hover {
  background: var(--civic-2);
}
.be-byok-save:disabled {
  background: var(--rule);
  color: var(--ink-3);
  cursor: not-allowed;
}
.be-byok-hint {
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
  margin: 8px 0 0;
}
.be-byok-status {
  margin: 10px 0 0;
  padding: 10px 12px;
  font-size: 13px;
  border-radius: 6px;
}
.be-byok-status.ok {
  background: oklch(0.94 0.04 145);
  color: oklch(0.34 0.1 145);
}
.be-byok-status.error {
  background: oklch(0.94 0.05 28);
  color: oklch(0.4 0.14 28);
}
.be-byok-saved {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 8px;
}
.be-byok-mask {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.be-byok-lab {
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
}
.be-byok-mask code {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink);
}
.be-byok-clear {
  background: transparent;
  border: 1px solid oklch(0.85 0.08 28);
  border-radius: 6px;
  padding: 8px 14px;
  font-size: 12.5px;
  color: var(--vote-red);
  cursor: pointer;
}
.be-byok-clear:hover {
  background: oklch(0.97 0.025 28);
}

/* Tip-jar tagline — italic mono, deliberately quiet, sits in the
   gray gutter under BYOK. NOT REQUIRED is on purpose. */
.be-tipjar {
  margin: 18px 0 0;
  font-family: var(--mono);
  font-style: italic;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-3);
  line-height: 1.6;
}
.be-tipjar a {
  color: var(--civic);
  cursor: pointer;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Mobile — stack the input + Save button vertically so the 16 px
   font-size keeps iOS from zooming on focus. */
@media (max-width: 640px) {
  .be-byok-ttl {
    font-size: 18px;
  }
  .be-byok-row {
    flex-direction: column;
  }
  .be-byok-input-wrap input {
    font-size: 16px;
    min-height: 48px;
  }
  .be-byok-save {
    width: 100%;
    justify-content: center;
    min-height: 48px;
  }
}

/* ============ Tip jar page ============ */
.tip-list {
  list-style: none !important;
  padding: 0 !important;
  display: grid;
  gap: 10px;
  margin: 6px 0 16px !important;
}
.tip-list .tip-link a {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: auto auto;
  column-gap: 12px;
  row-gap: 4px;
  align-items: center;
  padding: 16px 18px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 10px;
  text-decoration: none;
  color: var(--ink);
  font-family: var(--sans);
}
.tip-list .tip-link a:hover {
  border-color: var(--civic);
  background: oklch(0.97 0.018 170);
}
.tip-list .tip-link.preferred a {
  border-color: var(--civic);
  background: oklch(0.97 0.018 170);
}
.tip-link-name {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 18px;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 10px;
  grid-column: 1;
  grid-row: 1;
}
.tip-link-note {
  font-size: 13.5px;
  color: var(--ink-3);
  grid-column: 1;
  grid-row: 2;
  line-height: 1.45;
}
.tip-link-arrow {
  font-family: var(--mono);
  font-size: 18px;
  color: var(--civic);
  grid-column: 2;
  grid-row: 1 / 3;
  align-self: center;
}
.tip-pref-tag {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  background: var(--civic);
  color: var(--paper-2);
  padding: 3px 7px;
  border-radius: 4px;
}

/* tip amount picker */
.tip-list--amounts {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  margin: 24px 0 12px !important;
}
.tip-list--amounts li {
  list-style: none;
}
.tip-amount-btn {
  display: block;
  text-align: center;
  padding: 18px 0;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 10px;
  font-family: var(--serif);
  font-size: 22px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none !important;
  transition:
    border-color 0.12s,
    background 0.12s;
}
.tip-amount-btn:hover {
  border-color: var(--civic);
  background: oklch(0.97 0.018 170);
  color: var(--civic);
}
.tip-note {
  font-size: 13px;
  color: var(--ink-3);
  text-align: center;
  margin: 0 0 24px !important;
}

/* ---------- Tip jar — Bold Flag / Keystone parity (08d-tipjar) ----------
   Locally-scoped white-palette tokens matching design-handoff/keystone-canvas
   src/screens.css .screen[data-palette="white"] + statics.css .sp-tip*.
   Scoped to .sp-tipjar only — does not touch the shared civic palette or
   any other static page. */
.sp-wrap.sp-tipjar {
  --tj-paper: oklch(1 0 0);
  --tj-paper-2: oklch(0.985 0.003 258);
  --tj-ink: oklch(0.2 0.035 260);
  --tj-ink-2: oklch(0.37 0.032 260);
  --tj-ink-3: oklch(0.54 0.026 260);
  --tj-brand: oklch(0.4 0.155 262);
  --tj-rule: oklch(0.88 0.006 260);
  --tj-replace: oklch(0.53 0.205 27);
  --tj-serif: "Newsreader", Georgia, serif;
  --tj-mono: "IBM Plex Mono", ui-monospace, monospace;
  background: var(--tj-paper);
}
.sp-wrap.sp-tipjar .sp-back {
  color: var(--tj-brand);
}
.sp-wrap.sp-tipjar .sp-kicker {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--tj-replace);
}
.sp-wrap.sp-tipjar .sp-kicker::before {
  content: "";
  width: 26px;
  height: 2px;
  background: var(--tj-replace);
}
.sp-wrap.sp-tipjar .sp-mast h1 {
  font-family: var(--tj-serif);
  color: var(--tj-ink);
}
.sp-wrap.sp-tipjar .dek {
  font-family: var(--tj-serif);
  color: var(--tj-ink-2);
  border-bottom: 2px solid var(--tj-ink);
  padding-bottom: 24px;
}
.sp-wrap.sp-tipjar .sp-prose {
  font-family: var(--tj-serif);
  color: var(--tj-ink-2);
}
.sp-wrap.sp-tipjar .sp-prose h2 {
  font-family: var(--tj-serif);
  color: var(--tj-ink);
}
.sp-wrap.sp-tipjar .sp-prose li::marker {
  color: var(--tj-brand);
}
.sp-wrap.sp-tipjar .sp-prose b {
  color: var(--tj-ink);
}
.sp-wrap.sp-tipjar .tip-list--amounts {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.sp-wrap.sp-tipjar .tip-amount-btn {
  min-width: 96px;
  padding: 16px 22px;
  background: var(--tj-paper-2);
  border: 1.5px solid var(--tj-rule);
  border-radius: 12px;
  font-family: var(--tj-serif);
  color: var(--tj-ink);
  box-shadow:
    0 1px 0 oklch(0.92 0.012 85),
    0 12px 30px -22px oklch(0.2 0.03 255 / 0.18);
}
.sp-wrap.sp-tipjar .tip-amount-btn:hover {
  border-color: var(--tj-brand);
  background: var(--tj-paper-2);
  color: var(--tj-brand);
}
.sp-wrap.sp-tipjar .tip-amount-btn.lead {
  background: var(--tj-brand);
  color: var(--tj-paper-2);
  border-color: var(--tj-brand);
}
.sp-wrap.sp-tipjar .tip-note {
  font-family: var(--tj-mono);
  color: var(--tj-ink-3);
  text-align: left;
}

/* ---------- About — Bold Flag / Keystone parity (08a-about) ----------
   Locally-scoped white-palette tokens matching design-handoff/keystone-canvas
   src/screens.css .screen[data-palette="white"] + statics.css .sp-mast/
   .sp-kicker/.dek/.sp-prose rules. Scoped to .sp-about only — does not touch
   the shared civic palette or any other static page. */
.sp-wrap.sp-about {
  --ab-paper: oklch(1 0 0);
  --ab-paper-2: oklch(0.985 0.003 258);
  --ab-ink: oklch(0.2 0.035 260);
  --ab-ink-2: oklch(0.37 0.032 260);
  --ab-ink-3: oklch(0.54 0.026 260);
  --ab-brand: oklch(0.4 0.155 262);
  --ab-rule: oklch(0.88 0.006 260);
  --ab-replace: oklch(0.53 0.205 27);
  --ab-tag-bg: oklch(0.95 0.006 260);
  --ab-serif: "Newsreader", Georgia, serif;
  --ab-mono: "IBM Plex Mono", ui-monospace, monospace;
  background: var(--ab-paper);
}
.sp-wrap.sp-about .sp-back {
  color: var(--ab-brand);
}
.sp-wrap.sp-about .sp-kicker {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--ab-replace);
}
.sp-wrap.sp-about .sp-kicker::before {
  content: "";
  width: 26px;
  height: 2px;
  background: var(--ab-replace);
}
.sp-wrap.sp-about .sp-mast h1 {
  font-family: var(--ab-serif);
  color: var(--ab-ink);
}
.sp-wrap.sp-about .dek {
  font-family: var(--ab-serif);
  font-size: 19px;
  color: var(--ab-ink-2);
  border-bottom: 2px solid var(--ab-ink);
  padding-bottom: 24px;
}
.sp-wrap.sp-about .sp-prose {
  font-family: var(--ab-serif);
  color: var(--ab-ink-2);
}
.sp-wrap.sp-about .sp-prose h2 {
  font-family: var(--ab-serif);
  color: var(--ab-ink);
}
.sp-wrap.sp-about .sp-prose b {
  color: var(--ab-ink);
}
.sp-wrap.sp-about .sp-prose ul {
  list-style: none;
  padding-left: 0;
}
.sp-wrap.sp-about .sp-prose li {
  padding-left: 26px;
  position: relative;
}
.sp-wrap.sp-about .sp-prose li::before {
  content: "";
  position: absolute;
  left: 6px;
  top: 8px;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--ab-brand);
  transform: rotate(45deg);
}
.sp-wrap.sp-about .sp-prose a {
  color: var(--ab-brand);
}
.sp-wrap.sp-about .sp-prose code {
  background: var(--ab-tag-bg);
  color: var(--ab-ink);
}

/* ---------- Methodology — Bold Flag / Keystone parity (08b-howitworks) ----------
   Locally-scoped white-palette tokens matching design-handoff/keystone-canvas
   src/screens.css .screen[data-palette="white"] + statics.css .sp-step.
   Scoped to .sp-methodology only — does not touch the shared civic palette or
   any other static page. */
.sp-wrap.sp-methodology {
  --mt-paper: oklch(1 0 0);
  --mt-paper-2: oklch(0.985 0.003 258);
  --mt-ink: oklch(0.2 0.035 260);
  --mt-ink-2: oklch(0.37 0.032 260);
  --mt-ink-3: oklch(0.54 0.026 260);
  --mt-brand: oklch(0.4 0.155 262);
  --mt-gold: oklch(0.72 0.125 76);
  --mt-rule: oklch(0.88 0.006 260);
  --mt-rule-2: oklch(0.93 0.005 260);
  --mt-replace: oklch(0.53 0.205 27);
  --mt-serif: "Newsreader", Georgia, serif;
  --mt-mono: "IBM Plex Mono", ui-monospace, monospace;
  background: var(--mt-paper);
}
.sp-wrap.sp-methodology .sp-back {
  color: var(--mt-brand);
}
.sp-wrap.sp-methodology .sp-kicker {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--mt-replace);
}
.sp-wrap.sp-methodology .sp-kicker::before {
  content: "";
  width: 26px;
  height: 2px;
  background: var(--mt-replace);
}
.sp-wrap.sp-methodology .sp-mast h1 {
  font-family: var(--mt-serif);
  color: var(--mt-ink);
}
.sp-wrap.sp-methodology .dek {
  font-family: var(--mt-serif);
  color: var(--mt-ink-2);
  border-bottom: 2px solid var(--mt-ink);
  padding-bottom: 24px;
}
.sp-wrap.sp-methodology .sp-prose {
  font-family: var(--mt-serif);
  color: var(--mt-ink-2);
}
.sp-wrap.sp-methodology .sp-prose h2 {
  font-family: var(--mt-serif);
  color: var(--mt-ink);
}
.sp-wrap.sp-methodology .sp-prose b {
  color: var(--mt-ink);
}
.sp-wrap.sp-methodology .sp-prose a {
  color: var(--mt-brand);
}
.sp-wrap.sp-methodology .sp-step {
  display: grid;
  grid-template-columns: 38px 1fr;
  gap: 16px;
  padding: 18px 0;
  border-top: 1px solid var(--mt-rule-2);
}
.sp-wrap.sp-methodology .sp-step .n {
  font-family: var(--mt-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--mt-paper-2);
  background: var(--mt-brand);
  width: 32px;
  height: 32px;
  border-radius: 8px;
  display: grid;
  place-items: center;
}
.sp-wrap.sp-methodology .sp-step:nth-child(even) .n {
  background: var(--mt-gold);
  color: var(--mt-ink);
}
.sp-wrap.sp-methodology .sp-step h3 {
  font-family: var(--mt-serif);
  font-weight: 600;
  font-size: 19px;
  margin: 4px 0 6px;
  color: var(--mt-ink);
  letter-spacing: -0.01em;
}
.sp-wrap.sp-methodology .sp-step p {
  font-family: var(--mt-serif);
  font-size: 16px;
  line-height: 1.55;
  color: var(--mt-ink-2);
  margin: 0;
}
.sp-wrap.sp-methodology .sp-step a {
  color: var(--mt-brand);
}

/* ---------- Why Now — Bold Flag / Keystone parity (07-whynow) ----------
   WhyNow never used the shared StaticPage shell — canvas's own WhyNow
   (design-handoff/keystone-canvas/src/screens-whynow.jsx + whynow.css)
   isn't part of the StaticPageVC family either, it's its own long-form
   editorial layout. This is a literal class-token port of that layout's
   content sections (wn-mast/wn-sec/wn-h2/wn-cols/wn-body/wn-stats/wn-stat/
   wn-pull/wn-ballot/wn-steps/wn-step/wn-cta) — the canvas's page chrome
   (flagbar/SCNav) is intentionally not replicated since App2.tsx's own
   AppNav already renders equivalent chrome around every stage. Scoped to
   .wn-wrap only — does not touch the shared civic palette or any other
   page. */
.wn-wrap {
  --wn-paper: oklch(1 0 0);
  --wn-paper-2: oklch(0.985 0.003 258);
  --wn-ink: oklch(0.2 0.035 260);
  --wn-ink-2: oklch(0.37 0.032 260);
  --wn-ink-3: oklch(0.54 0.026 260);
  --wn-brand: oklch(0.4 0.155 262);
  --wn-brand-2: oklch(0.31 0.145 262);
  --wn-gold: oklch(0.72 0.125 76);
  --wn-replace: oklch(0.53 0.205 27);
  --wn-rule: oklch(0.88 0.006 260);
  --wn-rule-2: oklch(0.93 0.005 260);
  --wn-shadow-soft:
    0 1px 0 oklch(0.92 0.012 85), 0 12px 30px -22px oklch(0.2 0.03 255 / 0.18);
  --wn-serif: "Newsreader", Georgia, serif;
  --wn-sans: "IBM Plex Sans", system-ui, sans-serif;
  --wn-mono: "IBM Plex Mono", ui-monospace, monospace;
  background: var(--wn-paper);
  color: var(--wn-ink);
  min-height: calc(100vh - 64px);
}
.wn-back {
  display: block;
  background: transparent;
  border: 0;
  color: var(--wn-brand);
  font-size: 13.5px;
  padding: 20px 90px 0;
  cursor: pointer;
}
.wn-back:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.wn-mast {
  padding: 40px 0 40px;
  border-bottom: 2px solid var(--wn-ink);
  margin: 0 90px;
  text-align: center;
}
.wn-mast .ey {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 18px;
  font-family: var(--wn-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--wn-replace);
}
.wn-mast h1 {
  font-family: var(--wn-serif);
  font-weight: 600;
  font-size: 76px;
  line-height: 0.96;
  letter-spacing: -0.035em;
  margin: 0;
  color: var(--wn-ink);
}
.wn-mast h1 em {
  font-style: italic;
  color: var(--wn-brand);
}
.wn-mast .dek {
  font-family: var(--wn-serif);
  font-size: 21px;
  line-height: 1.45;
  color: var(--wn-ink-2);
  margin: 18px auto 0;
  max-width: 660px;
  text-wrap: balance;
}
.wn-sec {
  padding: 52px 90px;
  border-bottom: 1px solid var(--wn-rule-2);
}
.wn-sec.alt {
  background: var(--wn-paper-2);
}
.wn-sec.brand {
  background: var(--wn-brand);
  color: oklch(0.96 0.02 262);
  border-bottom: none;
}
.wn-kicker {
  font-family: var(--wn-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--wn-replace);
  margin-bottom: 14px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.wn-kicker::before {
  content: "";
  width: 26px;
  height: 2px;
  background: var(--wn-replace);
}
.wn-sec.brand .wn-kicker {
  color: var(--wn-gold);
}
.wn-sec.brand .wn-kicker::before {
  background: var(--wn-gold);
}
.wn-h2 {
  font-family: var(--wn-serif);
  font-weight: 600;
  font-size: 42px;
  line-height: 1.06;
  letter-spacing: -0.02em;
  margin: 0 0 22px;
  color: var(--wn-ink);
  text-wrap: balance;
  max-width: 880px;
}
.wn-sec.brand .wn-h2 {
  color: oklch(0.99 0.01 262);
  max-width: 940px;
}
.wn-h2 em {
  font-style: italic;
  color: var(--wn-brand);
}
.wn-sec.brand .wn-h2 em {
  color: var(--wn-gold);
  font-style: normal;
}
.wn-cols {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: 48px;
  align-items: start;
}
.wn-body {
  font-size: 17.5px;
  line-height: 1.62;
  color: var(--wn-ink-2);
  max-width: 620px;
}
.wn-body p {
  margin: 0 0 16px;
}
.wn-body p:last-child {
  margin-bottom: 0;
}
.wn-body b {
  color: var(--wn-ink);
  font-weight: 600;
}
.wn-body .lead-in {
  font-variant: small-caps;
  letter-spacing: 0.03em;
  font-weight: 600;
  color: var(--wn-ink);
  font-size: 0.92em;
}
.wn-sec.brand .wn-body {
  color: oklch(0.92 0.02 262);
}
.wn-sec.brand .wn-body b {
  color: oklch(1 0 0);
}
.wn-stats {
  display: grid;
  gap: 18px;
}
.wn-stat {
  border: 1px solid var(--wn-rule);
  border-radius: 14px;
  background: var(--wn-paper);
  padding: 22px 24px;
  box-shadow: var(--wn-shadow-soft);
}
.wn-stat.red {
  border-color: oklch(0.8 0.1 27);
}
.wn-stat .v {
  font-family: var(--wn-serif);
  font-weight: 600;
  font-size: 60px;
  line-height: 0.92;
  letter-spacing: -0.03em;
  color: var(--wn-brand);
}
.wn-stat.red .v {
  color: var(--wn-replace);
}
.wn-stat .v small {
  font-size: 22px;
  font-weight: 500;
  letter-spacing: 0;
  margin-left: 4px;
  color: var(--wn-ink-3);
}
.wn-stat .l {
  font-size: 14px;
  line-height: 1.5;
  color: var(--wn-ink-2);
  margin-top: 12px;
}
.wn-stat .cite {
  font-family: var(--wn-mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--wn-ink-3);
  margin-top: 12px;
  padding-top: 11px;
  border-top: 1px solid var(--wn-rule-2);
}
.wn-pull {
  font-family: var(--wn-serif);
  font-weight: 500;
  font-size: 34px;
  line-height: 1.22;
  letter-spacing: -0.015em;
  color: var(--wn-ink);
  max-width: 900px;
  margin: 0;
  text-wrap: balance;
}
.wn-pull em {
  font-style: italic;
  color: var(--wn-brand);
}
.wn-pull .src {
  display: block;
  font-family: var(--wn-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--wn-ink-3);
  margin-top: 20px;
}
.wn-ballot {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  margin-top: 36px;
  border: 1px solid oklch(1 0 0 / 0.16);
  border-radius: 14px;
  overflow: hidden;
}
.wn-ballot .cell {
  padding: 26px 24px;
}
.wn-ballot .cell + .cell {
  border-left: 1px solid oklch(1 0 0 / 0.16);
}
.wn-ballot .v {
  font-family: var(--wn-serif);
  font-weight: 600;
  font-size: 52px;
  line-height: 0.95;
  letter-spacing: -0.03em;
  color: oklch(1 0 0);
}
.wn-ballot .v.gold {
  color: var(--wn-gold);
}
.wn-ballot .l {
  font-size: 13.5px;
  line-height: 1.45;
  color: oklch(0.9 0.02 262);
  margin-top: 10px;
}
.wn-steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  margin-top: 8px;
}
.wn-step {
  border: 1px solid var(--wn-rule);
  border-radius: 14px;
  background: var(--wn-paper);
  padding: 26px 24px;
  box-shadow: var(--wn-shadow-soft);
  position: relative;
  overflow: hidden;
}
.wn-step::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: var(--wn-brand);
}
.wn-step:nth-child(2)::before {
  background: var(--wn-gold);
}
.wn-step:nth-child(3)::before {
  background: var(--wn-replace);
}
.wn-step .n {
  font-family: var(--wn-mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--wn-paper-2);
  background: var(--wn-brand);
  width: 30px;
  height: 30px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  margin-bottom: 16px;
}
.wn-step:nth-child(2) .n {
  background: var(--wn-gold);
  color: var(--wn-ink);
}
.wn-step:nth-child(3) .n {
  background: var(--wn-replace);
}
.wn-step h3 {
  font-family: var(--wn-serif);
  font-weight: 600;
  font-size: 22px;
  letter-spacing: -0.01em;
  margin: 0 0 8px;
  color: var(--wn-ink);
}
.wn-step p {
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--wn-ink-3);
  margin: 0;
}
.wn-step .tag {
  font-family: var(--wn-mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wn-brand);
  font-weight: 700;
  margin-top: 14px;
  display: inline-block;
}
.wn-cta {
  padding: 60px 90px;
  text-align: center;
  background: var(--wn-paper-2);
}
.wn-cta h2 {
  font-family: var(--wn-serif);
  font-weight: 600;
  font-size: 40px;
  letter-spacing: -0.02em;
  margin: 0 0 12px;
  color: var(--wn-ink);
  text-wrap: balance;
}
.wn-cta p {
  font-size: 16px;
  color: var(--wn-ink-2);
  margin: 0 auto 26px;
  max-width: 540px;
}
.wn-cta .btn-primary {
  background: var(--wn-brand);
  color: var(--wn-paper-2);
  border: none;
  border-radius: 10px;
  font-family: var(--wn-sans);
  font-weight: 600;
  font-size: 16px;
  padding: 16px 26px;
  min-height: 56px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  box-shadow: var(--wn-shadow-soft);
}
.wn-cta .btn-primary:hover {
  background: var(--wn-brand-2);
}
.wn-cta .sub {
  font-family: var(--wn-mono);
  font-size: 11px;
  color: var(--wn-ink-3);
  margin-top: 16px;
  letter-spacing: 0.02em;
}
@media (max-width: 900px) {
  .wn-back,
  .wn-sec,
  .wn-cta {
    padding-left: 32px;
    padding-right: 32px;
  }
  .wn-mast {
    margin: 0 32px;
  }
  .wn-mast h1 {
    font-size: 48px;
  }
  .wn-cols,
  .wn-ballot,
  .wn-steps {
    grid-template-columns: 1fr;
  }
  .wn-ballot .cell + .cell {
    border-left: none;
    border-top: 1px solid oklch(1 0 0 / 0.16);
  }
}

/* ---------- Privacy — Bold Flag / Keystone parity (08c-privacy) ----------
   Locally-scoped white-palette tokens matching design-handoff/keystone-canvas
   src/screens.css .screen[data-palette="white"] + statics.css .sp-* rules.
   Scoped to .sp-privacy only — does not touch the shared civic palette or
   any other static page. */
.sp-wrap.sp-privacy {
  --pv-paper: oklch(1 0 0);
  --pv-paper-2: oklch(0.985 0.003 258);
  --pv-ink: oklch(0.2 0.035 260);
  --pv-ink-2: oklch(0.37 0.032 260);
  --pv-ink-3: oklch(0.54 0.026 260);
  --pv-brand: oklch(0.4 0.155 262);
  --pv-rule: oklch(0.88 0.006 260);
  --pv-replace: oklch(0.53 0.205 27);
  --pv-tag-bg: oklch(0.95 0.006 260);
  --pv-serif: "Newsreader", Georgia, serif;
  --pv-mono: "IBM Plex Mono", ui-monospace, monospace;
  background: var(--pv-paper);
}
.sp-wrap.sp-privacy .sp-back {
  color: var(--pv-brand);
}
.sp-wrap.sp-privacy .sp-kicker {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--pv-replace);
}
.sp-wrap.sp-privacy .sp-kicker::before {
  content: "";
  width: 26px;
  height: 2px;
  background: var(--pv-replace);
}
.sp-wrap.sp-privacy .sp-mast h1 {
  font-family: var(--pv-serif);
  color: var(--pv-ink);
}
.sp-wrap.sp-privacy .dek {
  font-family: var(--pv-serif);
  font-size: 19px;
  color: var(--pv-ink-2);
  border-bottom: 2px solid var(--pv-ink);
  padding-bottom: 24px;
}
.sp-wrap.sp-privacy .sp-meta {
  color: var(--pv-ink-3);
}
.sp-wrap.sp-privacy .sp-prose {
  font-family: var(--pv-serif);
  color: var(--pv-ink-2);
}
.sp-wrap.sp-privacy .sp-prose h2 {
  font-family: var(--pv-serif);
  color: var(--pv-ink);
}
.sp-wrap.sp-privacy .sp-prose b {
  color: var(--pv-ink);
}
.sp-wrap.sp-privacy .sp-prose i {
  color: var(--pv-ink);
}
.sp-wrap.sp-privacy .sp-prose a {
  color: var(--pv-brand);
}
.sp-wrap.sp-privacy .sp-prose code {
  background: var(--pv-tag-bg);
  color: var(--pv-ink);
}

/* ---------- Edit-issues modal — Bold Flag / Keystone parity (09d-edit-issues) ----------
   Locally-scoped white/navy/red palette, values lifted verbatim from canvas's own
   design-handoff/design_handoff_voter_choice_redesign/screens.css
   .screen[data-palette="white"] block ("PALETTE B — Bold Flag"), the palette behind
   screens-intake.jsx's EditIssues (.amd-modal). EditIssuesModal.tsx keeps its own
   amend- / be- prefixed class names (see parity-gate.ts's 09d-edit-issues waiver) but
   they — and every shared IssueConversation/IssueRow class nested inside them
   (.msg/.bubble/.themes-card/.theme-row/.co-input/etc, also used un-scoped by the
   already-passing 09a/09b/09c intake scenarios) — all read the same global design
   tokens. Re-declaring those tokens on .amend-modal cascades the Keystone palette
   to every descendant without touching the shared civic-mood default those other
   scenarios still rely on. Scoped to .amend-modal only. */
.amend-modal {
  --paper: oklch(1 0 0);
  --paper-2: oklch(0.985 0.003 258);
  --rule: oklch(0.88 0.006 260);
  --rule-2: oklch(0.93 0.005 260);
  --ink: oklch(0.2 0.035 260);
  --ink-2: oklch(0.37 0.032 260);
  --ink-3: oklch(0.54 0.026 260);
  --civic: oklch(0.4 0.155 262);
  --civic-2: oklch(0.31 0.145 262);
  --civic-soft: oklch(0.94 0.04 262);
  --vote-red: oklch(0.53 0.205 27);
  --tag-bg: oklch(0.95 0.006 260);
  --serif: "Newsreader", Georgia, serif;
  --mono: "IBM Plex Mono", ui-monospace, monospace;
}
/* Canvas's .iq-msg.user .iq-bubble is a soft navy-tinted bubble, not a solid-ink
   one — .msg.user .bubble's shared rule (background: var(--ink)) is the right
   call for the cold-open scenarios (09a/09b/09c) that already pass, so override
   it locally instead of changing the shared rule. */
.amend-modal .msg.user .bubble {
  background: var(--civic-soft);
  border: 1px solid oklch(0.84 0.05 262);
  color: var(--civic-2);
}
/* .chip/.chips are otherwise unstyled outside the .ws-input sidebar context —
   give the quick-reply chips a real pill treatment matching canvas's
   .amd-modal .iq-opt buttons instead of bare unstyled <button>s. */
.amend-modal .chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.amend-modal .chip {
  font-family: var(--sans);
  font-size: 13px;
  background: var(--paper);
  border: 1px solid var(--rule);
  color: var(--ink-2);
  padding: 9px 14px;
  border-radius: 999px;
  cursor: pointer;
}
.amend-modal .chip:hover:not(:disabled) {
  border-color: var(--civic);
  color: var(--ink);
}
.amend-modal .chip:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ---------- Intake main flow (09a/09b/09c) — visual-parity pass ----------
   The .amend-modal chip/AI-bubble treatment above was only ever scoped to
   the edit-issues modal; the main ask/propose/locked flow (redesign/IntakeView,
   IssueConversation, IntakeLocked — all rendered inside .coldopen, only under
   the Keystone/.bf-app experience) never got the same pass. Canvas's
   screens-intake.jsx renders AI turns as bare serif text (.iq-bubble has no
   border/background) and gives quick-reply chips a real pill (.iq-opt), not
   bare <button>s. Scoped to `.bf-app .coldopen` so the legacy ballot-mode
   ColdOpenView (VoterChoiceApp.tsx, same shared classnames, gated off .bf-app)
   is untouched. */
.bf-app .coldopen .msg.ai .bubble,
.amend-modal .msg.ai .bubble {
  background: none;
  border: none;
  padding: 0;
}
.bf-app .coldopen .chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.bf-app .coldopen .chip {
  font-family: var(--sans);
  font-size: 13px;
  background: var(--paper);
  border: 1px solid var(--rule);
  color: var(--ink-2);
  padding: 9px 14px;
  border-radius: 999px;
  cursor: pointer;
}
.bf-app .coldopen .chip:hover:not(:disabled) {
  border-color: var(--brand);
  color: var(--ink);
}
.bf-app .coldopen .chip:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
/* Canvas's .iq-ctx context line is plain-case mono with no leading dot
   marker — .co-context's shared rule adds both (uppercase + a colored
   ::before dot) for the civic-mood default. Scoped undo for Keystone. */
.bf-app .coldopen .co-context {
  text-transform: none;
}
.bf-app .coldopen .co-context::before {
  content: none;
}
/* Canvas's .iq-card has a uniform 1px border, no colored top accent —
   .themes-card's shared rule adds a 3px brand-colored top border. */
.bf-app .themes-card {
  border-top-width: 1px;
}
/* Canvas's .iq-privacy hint is sentence-case, not shouty caps. */
.bf-app .coldopen .co-input .hint,
.amend-modal .co-input .hint {
  text-transform: none;
}

/* Canvas's IntakeAsk hero (.iq-ask kicker + h1 + intro paragraph,
   intake.css:99-103) — only shown pre-conversation (IntakeView.tsx gates
   it on convo.log.length === 0). Follows the same kick/star kicker idiom
   as OrientationView's .ori-ey (redesign2.css:2661), sized per canvas's
   own .iq-ask spec rather than reusing .ori-card's 40px. */
.bf-app .coldopen .ask-hero {
  margin-bottom: 22px;
}
.bf-app .coldopen .ask-hero .kick {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--brand);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 16px;
}
.bf-app .coldopen .ask-hero h1 {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 38px;
  line-height: 1.08;
  letter-spacing: -0.02em;
  margin: 0 0 12px;
  color: var(--ink);
  text-wrap: balance;
}
.bf-app .coldopen .ask-hero h1 em {
  font-style: italic;
  color: var(--brand);
}
.bf-app .coldopen .ask-hero p {
  font-family: var(--serif);
  font-size: 17px;
  line-height: 1.5;
  color: var(--ink-2);
  margin: 0;
  max-width: 560px;
}

/* ---------- Intake Round 3 — jurisdiction pill (card 9143a622: "every
   issue carries a JURISDICTION tag") ----------
   Canvas's IqRow accepts a `juris` prop (screens-intake.jsx) but the local
   snapshot never renders it — intake.css already ships the pill's styling
   (.iq-juris/.fed/.state), just unwired. themesToIssues (IssueConversation.tsx)
   now resolves each issue's level via the same canonical-issue→jurisdiction
   lookup the workspace itself uses post-lock (getIssueLevel); IssueRow
   renders the pill only once a level actually resolved — a custom issue
   with no canonical match gets no pill rather than a guess (honest-data).
   `.both` has no canvas precedent (the artboard only shows FEDERAL/STATE
   examples); styled neutral with --tag-bg so it doesn't compete with the
   two decisive fed/state colors, since "both" is in fact the most common
   lean in ISSUE_JURISDICTION_LEAN. Scoped to .bf-app rather than narrowly
   to .coldopen — IssueRow is shared by the live conversation (.coldopen),
   the locked confirm screen (.issue-locked-confirm), and the edit-issues
   modal (.amend-modal), all three of which need the pill styled. Legacy
   AmendmentEditor's own IssueRow usage (VoterChoiceApp.tsx, gated off
   .bf-app) never sets `issue.level`, so the pill JSX simply never renders
   there regardless of this CSS. */
.bf-app .iq-juris {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  white-space: nowrap;
  flex-shrink: 0;
}
.bf-app .iq-juris.fed {
  background: var(--brand-soft);
  color: var(--brand-2);
}
.bf-app .iq-juris.state {
  background: oklch(0.93 0.05 78);
  color: oklch(0.46 0.1 70);
}
.bf-app .iq-juris.both {
  background: var(--tag-bg);
  color: var(--ink-2);
}

/* ---------- Intake Round 3.1 correction — locked-state jurisdiction
   breakdown renders as PILLS, not a text line ----------
   The live canvas source (2026-07-11 edits, .keystone-canvas-refs postdate
   this) settled `.jbreak` as two REUSED `.iq-juris fed`/`.iq-juris state`
   pills — literally `<span className="iq-juris fed">2 Federal</span>` —
   not a mono uppercase text line with a "·" separator, which is what this
   section originally shipped (a reasonable guess before the live source
   was available, now corrected). `.jbreak` itself is just the flex
   container; all the visible styling comes from the SAME `.iq-juris`/
   `.fed`/`.state` pill rules the rows above already use, so the "your
   issues are set" banner echoes the exact pill look, not a re-invented
   text treatment. Counts still come from issuesForLevel (delegationData.ts,
   unchanged). */
.bf-app .iq-locked .jbreak {
  margin-left: auto;
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

/* ---------- Intake Round 3 — "Lock these in" prominence (card 4b7e5a66)
   ----------
   The lock CTA is the one true commit moment in the flow — IssueConversation's
   "Lock these in" click transitions into the confirm screen, and IntakeLocked's
   own confirm button is what actually fires onLock; both surface the same
   primaryBtn copy — but wore ordinary footer/button weight. IntakeLocked's
   confirm button in particular reused the bare `.send` class, identical to a
   mid-conversation chat Send. `.ready` marks the footer as the flow's
   capstone; `.lock-cta` gives the button sub-label room and a heavier brand
   shadow. Both are opt-in via JSX: IssueConversation only adds them when
   passed a primarySubLabel, which only IntakeView supplies — EditIssuesModal's
   re-score "Apply" keeps ordinary weight, since review has already started
   for that flow. IntakeLocked's confirm is always the real lock, so it
   always gets the treatment. */
.bf-app .th-foot.ready {
  border-top: 2px solid var(--brand);
  padding-top: 20px;
}
.bf-app .th-foot.ready .lock-cta {
  width: 100%;
  justify-content: center;
}
.bf-app .co-input.ready {
  border-top: 2px solid var(--brand);
  /* Literal port of the live canvas's `.iq-foot.ready` (padding-top: 17px;
     padding-bottom: 19px;) — an asymmetric pair, not the flat 20px this
     section originally shipped. Horizontal padding is unaffected (still
     the base composer band's 14px/30px). */
  padding-top: 17px;
  padding-bottom: 19px;
}
/* Literal port of the live canvas's `.iq-foot.ready .iq-lock` +
   `.iq-lock-sub`. Shared by BOTH ready-state lock buttons (IntakeLocked's
   own confirm button — the direct canvas equivalent — and
   IssueConversation's in-card "Lock these in" button, a repo-only
   additive affordance canvas doesn't have but which intentionally reuses
   the same capstone weight per the original Round-3 decision). */
.bf-app .lock-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  min-height: 62px;
  padding: 12px 20px;
  box-shadow:
    0 12px 26px -10px color-mix(in oklch, var(--brand) 50%, transparent),
    var(--shadow-soft);
}
.bf-app .lock-cta .lock-label {
  font-size: 16.5px;
  letter-spacing: -0.005em;
}
.bf-app .lock-cta .lock-sub {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0.02em;
  text-transform: none;
  color: oklch(0.94 0.02 262);
}

/* ---------- Intake Round 3 — privacy line reposition ----------
   Canvas's .iq-privacy is its own centered full-width line BELOW the whole
   footer with a leading colored dot marker (intake.css); the port had it
   inline beside the Send button instead (.co-input .row .hint). Content was
   already right (intake.inputHint) — this only moves it. New class, not a
   reuse of `.hint`, so the existing `.hint` mobile-reflow rules (still used
   by the legacy composer) are untouched. Applied to both IssueConversation's
   ordinary composer and IntakeLocked's confirm row, replacing the latter's
   ad-hoc inline style with the same shared treatment. */
.bf-app .co-privacy {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--ink-3);
  margin-top: 9px;
  text-align: center;
}
/* Literal port of the live canvas's `.iq-privacy .dot { color: var(--keep) }`.
   `--keep` is only defined locally inside `.issue-locked-confirm`
   (redesign2.css, IntakeLocked's own scope) — that already covers the
   `.ready` composer's dot, but `.co-privacy` ALSO renders inside
   IssueConversation's ordinary composer (`.issue-convo`, no local
   mapping), where an unmapped `--keep` would resolve to nothing. Defining
   it once here, on the shared `.coldopen` ancestor of both contexts,
   keeps the token name identical to canvas's (`var(--keep)`, not a
   substituted `var(--civic)`) while resolving correctly everywhere the
   dot renders — mapped onto `--civic`, the same "alignment keep green"
   token the .bf-app root block already documents as deliberately left
   unmapped for exactly this purpose. */
.bf-app .coldopen {
  --keep: var(--civic);
}
.bf-app .co-privacy .dot {
  color: var(--keep);
}

/* ---------- Intake Round 3.1 — composer chrome parity ----------
   Muxin's verdict on the Round-3 build: "I like the Design version of the
   chat box and how it looks like its own separate grey section with a
   white box. It just looks a lot nicer and neater and cleaner compared to
   the chat version in our repo." Canvas's composer is TWO nested layers
   (intake.css .iq-foot/.iq-composer): a full-width grey footer TRENCH
   (top rule only, no boxed card) that reaches the .iq shell's full width
   while the conversation stage above stays inset — holding a WHITE
   rounded textarea sitting inline next to Send. Ours was one uniform grey
   box (.co-input's own background + border + radius) with a transparent
   textarea (no white/grey contrast at all) and the Send button on its own
   row below instead of alongside.

   Bleeds past .coldopen's own side padding (32px desktop / 18px at the
   ≤640px breakpoint — prototype.css:921, prototype-c.css:1868) so the
   band spans edge-to-edge of the content column the way canvas's footer
   reaches its shell's full width. ONE known, deliberate structural gap
   from a literal port: canvas's `.iq` shell has no width cap at all (the
   footer trench spans the full browser viewport, with only `.iq-foot-inner`
   capped at 760px/centered inside it) — `.coldopen` itself is already
   `max-width: 760px; margin: 0 auto` (prototype.css:919), so this bleed
   only reaches that 760px column's own edges, not the true viewport edge.
   Restructuring `.coldopen` to be viewport-width (matching AppNav above
   it) is a page-shell-level change touching every other .coldopen view,
   out of scope for a composer-chrome fix — the PADDING values inside the
   band (14px 30px) are still ported literally from `.iq-foot`'s own rule,
   and the composer's own content is already inherently 760px-capped/
   centered by .coldopen's existing max-width, satisfying the
   `.iq-foot-inner` requirement without a separate wrapper. Scoped to
   `.coldopen .co-input` only — IssueConversation's composer is ALSO reused
   inside .amend-modal (the edit-issues modal), where canvas keeps the
   plain, unbanded `.amd-composer` (screens-intake.jsx's EditIssues never
   wraps it in .iq-foot) — so the modal composer is intentionally left
   alone. */
.bf-app .coldopen .co-input {
  border: none;
  border-top: 1px solid var(--rule-2);
  border-radius: 0;
  margin-left: -32px;
  margin-right: -32px;
  width: calc(100% + 64px);
  padding: 14px 30px;
}
.bf-app .coldopen .co-composer {
  display: flex;
  gap: 10px;
  align-items: flex-end;
}
.bf-app .coldopen .co-composer textarea {
  flex: 1;
  min-width: 0;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 11px;
  padding: 13px 15px;
  min-height: 50px;
  /* Literal 14px — the base .co-input textarea rule (prototype.css) sets
     15px/line-height:1.55 for the legacy composer; both overridden here. */
  font-size: 14px;
  line-height: 1.4;
  resize: none;
}
.bf-app .coldopen .co-composer .send {
  min-height: 50px;
  padding: 0 20px;
  border-radius: 11px;
  flex-shrink: 0;
  box-shadow: var(--shadow-soft);
  /* Literal 14px — the base .co-input .send rule (prototype.css) sets
     13.5px. */
  font-size: 14px;
  /* The ≤640px `.co-input .send { width: 100% }` rule below (this file,
     legacy stacked-column composer) has lower specificity but no width
     reset here previously let it leak into this flex row: the button's
     flex-basis (auto) then resolved from that 100% width against the
     composer's own box, forcing it to claim the full row and pushing the
     textarea to ~0, overflowing the viewport at mobile widths. */
  width: auto;
}
@media (max-width: 640px) {
  .bf-app .coldopen .co-input {
    margin-left: -18px;
    margin-right: -18px;
    width: calc(100% + 36px);
    padding: 14px 18px;
  }
}

/* ---------- Intake Round 3.1 — compact issue-row density ----------
   Muxin's verdict: "The design version does a better job of showing, in a
   very clean way, the list of issues. That layout is just so much smaller
   and easier to read compared to our layout." Canvas's IqRow (intake.css
   .iq-row, lines 36-47) is a small bordered/rounded chip: a neutral
   15px rank, a bold-but-modest title, ONE tiny mono quote line, tight
   11px/12px padding — versus our .theme-row's dashed-divider list with a
   28px display-serif rank number and roomy, unbordered 14px/0 rows.

   IssueRow is SHARED: the same component also renders inside the legacy
   ballot-mode AmendmentEditor and ColdOpenView (VoterChoiceApp.tsx, gated
   off .bf-app — untouched, never passes the variant). Rather than restyle
   .theme-row globally, IssueRow takes an opt-in `rowVariant="canvas"` prop
   (VoterChoiceApp.tsx) that adds a `.theme-row--canvas` modifier class.
   IssueReviewCard (IssueConversation.tsx) is the ONE shared card behind
   IntakeView's conversation, IntakeLocked, AND EditIssuesModal (all three
   Keystone call sites), so setting the prop there covers all of them —
   matching canvas, whose own EditIssues screen reuses the identical
   compact IqRow.

   Gated to the ≥1024px desktop range — the exact width this feedback was
   given against — so the already-tuned mobile (≤640px) and tablet
   (641–1023px, line ~4579) stacked touch layouts for this same grid are
   completely unaffected. The quote font-size needs `!important` to beat
   the unscoped a11y "Body text scale pass" bump above (line ~1994),
   which stays in effect for every other .theme-row context (including
   this one below 1024px) — this is a deliberate density trade only for
   the desktop canvas-matched treatment, not a rollback of that pass.

   Values below are ported literally from the live canvas's `.iq-row`
   family (padding: 11px 12px; gap: 11; border-radius: 11px; `.iq-rank`
   width:16px/text-align:center; `.iq-arrows`/`.iq-arrow` gap:1/16x13/8px
   with a brand hover; `.iq-name` 14.5px/500, unset family → inherits the
   app's sans default, NOT the serif/600 the base .theme-row .nm uses;
   `.iq-name .you` mono/10px/ink-3/400, no border or italic). Two
   deliberate, DOCUMENTED deviations from a literal 1:1 port, both to
   avoid dropping real data (never silently suppress a voter's own
   words): (1) canvas's IqRow takes a single `you` string; our IssueRow
   can carry MULTIPLE quotes per issue (`quotes: [{label, text}]`), so
   `.quotes`/`.quote` stays a list, each line re-styled to canvas's `.you`
   typography rather than collapsing to one line. (2) the tiny
   "example"/"and" `.lab` prefix distinguishing multiple quotes has no
   canvas counterpart (canvas never shows more than one) — kept, sized
   down to stay unobtrusive, rather than deleted outright. */
@media (min-width: 1024px) {
  .bf-app .theme-row--canvas {
    grid-template-columns: 16px 16px 1fr auto;
    gap: 11px;
    align-items: center;
    padding: 11px 12px;
    margin-bottom: 7px;
    border: 1px solid var(--rule-2);
    border-radius: 11px;
    background: var(--paper);
  }
  .bf-app .theme-row--canvas:last-of-type {
    padding-bottom: 11px;
    margin-bottom: 0;
  }
  .bf-app .theme-row--canvas .ord {
    margin-top: 0;
    gap: 1px;
  }
  .bf-app .theme-row--canvas .ord button {
    width: 16px;
    height: 13px;
    font-size: 8px;
  }
  .bf-app .theme-row--canvas .ord button:hover:not(:disabled) {
    color: var(--brand);
  }
  .bf-app .theme-row--canvas .rank {
    font-size: 15px;
    line-height: 1;
    margin-top: 0;
    text-align: center;
  }
  .bf-app .theme-row--canvas .nm {
    font-family: var(--sans);
    font-size: 14.5px;
    font-weight: 500;
    margin-bottom: 2px;
    gap: 6px;
  }
  .bf-app .theme-row--canvas .nm .edit-pencil {
    font-size: 8.5px;
    padding: 1px 5px;
  }
  .bf-app .theme-row--canvas .quotes {
    gap: 2px;
  }
  .bf-app .theme-row--canvas .quote {
    font-family: var(--mono);
    font-size: 10px !important;
    line-height: 1.4 !important;
    color: var(--ink-3);
    padding-left: 0;
    border-left: none;
  }
  .bf-app .theme-row--canvas .quote em {
    font-style: normal;
  }
  .bf-app .theme-row--canvas .quote .lab {
    font-size: 8px;
    margin-right: 4px;
  }
  .bf-app .theme-row--canvas .acts {
    gap: 4px;
  }
  .bf-app .theme-row--canvas .acts button {
    font-size: 8.5px;
    padding: 1px 0;
  }
}

/* ============ NoContestedView — upload-first redesign ============
   Promotes the file upload to a big dropzone-style button at the
   top, with the paste textarea as the secondary path below. Adds
   a multi-step processing state with a real progress UI so users
   know the AI is working on their ballot. */
.nc-upload-card,
.nc-paste-card {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 18px 18px 18px;
  margin-bottom: 12px;
}
.nc-upload-eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
  margin-bottom: 12px;
}
.nc-upload-num {
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  background: var(--civic);
  color: var(--paper-2);
  border-radius: 50%;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0;
}

/* Big dropzone button — primary visual affordance. Civic border,
   icon + 2-line label, hover lifts to filled civic. */
.nc-upload-btn {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 16px 18px;
  background: var(--paper-2);
  border: 2px dashed var(--civic);
  border-radius: 10px;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--ink);
  transition:
    background 0.15s ease,
    border-style 0.15s ease;
}
.nc-upload-btn:hover {
  background: oklch(0.97 0.018 170);
  border-style: solid;
}
.nc-upload-ico {
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--civic);
  color: var(--paper-2);
  flex: 0 0 44px;
}
.nc-upload-lab {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.nc-upload-main {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 17px;
  color: var(--ink);
}
.nc-upload-sub {
  font-size: 13px;
  color: var(--ink-3);
  line-height: 1.45;
}

/* OR divider between upload + paste */
.nc-or {
  display: flex;
  align-items: center;
  text-align: center;
  margin: 18px 0;
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--ink-3);
}
.nc-or::before,
.nc-or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}
.nc-or span {
  padding: 0 14px;
}

/* Paste card (secondary path) */
.nc-paste-area {
  width: 100%;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: 12px 14px;
  font-family: var(--serif);
  font-size: 14px;
  resize: vertical;
  outline: none;
  min-height: 140px;
  margin-bottom: 12px;
}
.nc-paste-area:focus {
  border-color: var(--civic);
}
.nc-paste-card .nc-primary {
  width: 100%;
  justify-content: center;
}

.nc-foot {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px dashed var(--rule-2);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.nc-foot .nc-back {
  align-self: flex-start;
  padding: 10px 16px;
}

/* ============ Processing state ============ */
.nc-processing {
  padding: 8px 0;
}
.nc-proc-head h2 {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 26px;
  line-height: 1.15;
  letter-spacing: -0.015em;
  margin: 0 0 14px;
  color: var(--ink);
}
.nc-proc-file {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 24px;
  padding: 12px 14px;
  background: var(--paper);
  border: 1px solid var(--rule-2);
  border-radius: 8px;
  font-size: 13.5px;
}
.nc-proc-file-ico {
  color: var(--civic);
  display: inline-flex;
}
.nc-proc-file code {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink);
  background: transparent;
  padding: 0;
}
.nc-proc-file-size {
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: 11.5px;
}
.nc-proc-steps {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
  display: grid;
  gap: 4px;
}
.nc-proc-step {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 14px;
  background: var(--paper);
  border: 1px solid var(--rule-2);
  border-radius: 8px;
  font-size: 15px;
  line-height: 1.4;
  color: var(--ink-3);
  transition:
    background 0.2s ease,
    color 0.2s ease,
    border-color 0.2s ease;
}
.nc-proc-step.done {
  color: var(--ink-2);
}
.nc-proc-step.done .nc-proc-step-ico {
  background: oklch(0.62 0.13 145);
  color: var(--paper-2);
}
.nc-proc-step.active {
  background: oklch(0.97 0.018 170);
  border-color: var(--civic);
  color: var(--ink);
  font-weight: 600;
}
.nc-proc-step.active .nc-proc-step-ico {
  background: var(--civic);
  color: var(--paper-2);
}
.nc-proc-step-ico {
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--tag-bg);
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 700;
  flex: 0 0 28px;
}
.nc-proc-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid var(--paper-2);
  border-top-color: transparent;
  border-radius: 50%;
  animation: nc-spin 0.8s linear infinite;
}
@keyframes nc-spin {
  to {
    transform: rotate(360deg);
  }
}
.nc-proc-hint {
  margin: 0;
  padding: 14px 16px;
  background: var(--paper);
  border-left: 3px solid var(--gold);
  border-radius: 6px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-3);
  font-style: italic;
}

@media (max-width: 600px) {
  .nc-upload-btn {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding: 16px 14px;
  }
  .nc-upload-main {
    font-size: 16px;
  }
  .nc-upload-sub {
    font-size: 12.5px;
  }
  .nc-proc-head h2 {
    font-size: 22px;
  }
  .nc-proc-step {
    font-size: 14px;
    padding: 12px 12px;
  }
}

/* ============ Budget-exhausted ballot-pane footer ============
   Replaces the normal .b-foot stack when the AI budget runs out.
   Makes BYOK + handoff the dominant actions so "what's next" is
   obvious without opening the modal. */
.b-foot.exhausted {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.bx-banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  background: oklch(0.96 0.04 75);
  border: 1px solid oklch(0.86 0.08 75);
  border-radius: 8px;
}
.bx-banner-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--gold);
  margin-top: 6px;
  flex: 0 0 8px;
}
.bx-banner-ttl {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--ink);
}
.bx-banner-sub {
  font-size: 12.5px;
  color: var(--ink-2);
  margin-top: 2px;
}
.bx-cta {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 9px;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--ink);
}
.bx-cta:hover {
  border-color: var(--civic);
  background: oklch(0.97 0.018 170);
}
.bx-cta.primary {
  background: var(--civic);
  border-color: var(--civic);
  color: var(--paper-2);
}
.bx-cta.primary:hover {
  background: var(--civic-2);
}
.bx-cta-ico {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: oklch(1 0 0 / 0.18);
  flex: 0 0 32px;
  font-family: var(--mono);
  font-size: 15px;
}
.bx-cta:not(.primary) .bx-cta-ico {
  background: var(--tag-bg);
  color: var(--civic);
}
.bx-cta-lab {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1;
}
.bx-cta-main {
  font-weight: 600;
  font-size: 14px;
}
.bx-cta-sub {
  font-size: 11.5px;
  opacity: 0.85;
  line-height: 1.35;
}
.bx-cta .arrow {
  font-family: var(--mono);
  flex: 0 0 auto;
}
.bx-secondary {
  display: flex;
  gap: 8px;
}
.bx-secondary button {
  flex: 1;
  padding: 10px 12px;
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 8px;
  font-size: 12.5px;
  color: var(--ink-2);
  cursor: pointer;
}
.bx-secondary button:hover:not(:disabled) {
  border-color: var(--ink-2);
  color: var(--ink);
}
.bx-secondary button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.bx-tip {
  margin: 4px 0 0;
  font-family: var(--mono);
  font-style: italic;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  line-height: 1.6;
  text-align: center;
}
.bx-tip a {
  color: var(--civic);
  cursor: pointer;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ============ Post-decision toast ============
   One-time celebration + next-steps toast when the user decides
   every race. Slides up from the bottom, dismissable, never repeats
   (guarded by localStorage in the app). */
.pd-toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 800;
  width: calc(100% - 32px);
  max-width: 440px;
  background: var(--ink);
  color: var(--paper-2);
  border-radius: 14px;
  box-shadow: 0 20px 50px -16px oklch(0.18 0.018 240 / 0.5);
  padding: 18px 18px 16px;
  animation: pd-rise 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
}
@keyframes pd-rise {
  from {
    transform: translate(-50%, 16px);
    opacity: 0;
  }
  to {
    transform: translate(-50%, 0);
    opacity: 1;
  }
}
.pd-toast-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.pd-toast-ttl {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 18px;
  line-height: 1.2;
}
.pd-toast-sub {
  font-size: 12.5px;
  color: oklch(0.85 0.01 240);
  margin-top: 3px;
  line-height: 1.45;
}
.pd-toast-x {
  background: transparent;
  border: 0;
  color: oklch(0.75 0.01 240);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
  flex: 0 0 auto;
}
.pd-toast-x:hover {
  color: var(--paper-2);
}
.pd-toast-actions {
  display: flex;
  gap: 8px;
}
.pd-toast-actions button {
  flex: 1;
  padding: 11px 10px;
  border-radius: 8px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  border: 0;
}
.pd-toast-actions .pd-print {
  background: var(--paper-2);
  color: var(--ink);
}
.pd-toast-actions .pd-save {
  background: oklch(1 0 0 / 0.14);
  color: var(--paper-2);
}
.pd-toast-actions .pd-tip {
  background: transparent;
  color: var(--paper-2);
  border: 1px solid oklch(1 0 0 / 0.3);
}
.pd-toast-actions button:hover {
  filter: brightness(1.1);
}

/* ============ Sticky-sidebar workspace (desktop + tablet) ============
   Make the workspace fill the viewport and scroll each pane
   independently — only the center chat column scrolls the
   long candidate content. The rails + ballot stay put instead
   of the whole page scrolling (which left big empty gaps below
   the short rails). Scoped ≥768px; mobile keeps its overlay flow. */
@media (min-width: 768px) {
  .ws-shell {
    display: flex;
    flex-direction: column;
    height: 100vh;
    overflow: hidden;
  }
  .ws-shell .ws-wrap {
    flex: 1;
    min-height: 0;
    overflow: hidden;
  }
  .ws-shell .ws-rail {
    overflow-y: auto;
  }
  .ws-shell .ws-ballot {
    overflow-y: auto;
  }
  .ws-shell .ws-chat {
    overflow: hidden;
  }
  /* The chat body is the one scroll region for the candidate content. */
  .ws-shell .ws-chat .body {
    overflow-y: auto;
    min-height: 0;
  }
  /* Visually we want ONE scrollbar (the center). The side rails stay
     scroll-functional (wheel/trackpad/keyboard) but hide their bars
     so the layout doesn't show three tracks. */
  .ws-shell .ws-rail,
  .ws-shell .ws-ballot {
    scrollbar-width: none; /* Firefox */
    -ms-overflow-style: none; /* old Edge */
  }
  .ws-shell .ws-rail::-webkit-scrollbar,
  .ws-shell .ws-ballot::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none; /* WebKit */
  }
  /* Center scrollbar: slim + unobtrusive. */
  .ws-shell .ws-chat .body {
    scrollbar-width: thin;
    scrollbar-color: var(--rule) transparent;
  }
  .ws-shell .ws-chat .body::-webkit-scrollbar {
    width: 8px;
  }
  .ws-shell .ws-chat .body::-webkit-scrollbar-thumb {
    background: var(--rule);
    border-radius: 999px;
    border: 2px solid var(--paper);
  }
  .ws-shell .ws-chat .body::-webkit-scrollbar-track {
    background: transparent;
  }
  /* Poll bar stays a fixed-height row at the top of the shell. */
  .ws-shell .poll-bar {
    position: static;
    flex: 0 0 auto;
  }
  /* Slim footer pinned at the bottom of the shell — full .hp-foot styles apply,
     these overrides reduce height so the three panels keep most of the viewport. */
  .ws-shell .hp-foot-slim {
    flex: 0 0 auto;
    padding: 7px 18px;
    font-size: 12px;
    border-top: 1px solid var(--rule);
  }
}

/* ============ FundingMixBars (shared component) ============
   One stacked bar + legend used in BOTH the candidate-card Money
   trail and the Compare modal so they never drift. */
.fmix {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.fmix-bar {
  display: flex;
  height: 30px;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--rule);
  background: var(--paper-2);
}
.fmix-bar .seg {
  display: grid;
  place-items: center;
  min-width: 0;
  font-family: var(--serif);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: -0.01em;
}
.fmix-bar .seg.small {
  background: var(--civic);
  color: var(--paper-2);
}
.fmix-bar .seg.large {
  background: var(--gold);
  color: var(--ink);
}
.fmix-bar .seg.pac {
  background: var(--vote-red);
  color: var(--paper-2);
}
.fmix-legend {
  display: grid;
  grid-template-columns: repeat(3, auto);
  gap: 6px 18px;
  justify-content: start;
  font-size: 13px;
  color: var(--ink-3);
}
.fmix-legend > div {
  display: flex;
  align-items: center;
  gap: 7px;
  line-height: 1.3;
}
.fmix-legend b {
  color: var(--ink);
  font-weight: 600;
}
.fmix-legend small {
  color: var(--ink-3);
  font-size: inherit;
}
.fmix-legend .sw {
  width: 11px;
  height: 11px;
  border-radius: 3px;
  flex: 0 0 11px;
}
.fmix-legend .sw.small {
  background: var(--civic);
}
.fmix-legend .sw.large {
  background: var(--gold);
}
.fmix-legend .sw.pac {
  background: var(--vote-red);
}
@media (max-width: 600px) {
  .fmix-legend {
    grid-template-columns: 1fr;
    gap: 7px;
  }
}

/* ============ Compare-foot: stop the <b> from splitting columns ===
   .cmp-foot is display:flex; the bold <Reveal> + surrounding text
   nodes were each becoming separate flex items → 3 columns on
   mobile. Wrap the text in one span so it flows inline. */
.cmp-foot .cmp-foot-text {
  flex: 1;
  min-width: 0;
}

/* ============ SHOW DETAILS — obvious pill on every viewport ===
   Was a bare mono-caps text link on desktop (easy to miss) and a
   pill on mobile. Make it a clear bordered civic pill everywhere
   so the Money trail disclosure reads as tappable. */
.cv2-disclose-chev {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--civic);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 9px 15px;
  border: 1px solid var(--civic-soft);
  border-radius: 999px;
  background: var(--paper);
  flex: 0 0 auto;
}
.cv2-disclose-toggle:hover .cv2-disclose-chev {
  background: var(--civic);
  color: var(--paper-2);
  border-color: var(--civic);
}
/* Mobile: full-width filled pill — placed AFTER the base rule so it
   wins on ≤640 (equal specificity → source order decides). */
@media (max-width: 640px) {
  .cv2-disclose-toggle {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
  .cv2-disclose-chev {
    align-self: stretch;
    justify-content: center;
    background: var(--civic-soft);
    color: var(--civic);
    min-height: 44px;
    padding: 11px 14px;
  }
}

/* ============ Issue ranking — tablet range (641–1023) ============
   The cold-open issue list used the dense 4-column desktop grid in
   the 641–1023 band, which squeezed the quotes into a narrow column.
   Apply the same clean stacked layout we use on phones: drag handle
   left, full-width body (title + quotes), REMOVE chip below. */
@media (min-width: 641px) and (max-width: 1023px) {
  .theme-row {
    grid-template-columns: 44px 1fr;
    column-gap: 14px;
    row-gap: 8px;
    align-items: start;
    padding: 16px 0;
  }
  .theme-row .ord {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    width: 44px;
    margin: 0;
    grid-column: 1;
    grid-row: 1;
  }
  .theme-row .ord .drag-handle {
    width: 44px;
    height: 52px;
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 6px;
  }
  .theme-row .ord .ord-arrows {
    display: none;
  }
  .theme-row .rank {
    display: none;
  }
  .theme-row .body {
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
    width: 100%;
  }
  .theme-row .quotes {
    width: 100%;
  }
  .theme-row .quote {
    width: 100%;
  }
  .theme-row .acts {
    grid-column: 2;
    grid-row: 2;
    flex-direction: row;
    justify-content: flex-start;
    gap: 14px;
    padding-top: 8px;
    border-top: 1px dashed var(--rule-2);
  }
  .theme-row .acts button.danger {
    font-size: 12.5px;
    padding: 10px 14px;
    min-height: 40px;
    border: 1px solid oklch(0.88 0.05 28);
    border-radius: 999px;
    color: var(--vote-red);
    background: transparent;
  }
}

/* ============ Ballot-pane edit-issues entry (mobile/tablet) ============
   Surfaces "Your issues · Edit ranking" inside the ballot pane when
   the desktop left rail (which normally holds it) is hidden ≤1023px.
   Hidden on desktop to avoid duplicating the rail's control. */
.b-issues-edit {
  display: none;
}
@media (max-width: 1023px) {
  .b-issues-edit {
    display: block;
    padding: 14px 20px 16px;
    border-bottom: 1px solid var(--rule);
    background: var(--paper-2);
  }
  .b-issues-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
  }
  .b-issues-lab {
    font-family: var(--mono);
    font-size: 10.5px;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--ink-3);
  }
  .b-issues-btn {
    background: var(--paper);
    border: 1px solid var(--civic-soft);
    color: var(--civic);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    padding: 9px 15px;
    border-radius: 999px;
    min-height: 40px;
    white-space: nowrap;
  }
  .b-issues-btn:hover {
    background: var(--civic);
    color: var(--paper-2);
    border-color: var(--civic);
  }
  .b-issues-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .b-issues-list li {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: 14px;
    color: var(--ink);
    line-height: 1.35;
  }
  .b-issues-list li .n {
    font-family: var(--mono);
    font-size: 11px;
    color: var(--civic);
    font-weight: 600;
    flex: 0 0 auto;
  }
}

@media print {
  .app-nav,
  .skip-link,
  .nav-cog,
  .tweaks,
  .sx-overlay,
  .be-modal-overlay {
    display: none !important;
  }
  body {
    background: white;
  }
  .print-wrap {
    padding: 0;
  }
  .print-sheet {
    margin: 0;
    box-shadow: none;
    border: 0;
    page-break-inside: avoid;
    max-width: 100%;
    font-family: Georgia, "Times New Roman", serif;
  }
  .ballot-group {
    page-break-inside: avoid;
    break-inside: avoid;
  }
  .br {
    page-break-inside: avoid;
    break-inside: avoid;
  }
  .ph-head,
  .voter-meta {
    border-color: black;
  }
  /* Force exact color so the ballot checkmark prints */
  * {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }
  .print-actions,
  .print-banner {
    display: none !important;
  }
  @page {
    margin: 0.5in;
    size: letter;
  }
}
