/* Wingmate waitlist page.
   Dark and soft: panels start black and fade into deep indigo, text is Figtree, white marks the
   one primary thing and everything secondary is translucent white. Soft glows, never shadows. */

:root {
  --bg: #040404;
  --ink: #ffffff;
  --ink-2: rgba(255, 255, 255, 0.62);
  --ink-3: rgba(255, 255, 255, 0.48);
  --ink-75: rgba(255, 255, 255, 0.75);
  --glass: rgba(255, 255, 255, 0.07);
  --line: rgba(255, 255, 255, 0.1);
  --button: #1c1c1c;
  --device: #0a0a0c;
  --green: #2fd27a;
  --yellow: #f2d06b;
  --captain: #ff5c8a;
  --nne: #b86cf0;
  --panel: linear-gradient(180deg, #000000 0%, #020106 46%, #0e0333 64%, #1d0868 78%, #3423b4 90%, #6a5ff0 100%);
  --gutter: clamp(16px, 4vw, 40px);

  /* Motion: arrivals settle on a long ease-out, bubbles and presses get a soft spring, and loops
     breathe on a sine. */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.3, 0.64, 1);
  --ease-press: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-sine: cubic-bezier(0.45, 0, 0.55, 1);
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
}

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: Figtree, system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
}

img,
svg {
  display: block;
}

a {
  color: var(--ink);
}

a:hover {
  color: #b9b2ff;
}

[hidden] {
  display: none !important;
}

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

.page {
  min-height: 100vh;
  padding: 12px; /* the hero and the closing panel sit this far in from every edge */
  overflow-x: clip; /* the soft glows may reach past the edges on narrow screens */
}

.container {
  max-width: 1120px;
  margin: 0 auto;
  padding-inline: var(--gutter);
}

/* ---- Type --------------------------------------------------------------------------------- */

.eyebrow {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
}

.eyebrow::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink);
}

.title {
  margin: 0;
  font-size: clamp(36px, 5vw, 52px);
  line-height: 1.04;
  font-weight: 600;
  letter-spacing: -0.035em;
}

.lead {
  margin: 0;
  font-size: 17px;
  line-height: 25px;
  color: var(--ink-2);
}

/* ---- Doodle avatars ----------------------------------------------------------------------- */

.pair {
  display: flex;
}

.avatar {
  --size: 34px;
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: #73293e;
}

.avatar img {
  width: 86%;
  height: 86%;
}

.avatar--nne {
  background: #53316c;
}

.pair .avatar + .avatar {
  margin-left: calc(var(--size) * -0.3);
  border: 2px solid #000000;
}

.flip {
  transform: scaleX(-1);
}

/* ---- Buttons and the waitlist form -------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: var(--ink);
  color: #000000;
  font: 600 15px Figtree, system-ui, sans-serif;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 0.45s var(--ease-press);
}

.btn:hover {
  color: #000000;
}

.btn:active {
  transform: scale(0.96);
}

/* Secondary: the nav button, so the form's white button is the one primary action. */
.btn--glass {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: var(--ink);
  transition:
    transform 0.45s var(--ease-press),
    background-color 0.3s var(--ease-sine);
}

.btn--glass:hover {
  background: rgba(255, 255, 255, 0.1);
  color: var(--ink);
}

.join {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  width: 100%;
  max-width: 460px;
  padding: 6px;
  border-radius: 999px;
  background: var(--glass);
  border: 1px solid rgba(255, 255, 255, 0.12);
}

.join input {
  flex: 1 1 180px;
  min-width: 0;
  height: 44px;
  padding: 0 16px;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--ink);
  font: 400 16px Figtree, system-ui, sans-serif;
}

.join input::placeholder {
  color: var(--ink-3);
}

.join:focus-within {
  border-color: rgba(255, 255, 255, 0.3);
}

.joined {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 20px;
  border-radius: 999px;
  background: rgba(47, 210, 122, 0.12);
  border: 1px solid rgba(47, 210, 122, 0.3);
  font-size: 15px;
  animation: rise 0.7s var(--ease-out) both;
}

/* ---- Hero --------------------------------------------------------------------------------- */

.hero {
  /* The panel reaches the bottom of the screen, leaving the same 12px there as at the sides and
     top. On a tall screen the copy sits in the middle of the space under the nav. */
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - 24px);
  min-height: calc(100svh - 24px);
  border-radius: 40px;
  overflow: hidden;
  background: var(--panel);
}

/* Full width inside the hero's column, up to the container's max width. */
.hero > .container {
  width: 100%;
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-block: 24px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.3px;
  text-decoration: none;
}

.nav .btn {
  font-size: 14px;
  padding: 0 18px;
}

.hero__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 44px;
  padding-top: 48px;
  padding-bottom: 104px;
  text-align: center;
}

.eyebrow--hero {
  font-size: 14px;
  color: var(--ink-75);
}

.eyebrow--hero::before {
  width: 8px;
  height: 8px;
  background: var(--captain);
}

.hero h1 {
  max-width: 960px;
  margin: 0;
  font-size: clamp(52px, 8vw, 112px);
  line-height: 0.98;
  font-weight: 500;
  letter-spacing: -0.05em;
  text-wrap: balance;
}

.hero__copy {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
  width: 100%;
}

.hero .lead {
  max-width: 560px;
  font-size: 18px;
  line-height: 27px;
}

.hero .join,
.hero .joined {
  margin-top: 6px;
}

.hero__note {
  margin: -8px 0 0;
  font-size: 13px;
  color: rgba(255, 255, 255, 0.72);
}

/* The waitlist forms, in the hero and the closing panel: the field and the button sit side by
   side as two separate pills. */
.join--split {
  gap: 8px;
  max-width: 480px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
}

.join--split input {
  height: 54px;
  padding: 0 20px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  transition: border-color 0.3s var(--ease-sine);
}

.join--split input:focus {
  border-color: rgba(255, 255, 255, 0.34);
}

.join--split .btn {
  height: 54px;
  padding: 0 24px;
  font-size: 16px;
}

.glow {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
}

/* ---- Hero cast ---------------------------------------------------------------------------- */

/* Each doodle's rank sets its size, how high it sits in the U and how faint it is: 1 is Captain
   and Nne in the middle, 6 the two at the ends. Outer ranks drop away as the screen narrows, so
   the row never wraps. */
.cast {
  position: relative;
  width: 100%;
}

.cast__glow {
  position: absolute;
  left: 50%;
  bottom: -170px;
  width: 460px;
  height: 460px;
  border-radius: 50%;
  pointer-events: none;
}

.cast__glow--captain {
  margin-left: -400px;
  background: radial-gradient(circle, rgba(255, 92, 138, 0.22) 0%, rgba(255, 92, 138, 0) 65%);
}

.cast__glow--nne {
  margin-left: -60px;
  background: radial-gradient(circle, rgba(184, 108, 240, 0.24) 0%, rgba(184, 108, 240, 0) 65%);
}

.cast__row {
  --pair: 112px;
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 22px;
}

/* Each doodle is a button: hover, focus or tap it and it says its line (see Doodle lines). */
.cast__doodle {
  --size: var(--pair);
  --lift: 0px;
  --fade: 1;
  --in: 0.15s;
  position: relative;
  flex: none;
  width: var(--size);
  height: var(--size);
  margin: 0 0 var(--lift);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.cast__doodle--2 { --size: 72px; --lift: 26px; --fade: 0.95; --in: 0.23s; }
.cast__doodle--3 { --size: 64px; --lift: 56px; --fade: 0.85; --in: 0.31s; }
.cast__doodle--4 { --size: 58px; --lift: 90px; --fade: 0.72; --in: 0.39s; }
.cast__doodle--5 { --size: 52px; --lift: 128px; --fade: 0.58; --in: 0.47s; }
.cast__doodle--6 { --size: 46px; --lift: 170px; --fade: 0.46; --in: 0.55s; }

/* Every doodle breathes on its own beat; the mirrored ones keep their flip while they do. */
.cast img {
  width: 100%;
  height: 100%;
  animation: bob 3.4s var(--ease-sine) var(--beat, 0s) infinite;
}

.cast img.flip {
  animation-name: bob-flip;
}

.cast__talk {
  display: block;
  width: 100%;
  height: 100%;
  opacity: var(--fade);
  transition:
    transform 0.6s var(--ease-spring),
    opacity 0.3s var(--ease-sine);
}

.is-talking > .cast__talk {
  transform: translateY(-6px) scale(1.05);
}

/* The one you point at comes forward: full strength, a little bigger, lifted. */
.cast__doodle:hover > .cast__talk,
.cast__doodle:focus-visible > .cast__talk,
.cast__doodle.is-saying > .cast__talk {
  opacity: 1;
  transform: translateY(-8px) scale(1.12);
}

/* While you are with one of them, Captain and Nne pause their chat. */
.cast:has(.cast__doodle:hover, .cast__doodle:focus-visible, .cast__doodle.is-saying) .cast__bubble {
  opacity: 0;
  transform: translateY(8px) scale(0.9);
}

/* Speech bubbles spring out of the corner nearest their wingmate. Captain's is white and
   anchored to his right edge; Nne's is glass and anchored to her left edge. */
.cast__bubble {
  position: absolute;
  left: 0;
  bottom: calc(100% + 14px);
  width: max-content;
  max-width: 280px;
  padding: 10px 14px;
  border-radius: 18px 18px 18px 6px;
  background: rgba(255, 255, 255, 0.12);
  -webkit-backdrop-filter: blur(20px) saturate(1.5);
  backdrop-filter: blur(20px) saturate(1.5);
  font-size: 14px;
  line-height: 19px;
  font-weight: 500;
  text-align: left;
  opacity: 0;
  transform: translateY(8px) scale(0.9);
  transform-origin: 0 100%;
  transition:
    opacity 0.4s var(--ease-out),
    transform 0.55s var(--ease-spring);
  pointer-events: none;
}

.cast__bubble--mine {
  left: auto;
  right: 0;
  border-radius: 18px 18px 6px 18px;
  background: var(--ink);
  color: #000000;
  transform-origin: 100% 100%;
}

.cast__bubble.is-on {
  opacity: 1;
  transform: none;
}

/* The spark sits level with the middle of the pair and swells when they agree. */
.cast__spark {
  flex: none;
  margin-bottom: calc(var(--pair) / 2 - 17px);
  transition: transform 0.7s var(--ease-press);
}

.cast__spark.is-bright {
  transform: scale(1.35);
}

.cast__spark svg {
  animation: twinkle 2.6s var(--ease-sine) infinite;
}

/* ---- Phone mockups ------------------------------------------------------------------------ */

.phone {
  --w: 300px;
  --h: 620px;
  --island-w: 88px;
  --island-h: 25px;
  position: relative;
  flex: none;
  width: var(--w);
  height: var(--h);
  padding: 10px;
  border-radius: 48px;
  background: var(--device);
  border: 1px solid rgba(255, 255, 255, 0.16);
  text-align: left;
}

.phone__screen {
  position: relative;
  height: 100%;
  border-radius: 38px;
  overflow: hidden;
  background: var(--panel);
}

.phone__content {
  display: flex;
  flex-direction: column;
  gap: 12px;
  height: 100%;
  padding: 50px 16px 16px;
}

.phone--score {
  --w: 310px;
  --h: 640px;
  --island-w: 92px;
  --island-h: 26px;
  border-radius: 50px;
}

.phone--score .phone__screen {
  border-radius: 40px;
}

.phone--score .status-bar {
  font-size: 12.5px;
}

/* iPhone status bar: the time in the left ear, signal, wifi and battery in the right, both on
   the Dynamic Island's centre line. Sizes are in em so the bar scales with the phone. */
.status-bar {
  position: absolute;
  top: 10px;
  left: 0;
  right: 0;
  z-index: 2;
  display: grid;
  grid-template-columns: 1fr var(--island-w) 1fr;
  align-items: center;
  height: var(--island-h);
  font-size: 12px;
  color: var(--ink);
}

.status-bar__time {
  justify-self: center;
  padding-right: 0.9em;
  position: relative;
  top: 0.08em;
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', Arial, sans-serif;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1;
}

.status-bar__island {
  position: relative;
  height: 100%;
  border-radius: 999px;
  background: #000000;
}

.status-bar__island::after {
  content: '';
  position: absolute;
  top: 50%;
  right: calc(var(--island-h) * 0.32);
  width: calc(var(--island-h) * 0.36);
  height: calc(var(--island-h) * 0.36);
  transform: translateY(-50%);
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #2a3150 0%, #10131f 55%, #050608 100%);
}

.status-bar__icons {
  justify-self: center;
  display: flex;
  align-items: center;
  gap: 0.3em;
}

/* ---- Score ring (results phone) ----------------------------------------------------------- */

.match-head {
  display: flex;
  align-items: center;
  gap: 10px;
}

.match-head__names {
  display: flex;
  flex-direction: column;
  font-size: 13px;
  font-weight: 500;
}

.match-head__names small {
  font-size: 11px;
  color: var(--ink-2);
}

.vibe {
  margin: 0;
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.4px;
}

.phone__content--score {
  gap: 14px;
  padding-inline: 18px;
}

.ring {
  position: relative;
  width: 240px;
  height: 240px;
  margin: 4px auto 0;
}

.ring > * {
  position: absolute;
  inset: 0;
}

.ring__glow {
  inset: auto;
  width: 150px;
  height: 150px;
}

.ring__glow--you {
  left: 34px;
  top: 46px;
  background: radial-gradient(circle, rgba(255, 92, 138, 0.34) 0%, rgba(255, 92, 138, 0) 70%);
}

.ring__glow--them {
  left: 92px;
  top: 52px;
  background: radial-gradient(circle, rgba(184, 108, 240, 0.36) 0%, rgba(184, 108, 240, 0) 70%);
}

/* The ring follows the scroll: main.js sets --score for the number, each lit dot's opacity and
   scale, and the walkers' turn. Without the script it shows 78. Each dot sits on its own spoke
   from the centre; once the ring rests on 78, --amp eases up to 1 and a slow breath travels round
   the ring as a wave while the whole ring sways. */
.ring__dots {
  animation: sway 16s var(--ease-sine) infinite;
}

.spoke {
  position: absolute;
  left: 120px;
  top: 120px;
  width: 0;
  height: 0;
}

.dot {
  position: absolute;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.13);
  animation: breathe 6s var(--ease-sine) infinite;
}

.dot__lit {
  position: absolute;
  inset: 0;
  border-radius: 50%;
}

.ring__score {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding-bottom: 4px;
}

.ring__num {
  --score: 78;
  font-size: 78px;
  line-height: 80px;
  font-weight: 500;
  letter-spacing: -3px;
  font-variant-numeric: tabular-nums;
  counter-reset: score var(--score);
}

.ring__num::after {
  content: counter(score);
}

.ring__of {
  font-size: 13px;
  font-weight: 600;
}

/* Both wingmates walk from the top, half the score each: 78 is 140.4 degrees round each side.
   The inner span turns back so the doodle stays upright. */
.walk--them,
.walk--you span {
  transform: rotate(140.4deg);
}

.walk--you,
.walk--them span {
  transform: rotate(-140.4deg);
}

.walk span {
  position: absolute;
  left: 103px;
  top: -2.6px;
  width: 34px;
  height: 34px;
}

.walk img {
  width: 34px;
  height: 34px;
}

.ring-facts {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin: 0;
  font-size: 12px;
  color: var(--ink-2);
}

/* The counts are the same size as their labels, just brighter. */
.ring-facts strong {
  font-weight: 500;
  color: var(--ink);
}

.score-summary {
  margin: 2px 0 0;
  padding: 12px 14px;
  border-radius: 18px;
  background: var(--glass);
  border: 1px solid var(--line);
  font-size: 12.5px;
  line-height: 18px;
}

/* The results screen carries on below the fold, so this card is cut off by the screen's edge. */
.result-card--peek {
  flex: none;
  animation: none;
}

/* ---- Wingmate date (chat phone) ----------------------------------------------------------- */

.chat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.chat-head h3 {
  margin: 0;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.3px;
}

.chat-head p {
  margin: 2px 0 0;
  font-size: 11px;
  color: var(--ink-2);
}

.live {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
}

.live::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--green);
  animation: breathe-dot 2s var(--ease-sine) infinite;
}

.chat {
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: opacity 0.6s var(--ease-sine);
}

.chat.is-resting,
.results.is-resting {
  opacity: 0;
}

.scene {
  display: flex;
  justify-content: center;
  animation: rise 0.7s var(--ease-out) both;
}

.scene span {
  padding: 4px 11px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-75);
}

/* Bubbles spring out from their own corner, like iMessage. */
.msg {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  padding-right: 30px;
  transform-origin: 0 100%;
  animation: pop 0.6s var(--ease-spring) both;
}

.msg--you {
  justify-content: flex-end;
  padding-right: 0;
  padding-left: 30px;
  transform-origin: 100% 100%;
}

.msg img {
  flex: none;
  width: 26px;
  height: 26px;
}

.msg p {
  margin: 0;
  padding: 9px 12px;
  border-radius: 18px 18px 18px 5px;
  background: rgba(255, 255, 255, 0.09);
  font-size: 13px;
  line-height: 18px;
}

.msg--you p {
  border-radius: 18px 18px 5px 18px;
  background: var(--ink);
  color: #000000;
}

.typing {
  padding: 0;
}

.typing img {
  animation: bob-small 1.6s var(--ease-sine) infinite;
}

.typing__dots {
  display: flex;
  gap: 4px;
  padding: 12px 13px;
  border-radius: 18px 18px 18px 5px;
  background: rgba(255, 255, 255, 0.09);
}

.msg--you .typing__dots {
  border-radius: 18px 18px 5px 18px;
  background: rgba(255, 255, 255, 0.16);
}

.typing__dots span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.8);
  animation: typing 1.4s var(--ease-sine) infinite;
}

.typing__dots span:nth-child(2) {
  animation-delay: 0.2s;
}

.typing__dots span:nth-child(3) {
  animation-delay: 0.4s;
}

/* ---- Friday highlights (results phone) ---------------------------------------------------- */

.results {
  gap: 10px;
  padding: 50px 14px 14px;
  transition: opacity 0.6s var(--ease-sine);
}

.result-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px;
  border-radius: 18px;
  background: var(--glass);
  border: 1px solid var(--line);
  animation: rise 0.7s var(--ease-out) both;
}

.result-card h4 {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 0;
  font-size: 14px;
  font-weight: 600;
}

.result-card ul {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 12px;
  line-height: 17px;
}

.result-card li::before {
  content: '· ';
}

.opener {
  background: var(--ink);
  border: 0;
  color: #000000;
}

.opener q {
  font-size: 15px;
  line-height: 20px;
  quotes: '\201C' '\201D';
}

.chip-dark {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 30px;
  padding: 0 12px;
  border-radius: 999px;
  background: #000000;
  color: var(--ink);
  font-size: 11px;
  font-weight: 600;
}

.results__spacer {
  flex: 1;
}

/* One slot at the bottom: the two buttons, then the match card cross-fades in over them. */
.results__end {
  display: grid;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}

.results__end.is-shown {
  opacity: 1;
  transform: none;
}

.results__end > * {
  grid-area: 1 / 1;
  align-self: end;
}

.actions {
  display: flex;
  gap: 8px;
  transition: opacity 0.35s var(--ease-sine), transform 0.5s var(--ease-out);
}

.is-matched .actions {
  opacity: 0;
  transform: translateY(6px) scale(0.97);
}

.pill {
  position: relative;
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  border-radius: 999px;
  background: var(--button);
  font-size: 12px;
  font-weight: 600;
  transition: transform 0.45s var(--ease-press);
}

.pill--primary {
  background: var(--ink);
  color: #000000;
}

.pill.is-pressed {
  transform: scale(0.95);
}

/* Where a finger lands. */
.tap {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 36px;
  height: 36px;
  margin: -18px 0 0 -18px;
  border-radius: 50%;
  background: rgba(20, 20, 30, 0.28);
  pointer-events: none;
  animation: tap 0.9s var(--ease-out) both;
}

.match-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 14px;
  border-radius: 18px;
  background: rgba(47, 210, 122, 0.12);
  border: 1px solid rgba(47, 210, 122, 0.3);
  text-align: center;
  transform-origin: 50% 100%;
  opacity: 0;
  transform: translateY(10px) scale(0.94);
  transition: opacity 0.6s var(--ease-out), transform 0.7s var(--ease-spring);
}

.is-matched .match-card {
  opacity: 1;
  transform: none;
}

.match-card .avatar {
  --size: 28px;
}

.match-card .avatar + .avatar {
  border-color: var(--device);
}

.match-card strong {
  font-size: 14px;
}

.match-card p {
  margin: 0;
  font-size: 11px;
  line-height: 15px;
  color: var(--ink-2);
}

.match-card .pill {
  align-self: stretch;
  flex: none;
  gap: 6px;
  height: 34px;
  margin-top: 2px;
}

/* ---- Side-by-side sections ---------------------------------------------------------------- */

/* Alignment rule: every heading block is centred, except the two side-by-side sections on wide
   screens, where the text sits left beside its phone. When those stack, they centre too. */
.split {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 64px;
  padding-top: 128px;
}

.split__text {
  flex: 1 1 0;
  min-width: 0;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.split__phone {
  position: relative;
  flex: 0 0 380px;
  min-width: 0;
  display: flex;
  justify-content: center;
}

.split__phone > .glow {
  top: 40px;
  left: 50%;
  width: 560px;
  height: 560px;
  margin-left: -280px;
}

.glow--nne {
  background: radial-gradient(circle, rgba(184, 108, 240, 0.32) 0%, rgba(184, 108, 240, 0) 65%);
}

.glow--captain {
  background: radial-gradient(circle, rgba(255, 92, 138, 0.28) 0%, rgba(255, 92, 138, 0) 65%);
}

.features {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}

.feature {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border-radius: 20px;
  background: var(--glass);
  border: 1px solid var(--line);
  text-align: left;
}

.feature__icon {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--button);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.feature__text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 14px;
  line-height: 19px;
  color: var(--ink-2);
}

.feature__text strong {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
}

/* ---- Centred sections --------------------------------------------------------------------- */

.centred {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  padding-top: 144px;
  text-align: center;
}

.centred .title {
  max-width: 760px;
}

.centred .lead {
  max-width: 600px;
}

.privacy-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  gap: 20px;
  width: 100%;
  margin-top: 36px;
  text-align: left;
}

.privacy-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.privacy-card h3 {
  margin: 8px 0 0;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.2px;
}

.privacy-card > p {
  margin: 0;
  font-size: 15px;
  line-height: 22px;
  color: var(--ink-2);
}

.stage {
  position: relative;
  height: 340px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  border-radius: 28px;
  overflow: hidden;
  background: #0d0b12;
  border: 1px solid var(--line);
}

.stage .glow {
  width: 420px;
  height: 420px;
}

.glow--pink-top {
  left: -80px;
  top: -60px;
  background: radial-gradient(circle, rgba(255, 92, 138, 0.32) 0%, rgba(255, 92, 138, 0) 68%);
}

.glow--violet-bottom {
  right: -120px;
  bottom: -140px;
  background: radial-gradient(circle, rgba(110, 91, 255, 0.35) 0%, rgba(110, 91, 255, 0) 68%);
}

.glow--lavender-top {
  right: -80px;
  top: -80px;
  background: radial-gradient(circle, rgba(185, 178, 255, 0.3) 0%, rgba(185, 178, 255, 0) 68%);
}

.glow--teal-bottom {
  left: -120px;
  bottom: -150px;
  background: radial-gradient(circle, rgba(46, 196, 182, 0.22) 0%, rgba(46, 196, 182, 0) 68%);
}

.stage__panel {
  position: relative;
  width: 100%;
  max-width: 380px;
  display: flex;
  flex-direction: column;
  padding: 18px;
  border-radius: 22px;
  font-size: 14px;
  line-height: 19px;
}

.mentions {
  gap: 4px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.12);
}

.panel-title {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0 0 6px;
}

.panel-title strong {
  font-size: 16px;
}

.panel-title small {
  font-size: 12px;
  color: var(--ink-2);
}

.mention {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
}

/* Each line stays on one line, like the rules card beside it. */
.mention span {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mention--off {
  color: var(--ink-3);
}

.mention--off span {
  text-decoration: line-through;
}

.mention .check {
  flex: none;
}

.check {
  width: 22px;
  height: 22px;
  border-radius: 7px;
  border: 1.5px solid rgba(255, 255, 255, 0.7);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.mention--off .check {
  border-color: rgba(255, 255, 255, 0.35);
}

/* Spaced so the card is the same height as "What I'll mention" beside it (210px on wide screens). */
.rules {
  gap: 4px;
  background: rgba(148, 140, 244, 0.16);
  border: 1px solid rgba(185, 178, 255, 0.22);
}

.rules__title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 0 0 6px;
  font-size: 16px;
  font-weight: 600;
}

.rule {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin: 0;
  padding: 6.5px 0;
}

.rule svg {
  flex: none;
}

.note {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 4px 0 0;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.35);
  font-size: 12px;
  color: var(--ink-75);
}

/* ---- Spark score -------------------------------------------------------------------------- */

/* Friday's results screen on a stage of its own, two notes on each side of it. On tablets the
   notes move under the phone in two columns; on phones they stack. */
.score {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 56px;
  width: 100%;
  margin-top: 44px;
}

.score__phone {
  position: relative;
  display: flex;
  justify-content: center;
}

.score__phone > .glow {
  top: 50%;
  left: 50%;
  width: 620px;
  height: 620px;
  margin: -310px 0 0 -310px;
  background: radial-gradient(circle, rgba(148, 140, 244, 0.4) 0%, rgba(148, 140, 244, 0.1) 45%, rgba(148, 140, 244, 0) 70%);
}

.score__notes {
  display: flex;
  flex-direction: column;
  gap: 48px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.score__notes:first-child {
  align-items: flex-end;
  text-align: right;
}

.score__notes:last-child {
  align-items: flex-start;
  text-align: left;
}

.score__note {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-width: 260px;
  font-size: 15px;
  line-height: 22px;
  color: var(--ink-2);
}

/* Each note's dot sits on the side nearest the phone. */
.score__note strong {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
}

.score__notes:first-child strong {
  flex-direction: row-reverse;
}

.score__note strong::before {
  content: '';
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--dot, var(--ink));
}

/* ---- The doodles -------------------------------------------------------------------------- */

/* Rows are centred, so a short last row sits in the middle. Each doodle breathes on its own beat
   and lifts a little on hover. */
.looks {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  width: 100%;
  margin: 28px 0 0;
  padding: 0;
  list-style: none;
}

.looks > li {
  flex: none;
  width: 156px;
}

.look {
  position: relative;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 20px 8px 16px;
  border-radius: 24px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: var(--ink);
  font: 600 15px Figtree, system-ui, sans-serif;
  cursor: pointer;
  transition: transform 0.5s var(--ease-spring), background-color 0.3s var(--ease-sine);
}

.look:hover {
  transform: translateY(-4px);
  background-color: rgba(255, 255, 255, 0.08);
}

.look__bubble {
  width: 84px;
  height: 84px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--bubble);
  transition: transform 0.5s var(--ease-spring);
}

.look:hover .look__bubble {
  transform: scale(1.06);
}

.look__bubble img {
  width: 72px;
  height: 72px;
  animation: bob 3.2s var(--ease-sine) var(--beat, 0s) infinite;
}

/* ---- Doodle lines ------------------------------------------------------------------------- */

/* Every doodle has a line (main.js adds them). Hover, focus or tap one and its line springs out
   of the corner nearest it, the name in its own colour, on frosted glass that blurs whatever is
   behind it so the words stay readable. In the hero, doodles left of the spark
   speak to the right and those after it speak to the left, so lines never run off the panel. In
   Pick a look, the line sits centred over the card. */
.say {
  position: absolute;
  left: -8px;
  bottom: calc(100% + 12px);
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: max-content;
  max-width: 230px;
  padding: 10px 14px 11px;
  border-radius: 18px 18px 18px 6px;
  background: rgba(20, 20, 28, 0.62);
  -webkit-backdrop-filter: blur(24px) saturate(1.6);
  backdrop-filter: blur(24px) saturate(1.6);
  color: var(--ink);
  font-size: 14px;
  line-height: 19px;
  font-weight: 500;
  text-align: left;
  opacity: 0;
  transform: translateY(8px) scale(0.9);
  transform-origin: 0 100%;
  transition:
    opacity 0.3s var(--ease-out),
    transform 0.5s var(--ease-spring);
  pointer-events: none;
}

.say strong {
  font-size: 12px;
  line-height: 16px;
  font-weight: 600;
  color: var(--c);
}

.cast__spark ~ .cast__doodle .say {
  left: auto;
  right: -8px;
  border-radius: 18px 18px 6px 18px;
  transform-origin: 100% 100%;
}

/* The outer doodles sit high in the U, close to the nav, so their lines hang below them. */
.cast__doodle--4 .say,
.cast__doodle--5 .say,
.cast__doodle--6 .say {
  top: calc(100% + 12px);
  bottom: auto;
  border-radius: 6px 18px 18px 18px;
  transform: translateY(-8px) scale(0.9);
  transform-origin: 0 0;
}

.cast__spark ~ .cast__doodle--4 .say,
.cast__spark ~ .cast__doodle--5 .say,
.cast__spark ~ .cast__doodle--6 .say {
  border-radius: 18px 6px 18px 18px;
  transform-origin: 100% 0;
}

[data-doodle]:hover,
[data-doodle]:focus-visible,
[data-doodle].is-saying {
  z-index: 2;
}

[data-doodle]:hover .say,
[data-doodle]:focus-visible .say,
[data-doodle].is-saying .say {
  opacity: 1;
  transform: none;
}

.look .say {
  left: 50%;
  bottom: calc(100% - 6px);
  align-items: center;
  max-width: 200px;
  border-radius: 18px;
  text-align: center;
  transform: translate(-50%, 8px) scale(0.9);
  transform-origin: 50% 100%;
}

.look:hover .say,
.look:focus-visible .say,
.look.is-saying .say {
  transform: translate(-50%, 0);
}

[data-doodle]:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.6);
  outline-offset: 4px;
}

/* ---- Closing call to action and footer ---------------------------------------------------- */

.cta {
  padding-top: 144px;
}

.cta__panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
  padding: 96px var(--gutter) 0;
  border-radius: 40px;
  background: linear-gradient(180deg, #000000 0%, #020106 30%, #0e0333 52%, #1d0868 70%, #3423b4 86%, #6a5ff0 100%);
  text-align: center;
}

.cta .avatar {
  --size: 64px;
}

.cta .pair .avatar + .avatar {
  border-width: 3px;
}

.cta .title {
  max-width: 720px;
  font-size: clamp(40px, 6vw, 64px);
  line-height: 1.02;
  letter-spacing: -0.04em;
}

.cta .lead {
  max-width: 480px;
  color: var(--ink);
}

.cta .joined {
  background: rgba(0, 0, 0, 0.35);
  border-color: rgba(47, 210, 122, 0.4);
}

.site-footer {
  /* The small print along the closing panel's bottom edge, as wide as the page's content. */
  align-self: stretch;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  max-width: calc(1120px - 2 * var(--gutter));
  margin: 74px auto 0;
  padding-block: 22px 24px;
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  font-size: 13px;
  color: rgba(255, 255, 255, 0.9);
}

.site-footer a {
  color: #ffffff;
}

.site-footer a:hover {
  color: #ffffff;
  text-decoration-thickness: 2px;
}

.site-footer .brand {
  gap: 8px;
  font-size: 13px;
  letter-spacing: 0;
}

/* ---- Responsive --------------------------------------------------------------------------- */

@media (max-width: 960px) {
  .split {
    flex-direction: column;
    gap: 56px;
  }

  .split__text {
    flex: none;
    width: 100%;
    max-width: 560px;
    align-items: center;
    text-align: center;
  }

  .split__phone {
    flex: none;
    width: 100%;
    order: 2;
  }

  .site-footer {
    flex-direction: column;
    justify-content: center;
    text-align: center;
  }
}

/* Tablet: the three cards under each side-by-side section sit in a row, wider than the text
   column, each one centred with its icon on top. On phones they stay stacked. */
@media (min-width: 601px) and (max-width: 960px) {
  .features {
    flex-direction: row;
    align-self: center;
    width: calc(100vw - 24px - 2 * var(--gutter));
    max-width: 880px;
  }

  .feature {
    flex: 1 1 0;
    min-width: 0;
    flex-direction: column;
    gap: 12px;
    padding: 20px 16px;
    text-align: center;
  }

  .feature__text {
    align-items: center;
  }
}

@media (max-width: 960px) {
  .score {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 48px 32px;
  }

  .score__phone {
    grid-column: 1 / -1;
    order: -1;
  }

  .score__notes,
  .score__notes:first-child,
  .score__notes:last-child {
    align-items: center;
    gap: 32px;
    text-align: center;
  }

  .score__note {
    align-items: center;
  }

  .score__notes:first-child strong {
    flex-direction: row;
  }
}

@media (max-width: 600px) {
  .score {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }
}

/* The cast drops its outer doodles as the screen narrows, then shrinks the pair. */
@media (max-width: 1180px) {
  .cast__doodle--6 {
    display: none;
  }
}

@media (max-width: 1040px) {
  .cast__doodle--5 {
    display: none;
  }
}

@media (max-width: 900px) {
  .cast__doodle--4 {
    display: none;
  }

  .cast__row {
    --pair: 92px;
    gap: 18px;
  }
}

@media (max-width: 640px) {
  .hero__body {
    gap: 36px;
    padding-bottom: 96px;
  }

  .cast__doodle--3 {
    display: none;
  }

  .cast__row {
    --pair: 80px;
    gap: 12px;
  }

  .cast__doodle--2 {
    --size: 56px;
    --lift: 20px;
  }

  /* Room above the pair for a two-line bubble, which reaches a little past its wingmate's
     outer edge so it stays inside the panel. */
  .cast {
    padding-top: 56px;
  }

  .cast__bubble {
    left: -24px;
    max-width: 150px;
    font-size: 13px;
    line-height: 18px;
  }

  .say {
    left: 0;
    max-width: 160px;
    font-size: 13px;
    line-height: 18px;
  }

  .cast__spark ~ .cast__doodle .say {
    right: 0;
  }

  .look .say {
    max-width: 170px;
  }

  .cast__bubble--mine {
    left: auto;
    right: -24px;
  }
}

/* Phones: the form stacks into a full-width field over a full-width button. */
@media (max-width: 480px) {
  .join {
    flex-direction: column;
    align-items: stretch;
    border-radius: 28px;
  }

  .join input {
    flex: none;
    text-align: center;
  }
}

/* ---- Scroll motion ------------------------------------------------------------------------ */

/* Smooth wheel scrolling comes from Lenis (vendor/lenis.min.js); these are its required rules. */
html.lenis,
html.lenis body {
  height: auto;
}

.lenis:not(.lenis-autoToggle).lenis-stopped {
  overflow: clip;
}

/* The hero arrives on load: the copy rises in, line by line, while the cast pops up from the
   middle outward. */
.has-motion .hero__copy > * {
  animation: arrive 1.1s var(--ease-expo) both;
}

.has-motion .hero__copy > :nth-child(2) {
  animation-delay: 0.08s;
}

.has-motion .hero__copy > :nth-child(3) {
  animation-delay: 0.16s;
}

.has-motion .hero__copy > :nth-child(n + 4) {
  animation-delay: 0.24s;
}

/* Backwards, not both: once a doodle has arrived its animation lets go, so nothing holds its
   opacity and the frosted lines can blur the doodles behind them. */
.has-motion .cast__doodle {
  animation: cast-in 1s var(--ease-spring) var(--in) backwards;
}

.has-motion .cast__spark {
  animation: fade-in 0.8s var(--ease-out) 0.5s backwards;
}

/* Everything else rises into place as it scrolls into view, a beat apart within its group
   (main.js sets --i and removes the attribute once the move is done). */
.has-motion [data-reveal] {
  opacity: 0;
  transform: translateY(32px);
  filter: blur(8px);
  transition:
    opacity 0.9s var(--ease-out),
    transform 1.2s var(--ease-expo),
    filter 0.9s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 70ms);
}

.has-motion [data-reveal].is-in {
  opacity: 1;
  transform: none;
  filter: blur(0);
}

.show-all [data-reveal] {
  opacity: 1 !important;
  transform: none !important;
  filter: none !important;
}

/* Scroll-linked pieces: main.js writes their transforms every frame. */
.has-motion [data-parallax] {
  will-change: transform;
}

.has-motion .phone[data-parallax] {
  transform-origin: 50% 100%;
  will-change: transform, opacity;
}

/* ---- Keyframes ---------------------------------------------------------------------------- */

@keyframes arrive {
  from {
    opacity: 0;
    transform: translateY(28px);
    filter: blur(10px);
  }
  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

@keyframes cast-in {
  from {
    opacity: 0;
    transform: translateY(28px) scale(0.6);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(12px);
    filter: blur(4px);
  }
  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

@keyframes pop {
  0% {
    opacity: 0;
    transform: translateY(6px) scale(0.86);
  }
  45% {
    opacity: 1;
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes typing {
  0%,
  80%,
  100% {
    opacity: 0.35;
    transform: scale(0.78);
  }
  40% {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes breathe-dot {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.45;
    transform: scale(0.78);
  }
}

@keyframes tap {
  0% {
    opacity: 0;
    transform: scale(0.5);
  }
  35% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(1.5);
  }
}

@keyframes bob {
  0%,
  100% {
    transform: translateY(0) rotate(0deg);
  }
  50% {
    transform: translateY(-5px) rotate(-2deg);
  }
}

@keyframes bob-flip {
  0%,
  100% {
    transform: scaleX(-1) translateY(0) rotate(0deg);
  }
  50% {
    transform: scaleX(-1) translateY(-6px) rotate(-2deg);
  }
}

@keyframes twinkle {
  0%,
  100% {
    opacity: 0.75;
    transform: scale(0.86) rotate(0deg);
  }
  50% {
    opacity: 1;
    transform: scale(1.08) rotate(12deg);
  }
}

@keyframes bob-small {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-2px);
  }
}

@keyframes breathe {
  0%,
  100% {
    transform: translateX(0) scale(1);
  }
  50% {
    transform: translateX(calc(var(--amp, 0) * 4px)) scale(calc(1 + var(--amp, 0) * 0.18));
  }
}

@keyframes sway {
  0%,
  100% {
    transform: rotate(calc(var(--amp, 0) * -1.6deg));
  }
  50% {
    transform: rotate(calc(var(--amp, 0) * 1.6deg));
  }
}

/* Reduced motion: every phone shows its finished screen and nothing loops. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}
