/*
 * Reusable pieces of the waitlist page. Each block matches one Framer component
 * (named in the comment) so it's easy to compare against the Framer project.
 */

/* ---------- Background video (Framer: "Video") ---------- */

.bg-video {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  background-color: var(--color-video-fallback);
  pointer-events: none;
}

/* ---------- Film grain (Framer: "Noise" code component) ----------
   Framer stacks a soft-light layer holding a multiply-blended canvas of random
   grey pixels over the whole hero, including the card. */

.grain {
  position: absolute;
  top: -17px;
  left: 0;
  z-index: 10;
  width: 100%;
  height: max(100vh, 100%);
  overflow: clip;
  mix-blend-mode: soft-light;
  pointer-events: none;
  user-select: none;
}

.grain__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 45px;
  mix-blend-mode: multiply;
  image-rendering: pixelated;
}

/* ---------- Card (Framer: "Beta Link" component, the frosted panel) ---------- */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  width: max-content;
  min-height: 420px;
  padding: 20px 22px 25px;
  border-radius: var(--radius-card);
  overflow: clip;
  background-color: var(--color-card-tint);
  -webkit-backdrop-filter: blur(11px);
  backdrop-filter: blur(11px);
  box-shadow:
    0 0.602px 3.011px -1.25px rgba(0, 0, 0, 0.18),
    0 2.289px 11.443px -2.5px rgba(0, 0, 0, 0.16),
    0 10px 50px -3.75px rgba(0, 0, 0, 0.06);
}

/* 1px white border drawn inside the card, like Framer's data-border overlay. */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--color-white);
  border-radius: inherit;
  pointer-events: none;
}

.card__intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
}

.card__heading-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  max-width: 100%;
}

.card__title {
  font-family: var(--font-display);
  font-size: 60px;
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.04em;
  text-align: center;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--color-white);
}

.card__subtitle {
  width: 302px;
  max-width: 100%;
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--color-subtitle);
}

/* ---------- Badge (Framer: "Badge") ---------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 16px;
  border-radius: var(--radius-pill);
  background-color: var(--color-badge-bg);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  overflow: hidden;
  font-family: var(--font-body-medium);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.03em;
  color: var(--color-white);
  white-space: nowrap;
}

.badge__logo {
  width: 21px;
  height: 17px;
  flex: none;
}

/* ---------- Waitlist form (Framer: "Input Form") ---------- */

.waitlist-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-self: stretch;
  /* Like Framer, the form fills the card but never makes it wider: the card's
     width comes from the heading and beta line only. */
  width: 0;
  min-width: 100%;
  position: relative;
  margin: 0;
}

.waitlist-form__row {
  display: flex;
  gap: 16px;
}

.field {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  height: 40px;
  border-radius: var(--radius-field);
  background: var(--color-input-bg);
}

.field::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--color-input-border);
  border-radius: inherit;
  pointer-events: none;
}

/* Email failed the check: red outline (keyboard focus, below, still shows blue). */
.field.field--invalid::after {
  border-color: var(--color-error);
}

.field:focus-within::after {
  border-color: var(--color-focus);
}

.field__input {
  display: block;
  width: 100%;
  height: 100%;
  padding: 12px;
  border: 0;
  border-radius: inherit;
  background: transparent;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0;
  color: var(--color-input-text);
  text-overflow: ellipsis;
  white-space: nowrap;
  outline: none;
}

.field__input::placeholder {
  color: var(--color-input-placeholder);
  opacity: 1;
}

/* Message under the email field ("Please enter your email address." …). */
.field-error {
  margin: -8px 0 0;
  font: 600 13px/1.3 var(--font-ui);
  color: var(--color-error);
  text-align: left;
}

/* Spam traps (Framer adds the same 11 hidden fields). Kept out of view and tab order. */
.honeypot {
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 1px;
  opacity: 0;
  transform: scale(0);
  pointer-events: none;
}

/* ---------- Submit button (Framer: "Button 2") ----------
   States, via data-state: idle | loading | success | error */

.submit-button {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-field);
  background-color: var(--color-off-white);
  color: var(--color-ink);
  font-family: var(--font-body-medium);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition:
    opacity 0.2s var(--ease-framer),
    background-color 0.2s var(--ease-framer);
}

.submit-button[data-state="idle"]:not(:disabled):hover,
.submit-button[data-state="idle"]:not(:disabled):active {
  opacity: 0.8;
}

/* The button ships disabled and the script enables it. If the script never runs
   (no JS, blocked, or crashed: html.js is then absent), show Framer's own
   "Disabled" variant so it doesn't look clickable. */
.submit-button:disabled {
  cursor: not-allowed;
}

html:not(.js) .submit-button:disabled {
  opacity: 0.5;
}

.submit-button[data-state="loading"],
.submit-button[data-state="success"] {
  cursor: default;
}

.submit-button__label--result {
  font-family: var(--font-ui);
  font-weight: 600;
}

.submit-button[data-state="error"] {
  background-color: var(--color-error-bg);
  color: var(--color-error);
}

/* Only the label for the current state is shown. */
.submit-button__label,
.submit-button__spinner {
  display: none;
}

.submit-button[data-state="idle"] .submit-button__label--idle,
.submit-button[data-state="success"] .submit-button__label--success,
.submit-button[data-state="error"] .submit-button__label--error {
  display: inline;
}

/* Loading spinner: a 20px ring with a dark arc sweeping round once per second. */
.submit-button[data-state="loading"] .submit-button__spinner {
  display: block;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: conic-gradient(from 0deg, rgba(0, 0, 0, 0) 0deg, rgb(0, 0, 0) 360deg);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* ---------- Beta link line ---------- */

.beta-line {
  font-family: var(--font-ui);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--color-beta-label);
  white-space: nowrap;
  text-align: center;
}

.beta-line__link {
  color: var(--color-white);
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.3s var(--ease-framer);
}

.beta-line__link:hover {
  color: var(--color-link-hover);
}

/* ---------- Mock-mode and test-version notices (never on the real site) ---------- */

.mock-notice,
.test-notice {
  position: fixed;
  left: 50%;
  bottom: 12px;
  z-index: 20;
  transform: translateX(-50%);
  max-width: calc(100% - 24px);
  padding: 6px 12px;
  border-radius: 8px;
  background: rgb(255, 214, 0);
  color: rgb(5, 5, 5);
  font: 600 12px/1.3 var(--font-ui);
  text-align: center;
}

/* ---------- Entrance animations (Framer appear effects) ----------
   Only run when JS is on (html.js) and the visitor hasn't asked for reduced motion. */

@media (prefers-reduced-motion: no-preference) {
  /* Badge wrapper: fades in after 1s. Badge itself rises and grows from 0.1s. */
  .js .badge-reveal {
    opacity: 0;
    animation: fade-in var(--spring-soft-duration) var(--spring-soft) 1s forwards;
  }

  .js .badge-reveal > .badge {
    opacity: 0;
    transform: perspective(1200px) translateY(100px) scale(0.9);
    animation: rise-in var(--spring-pop-duration) var(--spring-pop) 0.1s forwards;
  }

  /* Text split into words by reveal.js; each word un-blurs and rises 10px. */
  .js [data-reveal] {
    visibility: hidden;
  }

  .js [data-reveal].is-split {
    visibility: visible;
  }

  .word {
    display: inline-block;
    opacity: 0;
    filter: blur(4px);
    transform: translateY(10px);
    animation: word-in var(--spring-soft-duration) var(--spring-soft) forwards;
    animation-delay: var(--word-delay, 0s);
  }
}

@keyframes word-in {
  to {
    opacity: 1;
    filter: blur(0);
    transform: translateY(0);
  }
}
