/*
  afk landing page.

  The whole design comes out of one decision: the page runs the product rather
  than illustrating it. That means the loudest thing on the screen is a canvas
  playing a real effect, so everything around it is deliberately quiet. One
  typeface, one grid, two accents, no gradients, no shadows, no rounded cards.

  Type is a pair, but only one of them is a font file. The display face is
  afk's own 5x7 bitmap, drawn into a canvas by afk-effects.js, because the tool
  ships a font and using anything else for the wordmark would be a choice made
  for no reason. JetBrains Mono carries everything a reader has to read.
*/

@font-face {
  font-family: "JetBrains Mono Local";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src:
    local("JetBrains Mono"),
    local("JetBrainsMono-Regular"),
    url("fonts/JetBrainsMono-Regular.woff2") format("woff2");
}

@font-face {
  font-family: "JetBrains Mono Local";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src:
    local("JetBrains Mono Bold"),
    local("JetBrainsMono-Bold"),
    url("fonts/JetBrainsMono-Bold.woff2") format("woff2");
}

:root {
  /*
    Every colour here is taken from the tool, not chosen for the page.
    --ember is the middle of afk's fire palette, --phosphor is the exact green
    the rain effect draws with. The two accents are assigned meaning and kept
    apart: phosphor is the tool speaking, ember is the tool burning.
  */
  --void: #050505;
  --shell: #0b0b0c;
  --rule: #1c1c1e;
  --ash: #74706b;
  --bone: #e8e4dc;
  --phosphor: #00ff41;
  --ember: #e85d04;

  /* the live accent, rewritten by the effect switcher */
  --live: var(--ember);

  --mono: "JetBrains Mono Local", ui-monospace, SFMono-Regular, Menlo, monospace;

  --enter: cubic-bezier(0.16, 1, 0.3, 1);
  --tap: cubic-bezier(0.2, 0, 0, 1);
}

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

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--void);
  color: var(--bone);
  font-family: var(--mono);
  font-size: 15px;
  line-height: 1.65;
  letter-spacing: -0.01em;
  overflow-x: hidden;
}

a {
  color: inherit;
  text-decoration-color: var(--rule);
  text-underline-offset: 4px;
  transition: text-decoration-color 140ms var(--tap);
}

a:hover {
  text-decoration-color: var(--live);
}

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

.skip {
  position: absolute;
  left: -9999px;
}

.skip:focus {
  left: 1rem;
  top: 1rem;
  z-index: 20;
  background: var(--bone);
  color: var(--void);
  padding: 0.5rem 0.75rem;
}

.wrap {
  width: min(1100px, 100% - 2.5rem);
  margin-inline: auto;
}

/* ------------------------------------------------------------------- hero */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 4rem 0 2rem;
  isolation: isolate;
}

/*
  The ambient layer is the same effect as the wordmark, at the same moment,
  turned almost all the way down. It is what makes the page feel like it is
  running rather than decorated.
*/
.ambient {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -2;
  /* decorative, and it spans the whole hero: it must never take a click that
     was aimed at the effect switcher sitting on top of it */
  pointer-events: none;
  opacity: 0.1;
  mask-image: linear-gradient(to bottom, #000 0%, rgba(0, 0, 0, 0.55) 38%, transparent 68%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0, 0, 0, 0.55) 38%, transparent 68%);
}

/* the character grid, so the ambient layer reads as cells and not as a photo */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.025) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.025) 1px, transparent 1px);
  background-size: 1rem 1rem;
  mask-image: linear-gradient(to bottom, #000 0%, transparent 80%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 80%);
}

.mark-shell {
  position: relative;
  width: min(560px, 100%);
}

.mark {
  display: block;
  width: 100%;
  aspect-ratio: 17 / 7;
  image-rendering: pixelated;
}

/* the cursor afk leaves blinking at the end of its own wordmark */
.mark-shell::after {
  content: "";
  position: absolute;
  right: -0.4em;
  bottom: 8%;
  width: clamp(9px, 1.8vw, 18px);
  height: clamp(20px, 4.6vw, 46px);
  background: var(--live);
  animation: blink 1.1s steps(1, end) infinite;
  transition: background 400ms var(--enter);
}

@keyframes blink {
  0%, 45% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

.tagline {
  margin: 1.5rem 0 0;
  font-size: clamp(1.05rem, 2.3vw, 1.5rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  max-width: 22ch;
  line-height: 1.25;
}

.lede {
  margin: 1rem 0 0;
  color: var(--ash);
  max-width: 58ch;
}

/* ---------------------------------------------------------------- command */

.command {
  margin-top: 1.5rem;
  display: flex;
  align-items: stretch;
  border: 1px solid var(--rule);
  background: rgba(11, 11, 12, 0.72);
  backdrop-filter: blur(6px);
  width: max-content;
  max-width: 100%;
}

.command code {
  padding: 0.7rem 1rem;
  font-size: 0.95rem;
  white-space: nowrap;
  overflow-x: auto;
}

.command .prompt {
  color: var(--live);
  transition: color 400ms var(--enter);
}

.copy {
  border: 0;
  border-left: 1px solid var(--rule);
  background: transparent;
  color: var(--ash);
  font: inherit;
  font-size: 0.8rem;
  padding-inline: 0.9rem;
  cursor: pointer;
  transition: color 140ms var(--tap), background 140ms var(--tap);
}

.copy:hover {
  color: var(--bone);
  background: rgba(255, 255, 255, 0.04);
}

.copy[data-state="done"] {
  color: var(--phosphor);
}

/* ------------------------------------------------------------------ strip */

/*
  The switcher is the demo. Every label here changes what is playing behind the
  wordmark, so reading the list and trying the product are the same gesture.
*/
.strip {
  margin-top: 1.75rem;
  display: flex;
  flex-wrap: wrap;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  width: max-content;
  max-width: 100%;
}

.strip button {
  border: 0;
  border-right: 1px solid var(--rule);
  background: transparent;
  color: var(--ash);
  font: inherit;
  font-size: 0.85rem;
  padding: 0.55rem 0.95rem;
  cursor: pointer;
  transition: color 140ms var(--tap);
}

.strip button:last-child {
  border-right: 0;
}

.strip button:hover {
  color: var(--bone);
}

.strip button[aria-pressed="true"] {
  color: var(--void);
  background: var(--live);
  font-weight: 700;
  transition: background 400ms var(--enter);
}

.strip-note {
  margin: 0.85rem 0 0;
  font-size: 0.8rem;
  color: var(--ash);
}

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

.section {
  padding: 5.5rem 0;
  border-top: 1px solid var(--rule);
}

.eyebrow {
  margin: 0 0 1.5rem;
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ash);
}

h2 {
  margin: 0 0 1.25rem;
  font-size: clamp(1.35rem, 3.4vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.2;
  max-width: 26ch;
}

.prose {
  color: var(--ash);
  max-width: 62ch;
}

.prose p {
  margin: 0 0 1rem;
}

.prose strong {
  color: var(--bone);
  font-weight: 400;
}

/* ------------------------------------------------------------------- wall */

/*
  Twenty names, laid out as a wall rather than as cards. The six that run in a
  browser are buttons that play; the rest say what they are. The list doubles
  as the catalogue and the remote control.
*/
.wall {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  border-top: 1px solid var(--rule);
  border-left: 1px solid var(--rule);
  margin: 0;
  padding: 0;
}

.wall li {
  list-style: none;
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}

.wall button,
.wall span.cell {
  display: block;
  width: 100%;
  height: 100%;
  text-align: left;
  border: 0;
  background: transparent;
  color: var(--bone);
  font: inherit;
  padding: 0.9rem 1rem 1rem;
}

.wall button {
  cursor: pointer;
  transition: background 140ms var(--tap);
}

.wall button:hover {
  background: rgba(255, 255, 255, 0.045);
}

.wall .name {
  display: block;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.wall button .name::after {
  content: " \25B8";
  color: var(--live);
  transition: color 400ms var(--enter);
}

.wall .what {
  display: block;
  font-size: 0.78rem;
  color: var(--ash);
  line-height: 1.45;
  margin-top: 0.15rem;
}

/* ---------------------------------------------------------------- numbers */

/*
  The measurement table is the argument, so it is set as data and not as
  marketing: real numbers, the unit spelled out, and the row that undercuts the
  claim left in.
*/
.numbers {
  width: 100%;
  border-collapse: collapse;
  margin-top: 1.5rem;
  font-size: 0.88rem;
}

.numbers caption {
  text-align: left;
  color: var(--ash);
  font-size: 0.8rem;
  padding-bottom: 0.75rem;
  max-width: 62ch;
}

.numbers th,
.numbers td {
  text-align: right;
  padding: 0.55rem 0.9rem;
  border-bottom: 1px solid var(--rule);
  font-weight: 400;
}

.numbers th:first-child,
.numbers td:first-child {
  text-align: left;
  font-weight: 700;
}

.numbers thead th {
  color: var(--ash);
  font-size: 0.76rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 400;
}

.numbers .bar {
  display: block;
  height: 3px;
  background: var(--live);
  transition: background 400ms var(--enter);
}

.numbers .bar-cell {
  width: 30%;
  vertical-align: middle;
}

/* ------------------------------------------------------------------ steps */

.steps {
  display: grid;
  gap: 1.75rem;
  margin: 0;
  padding: 0;
}

.steps > div {
  display: grid;
  gap: 0.45rem;
}

.steps h3 {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 700;
}

.steps p {
  margin: 0;
  color: var(--ash);
  font-size: 0.88rem;
  max-width: 60ch;
}

/* ---------------------------------------------------------------- credits */

.credits {
  columns: 2;
  column-gap: 2.5rem;
  color: var(--ash);
  font-size: 0.85rem;
  margin: 0;
  padding: 0;
}

.credits li {
  list-style: none;
  break-inside: avoid;
  padding: 0.3rem 0;
}

.credits b {
  color: var(--bone);
  font-weight: 700;
}

/* ----------------------------------------------------------------- footer */

footer {
  border-top: 1px solid var(--rule);
  padding: 2.5rem 0 4rem;
  color: var(--ash);
  font-size: 0.82rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
  align-items: baseline;
}

footer .spacer {
  flex: 1;
}

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

@media (max-width: 640px) {
  .credits {
    columns: 1;
  }

  .section {
    padding: 4rem 0;
  }

  .command {
    width: 100%;
  }

  .numbers .bar-cell {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  .mark-shell::after {
    animation: none;
    opacity: 1;
  }
}
