/* Inter Tight (variable, 400–800), self-hosted. SIL Open Font License: fonts/OFL.txt */
/* latin-ext */
@font-face {
  font-family: 'Inter Tight';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url(../fonts/inter-tight-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* latin */
@font-face {
  font-family: 'Inter Tight';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url(../fonts/inter-tight-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Registered so the easter-egg colour cycle animates as a typed colour */
@property --tint {
  syntax: '<color>';
  inherits: true;
  initial-value: transparent;
}

:root {
  color-scheme: dark;
  --bg: #0B0B0C;
  --ink: #F4F4F2;
  --body: #D6D6D2;
  --muted: #B5B5B0;
  --line: #3A3A3E;
  --accent: #00B5E2;
  --ease: cubic-bezier(.2, .7, .2, 1);

  /* Easter-egg palette: Konami burst, colour cycle and confetti */
  --c1: var(--accent);
  --c2: #3D7BFF;
  --c3: #A78BFA;
  --c4: #FF5FA2;
  --c5: #FF4D3D;
  --c6: #FF8A1F;
  --c7: #B8F02E;
  --c8: #2EE6A6;
}

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

html { background: var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Inter Tight', system-ui, -apple-system, 'Segoe UI', sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  color: var(--ink);
  text-decoration: none;

  &:hover, &:focus-visible { color: var(--accent); }
  &:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 2px; }
}

.sprite { display: none; }

/* Screen-reader-only live region: always in the accessibility tree so announcements are reliable */
.sr-only {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.page {
  position: relative;
  overflow: clip;
  min-block-size: 100svh;
  padding-block: 40px 48px;
  padding-inline: clamp(16px, 5vw, 64px);

  @media (max-width: 640px) {
    padding-block: 20px 28px;
    padding-inline: 16px;
  }
}

/* Big AQ: outer layer follows the cursor (eased), inner layer follows scroll (immediate).
   All motion is opt-in via prefers-reduced-motion: no-preference. */
.mark {
  position: absolute;
  inset-block-start: 150px;
  inset-inline-end: -3%;
  inline-size: min(1000px, 92vw);
  pointer-events: none;

  & .layers { position: relative; }

  & svg {
    display: block;
    inline-size: 100%;
    block-size: auto;
    aspect-ratio: 664 / 394;
  }

  & .main {
    position: relative;
    --tint: var(--ink);
    fill: var(--tint);
  }

  /* Konami echoes: coloured copies of the mark, hidden until .burst is on .page */
  & .echo {
    position: absolute;
    inset: 0;
    opacity: 0;
    fill: var(--c);
  }

  @media (prefers-reduced-motion: no-preference) {
    transform: translate3d(var(--mx, 0px), var(--my, 0px), 0);
    transition: transform 1.1s var(--ease);
    will-change: transform;

    & .layers {
      transform: translate3d(0, var(--sy, 0px), 0);
      will-change: transform;
    }

    .burst & {
      & .echo {
        animation: echo 2.2s var(--ease) both;
        animation-delay: calc(var(--i) * 45ms);
      }
      & .main { animation: tint 2.2s steps(1) both; }
    }
  }

  @media (max-width: 640px) {
    inset-block-start: 76px;
    inset-inline-end: -6%;
    inline-size: 66vw;
  }
}

@keyframes echo {
  0% { opacity: 0; translate: 0 0; }
  35%, 70% { opacity: 1; translate: calc(var(--i) * -18px) calc(var(--i) * 12px); }
  100% { opacity: 0; translate: 0 0; }
}

/* Steps through the palette, then settles back on the element's own --tint (implicit 100%) */
@keyframes tint {
  0% { --tint: var(--c1); }
  12.5% { --tint: var(--c2); }
  25% { --tint: var(--c3); }
  37.5% { --tint: var(--c4); }
  50% { --tint: var(--c5); }
  62.5% { --tint: var(--c6); }
  75% { --tint: var(--c7); }
  87.5% { --tint: var(--c8); }
}

/* Pills pinned to the bottom centre of the viewport: Konami toast and GOTV prompt */
.pill {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 24px;
  inline-size: fit-content;
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--bg);
  font-size: .875rem;
  font-weight: 500;
  letter-spacing: .06em;
  white-space: nowrap;

  & strong { font-weight: 800; letter-spacing: 0; }
}

/* Toast never blocks clicks */
.toast {
  z-index: 10;
  padding: 10px 16px;
  opacity: 0;
  pointer-events: none;

  &:empty { display: none; }
  .burst & { animation: toast 2.8s var(--ease) both; }
}

@keyframes toast {
  0%, 10% { opacity: 0; translate: 0 16px; }
  22%, 80% { opacity: 1; translate: 0 0; }
  100% { opacity: 0; translate: 0 8px; }
}

/* GOTV easter egg: the word "GOTV" in the bio opens a "Have you voted?" pill */
.gotv {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--ink) 35%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  cursor: pointer;
  transition: color .2s, text-decoration-color .2s;

  &:hover, &:focus-visible { color: var(--accent); text-decoration-color: var(--accent); }
  &:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
}

.vote {
  z-index: 11;
  padding-block: 6px;
  padding-inline: 16px 6px;
  box-shadow: 0 16px 40px rgb(0 0 0 / .5);

  &[hidden] { display: none; }
  &.out { opacity: 0; }

  & .msg { padding-block: 9px; padding-inline-end: 10px; }

  & button {
    min-block-size: 36px;
    padding-block: 0;
    padding-inline: 16px;
    border-radius: 999px;
    font: inherit;
    letter-spacing: .04em;
    cursor: pointer;
    transition: background .2s, color .2s, border-color .2s;

    &:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  }

  & .yes {
    border: 0;
    background: var(--bg);
    color: var(--ink);

    &:hover, &:focus-visible { background: var(--accent); color: var(--bg); }
  }

  & .no {
    border: 1px solid var(--bg);
    background: transparent;
    color: var(--bg);

    &:hover, &:focus-visible {
      border-color: var(--accent);
      color: color-mix(in srgb, var(--accent) 62%, black);
    }
  }

  @media (prefers-reduced-motion: no-preference) {
    &.in { animation: vote-in .6s var(--ease) both; }
    &.out { animation: vote-out .6s var(--ease) both; }
  }

  @media (max-width: 640px) {
    inline-size: auto;
    inset-inline: 16px;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    padding: 12px;
    border-radius: 20px;
    white-space: normal;
    text-align: center;

    & > span:first-child { flex-basis: 100%; }
    & .msg { padding: 8px 0; }
  }
}

@keyframes vote-in {
  from { opacity: 0; translate: 0 16px; }
}

@keyframes vote-out {
  from { opacity: 1; translate: 0 0; }
  to { opacity: 0; translate: 0 8px; }
}

.confetti {
  position: fixed;
  inset: 0;
  z-index: 10;
  overflow: clip;
  pointer-events: none;

  & span {
    position: absolute;
    inset-inline-start: 50%;
    inset-block-end: 46px;
    border-radius: 2px;
    animation: fly 2s both;
  }

  @media (prefers-reduced-motion: reduce) { display: none; }
}

@keyframes fly {
  0% {
    transform: translate(0, 0) rotate(0deg);
    opacity: 1;
    animation-timing-function: cubic-bezier(.15, .7, .3, 1);
  }
  40% {
    transform: translate(calc(var(--dx) * .75), var(--dy)) rotate(calc(var(--r) * .4));
    opacity: 1;
    animation-timing-function: cubic-bezier(.5, 0, .9, .6);
  }
  100% {
    transform: translate(var(--dx), calc(var(--dy) + 100vh)) rotate(var(--r));
    opacity: 0;
  }
}

.wrap {
  position: relative;
  max-inline-size: 1200px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: 56px;

  @media (max-width: 640px) { gap: 28px; }
}

header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px 24px;
  min-block-size: 32px;
  padding-block-start: 12px;
  border-block-start: 2px solid var(--ink);
  font-size: .875rem;
  font-weight: 500;
}

.home {
  display: inline-flex;
  align-items: center;
  min-block-size: 32px;
  color: var(--accent);
  transition: color .25s ease;

  &:hover, &:focus-visible { color: var(--ink); }

  & svg {
    display: block;
    block-size: 20px;
    inline-size: auto;
    fill: currentColor;
  }
}

.arrow { display: inline-block; }

.hello {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-block-size: 32px;
  padding-inline: 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  transition: color .2s, border-color .2s;

  &:hover, &:focus-visible { border-color: var(--accent); }

  @media (prefers-reduced-motion: no-preference) {
    & .arrow { transition: translate .25s ease; }
    &:hover .arrow, &:focus-visible .arrow { translate: 3px 0; }
  }
}

/* Phone: mark tucks up under a semi-transparent panel; small headshot beside the role */
main {
  max-inline-size: 700px;
  display: flex;
  flex-direction: column;
  gap: 28px;
  padding-block: 8px 16px;
  padding-inline: 0 24px;
  background: color-mix(in srgb, var(--bg) 90%, transparent);

  @media (max-width: 640px) {
    display: grid;
    grid-template-columns: 1fr 56px;
    align-items: center;
    gap: 16px;
    margin-block-start: calc(16vw - 28px);
    padding-block: 10px 4px;
    padding-inline: 0;
    background: color-mix(in srgb, var(--bg) 72%, transparent);

    & h1, & .lead, & .bio { grid-column: 1 / -1; }
    & h1 { grid-row: 1; }
    & .role { grid-column: 1; grid-row: 2; }
    & .about { display: contents; }
    & .photo { grid-column: 2; grid-row: 2; }
    & .lead { grid-row: 3; }
    & .bio { grid-row: 4; }
  }
}

h1 {
  margin: 0;
  font-size: clamp(4rem, 10.5vw, 8.75rem);
  font-weight: 800;
  line-height: .86;
  letter-spacing: -.05em;

  & .accent {
    --tint: var(--accent);
    color: var(--tint);

    @media (prefers-reduced-motion: no-preference) {
      .burst & { animation: tint 2.2s steps(1) both; }
    }
  }
}

.role {
  --tint: var(--accent);
  margin: 0;
  padding-block-start: 14px;
  border-block-start: 1px solid var(--line);
  color: var(--tint);
  font-size: .9375rem;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;

  & span { white-space: nowrap; }

  @media (prefers-reduced-motion: no-preference) {
    .burst & { animation: tint 2.2s steps(1) both; }
  }

  @media (max-width: 640px) {
    font-size: clamp(.6875rem, 3.08vw, .75rem);
    letter-spacing: .04em;
  }
}

.lead {
  margin: 0;
  max-inline-size: 26ch;
  font-size: clamp(1.375rem, 2.3vw, 1.875rem);
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -.015em;
  text-wrap: balance;
}

.about {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 24px;
}

.photo {
  flex: none;
  inline-size: 120px;

  & img {
    display: block;
    inline-size: 120px;
    block-size: 120px;
    border-radius: 50%;
    object-fit: cover;
  }

  @media (max-width: 640px) {
    inline-size: 56px;

    & img { inline-size: 56px; block-size: 56px; }
  }
}

.bio {
  flex: 1 1 300px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  color: var(--body);
  font-size: 1.0625rem;
  line-height: 1.6;

  & p { margin: 0; max-inline-size: 64ch; text-wrap: pretty; }

  @media (max-width: 640px) {
    gap: 14px;
    font-size: 1rem;
    line-height: 1.55;
  }
}

footer {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 8px 24px;
  padding-block-start: 12px;
  border-block-start: 2px solid var(--ink);
  background: var(--bg);
  font-size: 1rem;
  font-weight: 500;

  & > div {
    min-block-size: 44px;
    display: flex;
    align-items: center;
  }
}

.link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: color .2s;

  /* Arrow slides in on hover; with reduced motion it simply stays visible */
  @media (prefers-reduced-motion: no-preference) {
    & .arrow {
      opacity: 0;
      translate: -6px 0;
      transition: opacity .25s ease, translate .3s var(--ease);
    }
    &:hover .arrow, &:focus-visible .arrow { opacity: 1; translate: 0 0; }
  }
}

/* 404: "Candidate withdrawn" ballot. No script — :has() shows the cast link for the marked choice. */
main.lost {
  max-inline-size: none;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 48px 64px;
  padding-inline: 0;
  background: none;

  @media (max-width: 640px) {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 32px;
    margin-block-start: 0;
    padding-block: 8px;
  }
}

.lost-text {
  flex: 1 1 420px;
  display: flex;
  flex-direction: column;
  gap: 28px;

  @media (max-width: 640px) { flex: none; gap: 20px; }

  & .lead { max-inline-size: 24ch; }
}

.ballot {
  --paper: var(--ink);
  --paper-ink: var(--bg);
  --paper-muted: #55554F;
  --paper-rule: #C9C9C4;

  flex: 0 1 360px;
  min-inline-size: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 24px 24px 20px;
  border-radius: 4px;
  background: var(--paper);
  color: var(--paper-ink);
  box-shadow: 0 24px 60px rgb(0 0 0 / .5);
  rotate: -1.5deg;

  @media (max-width: 640px) {
    flex: none;
    inline-size: 100%;
    max-inline-size: 420px;
    align-self: center;
    padding: 20px 18px 18px;
    rotate: -1deg;
  }

  & fieldset {
    margin: 0;
    padding: 0;
    border: 0;
    min-inline-size: 0;
  }

  & legend {
    padding: 0 0 10px;
    color: var(--paper-muted);
    font-size: .6875rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
  }
}

.choice {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
  min-block-size: 56px;
  padding-inline: 8px;
  border-block-start: 1px solid var(--paper-rule);
  cursor: pointer;
  transition: background .2s;

  &:hover { background: #E6E6E2; }

  /* Visually hidden but focusable: the drawn box shows its state */
  & input {
    position: absolute;
    opacity: 0;
    inline-size: 1px;
    block-size: 1px;
    margin: 0;
  }

  & .box {
    flex: none;
    display: grid;
    place-items: center;
    inline-size: 28px;
    block-size: 28px;
    border: 2px solid var(--paper-ink);
    border-radius: 50%;

    /* The voter's mark */
    &::after {
      content: '×';
      font-size: 30px;
      font-weight: 800;
      line-height: 1;
      translate: 0 -1px;
      opacity: 0;
    }
  }

  & input:checked + .box::after { opacity: 1; }
  & input:focus-visible + .box { outline: 2px solid var(--accent); outline-offset: 3px; }

  @media (prefers-reduced-motion: no-preference) {
    & input:checked + .box::after { animation: mark .25s var(--ease); }
  }

  & .who {
    display: flex;
    flex-direction: column;
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.3;
  }

  & small {
    color: var(--paper-muted);
    font-size: .8125rem;
    font-weight: 400;
  }

  &.withdrawn {
    cursor: default;
    color: #6B6B66;

    &:hover { background: none; }
    & .box { border-color: #B5B5B0; }
    & small { color: #6B6B66; }
  }
}

@keyframes mark {
  from { opacity: 0; scale: 1.8; }
}

.cast {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  min-block-size: 48px;
  border-radius: 999px;
  background: var(--paper-ink);
  color: var(--paper);
  font-weight: 600;
  transition: background .2s, color .2s;

  &:hover, &:focus-visible { background: var(--accent); color: var(--bg); }
  &:focus-visible { outline-color: var(--paper-ink); }

  &.idle {
    background: #DCDCD8;
    color: var(--paper-muted);
    font-weight: 500;
  }

  &[data-for] { display: none; }
}

.ballot:has(input:checked) .cast.idle { display: none; }
.ballot:has(#vote-home:checked) .cast[data-for="home"],
.ballot:has(#vote-mail:checked) .cast[data-for="mail"],
.ballot:has(#vote-in:checked) .cast[data-for="in"] { display: flex; }
