/* feria — teaser landing page
   Dark, monospace aesthetic over an animated ASCII energy field (canvas). */

:root {
  color-scheme: dark;

  --bg: #0a0b0d;
  --ink: #e9ebed;
  --ink-soft: #a3aab0;
  --ink-mono: #5d646b;
  --ink-faint: #43494f;
  --line: #23272b;
  --panel: #111316;

  --accent: oklch(0.64 0.12 170);
  --accent-link: oklch(0.74 0.11 170);
  --accent-link-hover: oklch(0.82 0.10 170);
}

html, body {
  margin: 0;
  height: 100%;
  width: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--bg);
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-wrap: pretty;
  /* Keep mobile browsers from "boosting" text on rotate, which would resize
     the layout under the fixed one-screen stage. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

a { color: var(--accent-link); text-decoration: none; }
a:hover { color: var(--accent-link-hover); }

/* The `hidden` attribute must win over the explicit `display` rules below. */
[hidden] { display: none !important; }
::selection { background: oklch(0.34 0.06 170); }

@keyframes fx-blink { 0%, 48% { opacity: 1; } 52%, 100% { opacity: 0; } }
@keyframes fx-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fx-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
@keyframes fx-dots { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "..."; } }

/* ---- Stage -------------------------------------------------------------- */

/* `svh` (not `dvh`) so the stage keeps one fixed height on mobile: it stays
   put when the URL bar collapses or the keyboard opens, instead of resizing
   and re-laying out the ASCII field mid-interaction. */
.stage {
  position: relative;
  width: 100%;
  height: 100vh;
  height: 100svh;
  min-height: 640px;
  overflow: hidden;
  background: var(--bg);
  color: var(--ink);
}

.stage__glow {
  position: absolute;
  inset: 0;
  background: radial-gradient(90% 60% at 50% 0%, #111418 0%, #0a0b0d 62%);
}

/* ---- ASCII energy field (canvas) --------------------------------------- */

/* Full-viewport grid of monospace glyphs whose character, colour and glow
   track a drifting energy blob. Rendered by ascii-field.js. */
.field {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* Vignette that keeps the centred wordmark and form legible over the field
   without washing out the glow. */
.stage__veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(50% 42% at 50% 50%,
      rgba(10, 11, 13, 0.9) 0%,
      rgba(10, 11, 13, 0.82) 34%,
      rgba(10, 11, 13, 0.42) 62%,
      transparent 84%),
    linear-gradient(to bottom, transparent 60%, rgba(10, 11, 13, 0.5) 100%);
}

/* ---- Center content ----------------------------------------------------- */

.center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 28px;
}

.wordmark {
  margin: 0;
  font: 400 clamp(46px, 7.4vw, 88px)/1 "Helvetica Neue", Helvetica, sans-serif;
  letter-spacing: -0.042em;
  text-shadow: 0 2px 40px rgba(10, 11, 13, 0.9), 0 0 12px rgba(10, 11, 13, 0.7);
  animation: fx-rise 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

.tagline {
  margin: clamp(20px, 3vh, 30px) 0 0;
  max-width: 20em;
  font: 400 17px/1.5 "Helvetica Neue", Helvetica, sans-serif;
  color: var(--ink-soft);
  text-shadow: 0 1px 24px rgba(10, 11, 13, 0.95);
  animation: fx-rise 0.7s 0.1s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

/* ---- Waitlist join ------------------------------------------------------ */

.join {
  margin-top: 30px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: fx-rise 0.7s 0.2s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

.join__box {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 13px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--panel);
  transition: border-color 0.3s ease;
  max-width: 100%;
  /* No double-tap-to-zoom delay or gesture on the form. */
  touch-action: manipulation;
}

/* Invalid email or a failed submit — nudge the border without shouting. */
.join__box[data-state="error"] {
  border-color: oklch(0.58 0.15 25);
}

.join__prompt {
  color: var(--accent);
  font: 400 12.5px "IBM Plex Mono", monospace;
}

.join__input {
  flex: none;
  box-sizing: border-box;
  width: 150px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--ink);
  font: 400 12.5px "IBM Plex Mono", monospace;
  outline: none;
}

.join__hint {
  font: 400 11px "IBM Plex Mono", monospace;
  letter-spacing: 0.06em;
  color: var(--ink-mono);
  opacity: 0.35;
  transition: opacity 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.join__hint.is-ready { opacity: 1; }

.join__done {
  display: flex;
  flex-direction: column;
  gap: 5px;
  text-align: left;
  font: 400 12.5px/1.5 "IBM Plex Mono", monospace;
}
.join__echo { color: var(--ink-mono); }
.join__ok {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--accent);
}

/* Skeleton placeholder shown while the waitlist request is in flight, so the
   network hang has feedback instead of a frozen, disabled input. */
.join__skeleton {
  display: none;
  align-items: center;
  gap: 10px;
}
.join__bar {
  width: 150px;
  height: 12px;
  border-radius: 3px;
  background: linear-gradient(
    90deg,
    var(--line) 0%,
    var(--ink-mono) 50%,
    var(--line) 100%
  );
  background-size: 200% 100%;
  animation: fx-shimmer 1.25s ease-in-out infinite;
}
.join__sending {
  font: 400 11px "IBM Plex Mono", monospace;
  letter-spacing: 0.06em;
  color: var(--ink-mono);
}
.join__dots::after {
  content: "";
  animation: fx-dots 1.2s steps(1, end) infinite;
}

/* loading: show the skeleton, hide the final confirmation. */
.join__done[data-state="loading"] .join__skeleton { display: flex; }
.join__done[data-state="loading"] .join__ok { display: none; }
.join__cursor {
  width: 1px;
  height: 12px;
  background: var(--accent);
  animation: fx-blink 1.15s step-end infinite;
}

/* ---- Footer ------------------------------------------------------------- */

.footer {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 20px 28px;
  display: flex;
  align-items: center;
  gap: 16px;
  font: 400 10.5px "IBM Plex Mono", monospace;
  color: var(--ink-faint);
}

/* ---- Touch / mobile ----------------------------------------------------- */

/* iOS Safari zooms the page whenever a focused field computes to less than
   16px, so on touch devices the input (and the sizes tied to it) go up to 16px
   rather than the 12.5px used on pointer devices. Nothing else is scaled. */
@media (pointer: coarse) {
  .join { width: 100%; }

  /* Fluid box so the larger type still fits a 320px screen. */
  .join__box { width: min(100%, 340px); }

  .join__input {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
    font-size: 16px;
  }

  .join__prompt,
  .join__done {
    font-size: 16px;
  }

  .join__hint { white-space: nowrap; }
  .join__cursor { height: 15px; }
}

/* Short viewports (landscape phones) must not exceed the stage height, or the
   fixed, overflow-hidden body would clip the form. */
@media (max-height: 640px) {
  .stage { min-height: 0; }
  .join { margin-top: 20px; }
}

/* ---- Reduced motion ----------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .wordmark,
  .tagline,
  .join,
  .join__cursor,
  .join__bar,
  .join__dots::after {
    animation: none;
  }
}
