/* Colors come from Sources/Vishot/Palette.swift, so the page, the logo and the app share one look. */
:root {
  --bg: #12121a;
  --surface: #1b1b28;
  --surface-2: #232336;
  --line: #34344e;
  --text: #ededf5;
  --muted: #a3a3bd;
  --accent: #6b5cfa;          /* Palette.accent: selection border */
  --accent-text: #a59cff;     /* accent lifted to 4.5:1 on --bg for small text */
  --hint: #ffd147;            /* Palette.hintLeaf: hint labels */
  --danger: #ff7a7a;
  --pixel: "Silkscreen", ui-monospace, monospace;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --step: steps(4, jump-none);
}

@font-face {
  font-family: "Silkscreen";
  src: url("fonts/silkscreen-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Silkscreen";
  src: url("fonts/silkscreen-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/jetbrains-mono-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/jetbrains-mono-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}

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

html { color-scheme: dark; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: var(--bg);
  color: var(--text);
  font: 400 1rem/1.6 var(--mono);
  -webkit-font-smoothing: antialiased;
}

/* The backdrop is two fixed layers behind the page: a sparse field of pixels far away and the
   pixel grid from the references nearer. main.js slides each at its own fraction of the scroll
   speed, so the page, the grid and the pixels move apart like planes at different depths.
   Each layer is one cell taller than the window, and moves by less than a cell (the scroll
   offset modulo the cell), so the translation stays on the compositor. */
body::before, body::after {
  content: "";
  position: fixed;
  inset: 0 0 auto;
  height: calc(100lvh + 128px);
  z-index: -1;
  pointer-events: none;
}
body::before {
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cg fill='%23a59cff'%3E%3Crect x='15' y='15' width='2' height='2' fill-opacity='.35'/%3E%3Crect x='79' y='47' width='2' height='2' fill-opacity='.2'/%3E%3Crect x='47' y='95' width='2' height='2' fill-opacity='.25'/%3E%3Crect x='111' y='111' width='2' height='2' fill-opacity='.15'/%3E%3C/g%3E%3C/svg%3E") 0 0 / 128px 128px;
  transform: translate3d(0, var(--far, 0px), 0);
}
body::after {
  background-image:
    linear-gradient(rgb(255 255 255 / 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgb(255 255 255 / 0.05) 1px, transparent 1px);
  background-size: 32px 32px;
  background-position: -1px -1px;
  transform: translate3d(0, var(--near, 0px), 0);
}

main { flex: 1; }

/* Foreground pieces sit a little closer than their section: main.js moves them by --lift
   while the section is coming in or going out, and at rest they are where the layout put them. */
.depth { transform: translate3d(0, var(--lift, 0px), 0); }

a { color: var(--accent-text); }

:focus-visible {
  outline: 2px solid var(--hint);
  outline-offset: 3px;
}

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

/* Honeypot: off-screen rather than display:none, which some bots skip. */
.trap {
  position: absolute;
  left: -10000px;
  width: 1px; height: 1px;
  overflow: hidden;
}

.skip {
  position: absolute;
  left: 1rem; top: -3rem;
  padding: .5rem .75rem;
  background: var(--hint);
  color: var(--bg);
  z-index: 10;
}
.skip:focus { top: 1rem; }

kbd {
  display: inline-block;
  min-width: 1.6em;
  padding: 0 .35em;
  margin: 0 .1em;
  border: 1px solid var(--line);
  border-bottom-width: 3px;
  background: var(--surface-2);
  color: var(--text);
  font: 700 .82em/1.5 var(--mono);
  text-align: center;
}

/* ---------- Header ---------- */

.top, .hero, .demo, .faq, .closing, .bottom {
  width: min(1200px, 100% - 2.5rem);
  margin-inline: auto;
}

.top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.5rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  color: var(--text);
  font: 700 1.25rem/1 var(--pixel);
  text-decoration: none;
}

.top-note {
  margin: 0;
  color: var(--muted);
  font-size: .8rem;
  letter-spacing: .08em;
  text-transform: uppercase;
}

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

.hero { padding-block: clamp(.5rem, 3vw, 2rem) 2rem; }

.headline {
  position: relative;
  margin: 0 0 1.75rem;
  font: 700 clamp(2.1rem, 5vw, 4.5rem)/1 var(--pixel);
  letter-spacing: -0.01em;
  text-transform: uppercase;
}
.headline .line { display: block; }
.headline .accent { color: var(--accent-text); }

.subline {
  margin: 0 0 3rem;
  font: 700 clamp(1rem, 2vw, 1.5rem)/1.2 var(--pixel);
}

.keys-word {
  color: var(--accent-text);
  text-transform: none;
  text-shadow: 0 0 24px rgb(107 92 250 / 0.45);
}

/* Covers the headline and is cleared block by block on load; see dissolve() in main.js. */
.dissolve {
  position: absolute;
  inset: -4px;
  width: calc(100% + 8px);
  height: calc(100% + 8px);
  image-rendering: pixelated;
  pointer-events: none;
}

.hero-row {
  display: grid;
  grid-template-columns: minmax(0, 36rem);
  gap: 3rem;
}

.lede {
  margin: 0;
  max-width: 36rem;
  color: var(--muted);
  font-size: 1.05rem;
}

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

.waitlist label {
  display: block;
  margin-bottom: .5rem;
  font: 700 .95rem/1 var(--pixel);
  text-transform: uppercase;
  letter-spacing: .04em;
}

.field {
  display: flex;
  gap: .75rem;
}

.field input {
  flex: 1;
  min-width: 0;
  min-height: 48px;
  padding: 0 .9rem;
  border: 2px solid var(--line);
  border-radius: 0;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  caret-color: var(--hint);
  transition: border-color .15s;
}
.field input::placeholder { color: #75758f; }
.field input:hover { border-color: #4a4a6a; }
.field input:focus-visible { outline: none; border-color: var(--accent); }
.field input[aria-invalid="true"] { border-color: var(--danger); }

.field button {
  position: relative;
  min-height: 48px;
  padding: 0 1.2rem;
  border: 0;
  border-radius: 0;
  background: var(--accent);
  color: #fff;
  font: 700 .95rem/1 var(--pixel);
  text-transform: uppercase;
  cursor: pointer;
  /* A hard pixel shadow that the button presses into. */
  box-shadow: 4px 4px 0 var(--hint);
  transition: transform .1s var(--step), box-shadow .1s var(--step), background-color .15s;
}
.field button:hover { background: #7c6efb; }
.field button:active { transform: translate(4px, 4px); box-shadow: 0 0 0 var(--hint); }
.field button[disabled] { cursor: progress; background: #4f45b8; }

.error, .status { margin: .5rem 0 0; font-size: .875rem; }
.error { color: var(--danger); }
.error:empty, .status:empty { display: none; }
.status { color: var(--hint); }

.privacy {
  margin: .9rem 0 0;
  color: var(--muted);
  font-size: .75rem;
  line-height: 1.5;
}

.waitlist.done .field { display: none; }
.waitlist.done label { color: var(--hint); }

/* Joining takes a screenshot of the form, the way Vishot does: the selection ring snaps onto it,
   the shutter flashes, and the shot shrinks into the corner with its watermark. See shoot() in
   main.js, which positions and animates these. */
.shot-ring, .shot-flash, .shot {
  position: fixed;
  z-index: 20;
  pointer-events: none;
}
.shot-flash { background: #fff; }
.shot {
  /* With the border, 1rem around the form. */
  padding: calc(1rem - 2px);
  border: 2px solid var(--line);
  background: var(--bg);
  box-shadow: 8px 8px 0 rgb(0 0 0 / 0.45);
  transform-origin: 0 0;
}
.shot .waitlist { margin: 0; }
/* Like Watermark.swift: the pixel font on a dark plate with a hard amber shadow. */
.shot-mark {
  position: absolute;
  right: .5rem;
  bottom: .5rem;
  padding: .15rem .4rem;
  background: var(--bg);
  border: 1px solid var(--line);
  box-shadow: 2px 2px 0 var(--hint);
  color: var(--text);
  font: 700 .7rem/1 var(--pixel);
  text-transform: uppercase;
}
.shot-tag {
  position: fixed;
  z-index: 21;
  padding: .3rem .55rem;
  background: var(--accent);
  box-shadow: 3px 3px 0 var(--hint);
  color: #fff;
  font: 700 .85rem/1 var(--pixel);
  text-transform: uppercase;
  pointer-events: none;
}

/* ---------- Demo ---------- */

.demo {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 1.5rem 2.5rem;
  padding-block: 1rem 3rem;
}

.screen { margin: 0; align-self: start; }

.monitor {
  position: relative;
  padding: 10px;
  background: var(--surface);
  border: 2px solid var(--line);
  box-shadow: 8px 8px 0 rgb(0 0 0 / 0.45);
}

#scene {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 192 / 120;
  image-rendering: pixelated;
  background: #191928;
}

.playpause {
  flex: none;
  margin-left: auto;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 2px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.playpause:hover { color: var(--text); border-color: var(--accent); }
.playpause svg { width: 16px; height: 16px; fill: currentColor; shape-rendering: crispEdges; }
.playpause .i-play { display: none; }
.playpause[data-paused] .i-play { display: block; }
.playpause[data-paused] .i-pause { display: none; }

.keycast {
  display: flex;
  align-items: center;
  gap: .9rem;
  min-height: 3.25rem;
  padding: .6rem .2rem 0;
  color: var(--muted);
  font-size: .9rem;
}
.keycast-keys { display: inline-flex; gap: .3rem; }
.keycast-keys kbd {
  font-size: 1.05rem;
  border-color: var(--accent);
  animation: keypress .24s var(--step);
}

@keyframes keypress {
  0% { transform: translateY(3px); border-bottom-width: 1px; }
  100% { transform: none; }
}

/* ---------- Features ---------- */

.features {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

.feature {
  position: relative;
  padding: .85rem 1rem 1rem;
  /* Solid and edged like the monitor, so the cards stand off the grid as much as it does. */
  border: 2px solid var(--line);
  background: var(--surface);
  box-shadow: 4px 4px 0 rgb(0 0 0 / 0.45);
  transition: background-color .2s, border-color .12s var(--step);
}

/* The active feature gets the demo's selection border: one of its pixels wide (--px, measured
   from the canvas in main.js), corner pixels left out, just outside the card. The card's own edge
   goes, so the ring is the edge, as when the demo selects a window. */
.feature::after, .faq details::after, .shot-ring {
  background:
    linear-gradient(var(--accent), var(--accent)) top / calc(100% - 2 * var(--px, 3px)) var(--px, 3px) no-repeat,
    linear-gradient(var(--accent), var(--accent)) bottom / calc(100% - 2 * var(--px, 3px)) var(--px, 3px) no-repeat,
    linear-gradient(var(--accent), var(--accent)) left / var(--px, 3px) calc(100% - 2 * var(--px, 3px)) no-repeat,
    linear-gradient(var(--accent), var(--accent)) right / var(--px, 3px) calc(100% - 2 * var(--px, 3px)) no-repeat;
  pointer-events: none;
}
.feature::after, .faq details::after {
  content: "";
  position: absolute;
  inset: calc(-2px - var(--px, 3px));
  opacity: 0;
  transition: opacity .12s var(--step);
  pointer-events: none;
}
.feature.active, .feature:hover { background: var(--surface-2); }
.feature.active, .faq details[open] { border-color: transparent; }
.feature.active::after, .faq details[open]::after { opacity: 1; }

.feature-head {
  display: flex;
  align-items: center;
  gap: .75rem;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text);
  font: 700 1rem/1.3 var(--pixel);
  text-align: left;
  text-transform: uppercase;
  cursor: pointer;
}
/* Stretch the button over the whole card so all of it is clickable. */
.feature-head::before { content: ""; position: absolute; inset: 0; }

.hint {
  flex: none;
  padding: .1rem .35rem;
  background: var(--hint);
  color: var(--bg);
  font: 700 .8rem/1.2 var(--mono);
}

/* Only the active feature shows its text, so the whole list fits beside the monitor.
   Without JS nothing is active and every text stays visible. */
.features:has(.active) .feature:not(.active) p { display: none; }

.feature p {
  margin: .45rem 0 0 calc(2.1rem + .75rem);
  color: var(--muted);
  font-size: .875rem;
  line-height: 1.55;
}

.feature code {
  padding: 0 .3em;
  background: var(--surface-2);
  color: var(--text);
  font: 400 .95em/1.5 var(--mono);
}

.progress {
  position: absolute;
  left: 0; bottom: 0;
  height: 3px;
  width: 100%;
  background: var(--hint);
  transform-origin: left;
  transform: scaleX(0);
}

/* ---------- FAQ ---------- */

.faq {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2rem;
  padding-block: 2rem 4rem;
}

.faq-title {
  margin: 0;
  text-align: center;
  font: 700 clamp(1.6rem, 3vw, 2.25rem)/1 var(--pixel);
  text-transform: uppercase;
}

.faq-list {
  width: min(48rem, 100%);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

.faq details {
  position: relative;
  border: 2px solid var(--line);
  background: var(--surface);
  box-shadow: 4px 4px 0 rgb(0 0 0 / 0.45);
  transition: background-color .2s, border-color .12s var(--step);
}
.faq details:hover, .faq details[open] { background: var(--surface-2); }
.faq details[open] { border-color: var(--accent); }

/* An open answer gets the same selection border as the active feature. */
.faq details::after {
  content: "";
  position: absolute;
  inset: -4px;
  border: 3px solid var(--accent);
  border-radius: 6px;
  opacity: 0;
  transition: opacity .12s var(--step);
  pointer-events: none;
}
.faq details[open]::after { opacity: 1; }

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .85rem 1rem;
  font: 700 1rem/1.3 var(--pixel);
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }

/* A pixel plus that drops its vertical bar when open. */
.faq summary::after {
  content: "";
  flex: none;
  width: 12px;
  height: 12px;
  background:
    linear-gradient(var(--hint), var(--hint)) center / 12px 4px no-repeat,
    linear-gradient(var(--hint), var(--hint)) center / 4px 12px no-repeat;
}
.faq details[open] summary::after {
  background: linear-gradient(var(--hint), var(--hint)) center / 12px 4px no-repeat;
}

.faq details p {
  margin: 0;
  padding: 0 1rem 1rem;
  color: var(--muted);
  font-size: .875rem;
  line-height: 1.55;
}

/* ---------- Reveal on load ---------- */

.js .reveal { opacity: 0; }
.js .reveal.in { animation: reveal .42s var(--step) both; }
@keyframes reveal {
  from { opacity: 0; clip-path: inset(0 0 100% 0); }
  /* Ends past the box, so a selection ring or shadow outside it is not clipped. */
  to { opacity: 1; clip-path: inset(-2rem); }
}

/* ---------- Closing sign-up ---------- */

.closing {
  display: grid;
  grid-template-columns: 1fr minmax(0, 30rem);
  gap: 1.5rem 4rem;
  align-items: center;
  padding-block: 1rem 2rem;
}
.closing-title {
  margin: 0;
  font: 700 clamp(1.6rem, 3vw, 2.25rem)/1.1 var(--pixel);
  text-transform: uppercase;
}

/* ---------- Section dots (only where the page snaps) ---------- */

.dots { display: none; }

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

.bottom {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.5rem 2rem;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: .8rem;
}

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

@media (max-width: 960px) {
  .demo, .faq, .closing { grid-template-columns: 1fr; }
}

@media (max-width: 520px) {
  .field { flex-direction: column; }
  .field button { min-height: 52px; }
  .top-note { display: none; }
  .headline .line { display: inline; }
  .feature p { margin-left: 0; }
}

/* ---------- One section at a time ----------
   Big enough screens snap from section to section. Smaller ones scroll as a normal page,
   because a section taller than the window must stay reachable. */

@media (min-width: 961px) and (min-height: 640px) {
  html { scroll-snap-type: y mandatory; }

  .top { position: absolute; top: 0; left: 0; right: 0; z-index: 2; }

  .hero, .demo, .finale {
    box-sizing: border-box;
    min-height: 100svh;
    scroll-snap-align: start;
    padding-top: 5.5rem;
  }
  .hero { display: flex; flex-direction: column; justify-content: center; padding-bottom: 3rem; }
  /* The guide gets most of the window: wider than the other sections, and the monitor as large as
     the height allows (the 13rem is the header, keycast bar and padding). */
  .demo {
    width: min(1680px, 100% - 7rem);
    grid-template-columns: minmax(0, 1fr) minmax(0, 28rem);
    gap: 1.5rem 3.5rem;
    align-content: center;
    padding-bottom: 3rem;
  }
  .screen { width: 100%; max-width: calc((100svh - 13rem) * 1.6); margin-inline: auto; }
  .finale { display: flex; flex-direction: column; justify-content: center; width: 100%; }
  /* The last section has to fit in one window, or the snap lets you scroll inside it. */
  .finale { padding-top: 3.5rem; padding-bottom: 0; justify-content: flex-start; }
  /* The FAQ sits near the top; auto margins centre the sign-up between it and the footer. */
  .finale .faq { gap: 1.25rem; padding-block: 0 .5rem; }
  .finale .faq-list { gap: .35rem; }
  /* Minus the 2px border, so the list is no taller than it was without one. */
  .finale .faq summary { padding-block: calc(.6rem - 2px); }
  .finale .closing { padding-block: 1.5rem; margin-block: auto; }
  .finale .closing-title { font-size: clamp(1.4rem, 2.4vw, 1.9rem); }
  .finale .bottom { padding-block: 1.25rem; }
  .finale .bottom { width: min(1200px, 100% - 2.5rem); box-sizing: border-box; margin-inline: auto; }
  .finale .bottom { align-self: stretch; }

  .dots {
    position: fixed;
    right: 1.25rem;
    top: 50%;
    z-index: 3;
    display: flex;
    flex-direction: column;
    gap: .75rem;
    transform: translateY(-50%);
  }
  .dots a {
    width: 12px;
    height: 12px;
    border: 2px solid var(--line);
    background: var(--surface);
    transition: background-color .12s var(--step), border-color .12s var(--step);
  }
  .dots a:hover { border-color: var(--accent); }
  .dots a[aria-current="true"] { background: var(--accent); border-color: var(--accent); }
}

@media (min-width: 961px) and (min-height: 640px) and (max-height: 800px) {
  .finale { padding-top: 3rem; }
  .finale .faq { gap: .75rem; }
  .finale .faq summary { padding-block: calc(.4rem - 2px); }
  .finale .faq-list { gap: .25rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-snap-type: none; }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    transition-duration: 1ms !important;
  }
  .js .reveal { opacity: 1; }
}
