/* The site is dark everywhere, so the light can show in every part. Wine marks the letters Typeet adds. */
:root {
  color-scheme: dark;
  --canvas: #000;
  --raised: #0b0b0d;
  --surface: rgb(255 255 255 / 0.035);
  --line: rgb(255 255 255 / 0.09);
  --ink: #ededef;
  --muted: #9a9aa2;
  --faint: #66666e;
  --wine: #e0607c;
  --ring: 0 0 0 1px var(--line);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif;
  --serif: ui-serif, "New York", "Iowan Old Style", Charter, Georgia, serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace;
  --ease: cubic-bezier(0.2, 0, 0, 1);
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --outline: oklch(1 0 0 / 0.1);
  /* The light's colors, red to violet, as in prism.js's rainbow. */
  --spectrum: #ff1f38, #ff7314, #ffdb29, #38f261, #1accff, #3852ff, #9e33ff;
  /* How far things move and blur when they appear. Reduced Motion sets both to 0 and keeps the fade. */
  --rise: 10px;
  --soft: 4px;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --rise: 0px;
    --soft: 0px;
  }
}

/* Increase Contrast: stronger text and lines. */
@media (prefers-contrast: more) {
  :root {
    --line: rgb(255 255 255 / 0.25);
    --muted: #c4c4ca;
    --faint: #9a9aa2;
    --wine: #f08ba1;
  }
}

* {
  box-sizing: border-box;
  margin: 0;
}

html {
  overflow-x: clip;
}

body {
  background: var(--canvas);
  color: var(--ink);
  font: 15px/1.5 var(--font);
  -webkit-font-smoothing: antialiased;
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 24px;
}

h1,
h2 {
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

p {
  text-wrap: pretty;
}

a {
  color: inherit;
  text-underline-offset: 3px;
  text-decoration-color: var(--faint);
}

/* Selected text takes the wine of the letters Typeet adds, not the system blue. */
::selection {
  background: rgb(224 96 124 / 0.38);
  color: #fff;
}

mark {
  background: none;
  color: var(--wine);
}

.muted {
  color: var(--muted);
}

.small {
  font-size: 13px;
}

.button {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 14px;
  border-radius: 8px;
  background: var(--ink);
  color: var(--canvas);
  font-weight: 500;
  font-size: 14px;
  text-decoration: none;
  white-space: nowrap;
  transition-property: transform, opacity;
  transition-duration: 120ms;
  transition-timing-function: var(--ease);
}

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

.button.large {
  height: 44px;
  padding: 0 22px;
  font-size: 15px;
  border-radius: 10px;
}

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

/* Flags from flag-icons (MIT), 4:3. The outline keeps white edges visible on white. */
.flag {
  display: block;
  flex: none;
  width: 24px;
  height: 18px;
  border-radius: 3px;
  object-fit: cover;
  outline: 1px solid var(--outline);
  outline-offset: -1px;
}

header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 0;
}

/* The first view: always dark, full width, with the light drawn behind it (prism.js). */
.stage {
  position: relative;
  isolation: isolate;
  margin-inline: calc(50% - 50vw);
  padding-inline: calc(50vw - 50%);
  background: var(--canvas);
  color: var(--ink);
  color-scheme: dark;
}

.stage .light {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  /* The light reaches 400px below the stage, behind the numbers, so the rainbow carries on toward the
     harp. It fades out slowly, so no color stops at a hard edge. */
  height: calc(100% + 400px);
  opacity: 0;
  transition: opacity 1200ms ease;
  -webkit-mask-image: linear-gradient(to bottom, black 60%, transparent);
  mask-image: linear-gradient(to bottom, black 60%, transparent);
}

.stage .light.lit {
  opacity: 1;
}

.stage .button {
  background: var(--ink);
  color: var(--canvas);
}

.brand {
  display: flex;
  color: var(--ink);
  text-decoration: none;
}

/* The logo, set in type: bold "type", a text cursor, light "et". Geist, cut down to the logo's
   letters with: pyftsubset scripts/fonts/Geist-Variable.ttf --text=typeet --layout-features=kern
   --flavor=woff2. Under the pointer the weights swap: "type" goes light and "et" goes bold. */
@font-face {
  font-family: "Typeet Logo";
  src: url("/fonts/geist-logo.woff2") format("woff2");
  font-weight: 100 900;
  font-display: block;
}

.brandmark {
  display: inline-flex;
  align-items: baseline;
  font: 700 20px/1 "Typeet Logo", sans-serif;
  white-space: nowrap;
}

.brandmark .type {
  letter-spacing: -0.035em;
}

.brandmark .et {
  font-weight: 300;
  letter-spacing: -0.02em;
}

.brandmark .type,
.brandmark .et {
  transition: font-weight 380ms var(--ease-out);
}

.brandmark .bar {
  /* Down to the y and p, and as far above the t as below the baseline (make-icon.swift). */
  align-self: baseline;
  width: 0.09em;
  height: 0.96em;
  /* The same clear space on both sides of the ink (make-icon.swift prints these). */
  margin: 0 0.064em 0 0.108em;
  border-radius: 0.045em;
  background: currentColor;
  transform: translateY(0.15em);
}

@media (hover: hover) and (pointer: fine) {
  a:hover > .brandmark .type,
  .brandmark:hover .type {
    font-weight: 300;
  }

  a:hover > .brandmark .et,
  .brandmark:hover .et {
    font-weight: 700;
  }
}

@media (prefers-reduced-motion: reduce) {
  .brandmark .type,
  .brandmark .et {
    transition: none;
  }
}

header nav {
  display: flex;
  align-items: center;
  gap: 18px;
}

.quiet-link {
  color: var(--muted);
  font-size: 14px;
  text-decoration: none;
  transition: color 150ms ease;
}

/* The first view comes in once, top to bottom. */
.hero > * {
  animation: enter 700ms var(--ease-out) backwards;
}

.hero > :nth-child(2) {
  animation-delay: 80ms;
}

.hero > :nth-child(3) {
  animation-delay: 160ms;
}

.hero > :nth-child(4) {
  animation-delay: 240ms;
}

.hero > :nth-child(5) {
  animation-delay: 320ms;
}

@keyframes enter {
  from {
    opacity: 0;
    transform: translateY(var(--rise));
    filter: blur(var(--soft));
  }
}

.hero {
  position: relative;
  padding: 104px 0 88px;
  text-align: center;
}

/* Where vgpu's prism stands: near the left edge of the screen, so its rainbow flows right through
   the window. */
.prism-slot {
  position: absolute;
  top: 40px;
  left: calc((100% - 100vw) / 2 + 2vw);
  width: clamp(260px, 27vw, 460px);
  height: clamp(280px, 30vw, 500px);
  pointer-events: none;
}

@media (max-width: 640px) {
  /* A phone swipes through one row of large flags (FlagWheel) in place of the two rows of small ones. */
  .hero .flags {
    display: none;
  }

  .hero .flag-wheel {
    display: flex;
    gap: 14px;
    margin: 28px -16px 0;
    padding: 10px 0;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 22%, #000 78%, transparent);
    mask-image: linear-gradient(to right, transparent, #000 22%, #000 78%, transparent);
  }

  .flag-wheel::-webkit-scrollbar {
    display: none;
  }

  .flag-wheel button {
    flex: none;
    display: grid;
    place-items: center;
    width: 52px;
    height: 44px;
    padding: 0;
    border: 0;
    background: none;
    scroll-snap-align: center;
    opacity: 0.45;
    transition-property: opacity, scale;
    transition-duration: 150ms;
    transition-timing-function: var(--ease-out);
  }

  .flag-wheel button[data-chosen] {
    opacity: 1;
    scale: 1.25;
  }

  .flag-wheel .flag {
    width: 44px;
    height: 33px;
    border-radius: 6px;
  }

  .hero .flag-wheel-name {
    display: block;
    margin-top: 6px;
    color: var(--ink);
    font: 400 18px/1.3 var(--serif);
    animation: enter 320ms var(--ease-out);
  }

  .prism-slot {
    top: 0;
    width: 200px;
    height: 220px;
  }
}

h1 {
  font-size: clamp(36px, 6.6vw, 76px);
  line-height: 1.04;
  letter-spacing: -0.02em;
}

/* The headline over the light: a soft dark halo, so the rainbow never runs through its letters. */
.hero h1 {
  text-shadow: 0 0 40px rgb(0 0 0 / 0.9), 0 0 12px rgb(0 0 0 / 0.7);
}

.lead {
  max-width: 680px;
  margin: 24px auto 0;
  line-height: 1.55;
  /* A dark halo keeps it readable where the rainbow passes behind it. */
  text-shadow: 0 0 24px #000, 0 0 10px #000, 0 0 3px #000;
  color: rgb(242 242 242 / 0.82);
  font-size: 18px;
}

/* The language picker under the window: big flags in one row. */
.flags {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  /* One row of 19 on a wide screen: as wide as the screen allows, past the text column. */
  margin: 36px calc(50% - 50vw + 16px) 0;
}

.flags [role="radio"] {
  position: relative;
  display: grid;
  place-items: center;
  width: 46px;
  height: 38px;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: none;
  cursor: pointer;
  opacity: 0.55;
  filter: saturate(0.7);
  transition-property: opacity, filter, transform;
  transition-duration: 150ms;
  transition-timing-function: var(--ease);
}

.flags [role="radio"]:active {
  transform: scale(0.94);
}

.flags .flag {
  width: 30px;
  height: 22px;
  border-radius: 4px;
}

.flags [role="radio"][aria-checked="true"] {
  opacity: 1;
  filter: none;
}

/* The chosen flag's mark, and the softer layer that glides to the flag under the pointer. */
.flags .pill,
.flags .glide {
  position: absolute;
  top: 0;
  left: 0;
  width: 46px;
  height: 38px;
  border-radius: 10px;
  pointer-events: none;
}

.flags .pill {
  background: rgb(255 255 255 / 0.12);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.12);
}

.flags .glide {
  background: rgb(255 255 255 / 0.06);
  opacity: 0;
  transition:
    transform 220ms var(--ease-out),
    opacity 150ms ease;
}

.flags .glide.on {
  opacity: 1;
}

/* The demo: a text field with the focus, as in any app: set into the page, with its border and a
   soft focus ring. The light enters it white and leaves it in colors. */
.window {
  max-width: 880px;
  margin: 72px auto 0;
  border-radius: 12px;
  background: rgb(12 12 14 / 0.78);
  -webkit-backdrop-filter: blur(18px) saturate(1.2);
  backdrop-filter: blur(18px) saturate(1.2);
  box-shadow:
    0 0 0 1px rgb(255 255 255 / 0.18),
    0 0 0 4px rgb(255 255 255 / 0.05),
    inset 0 2px 6px rgb(0 0 0 / 0.45),
    0 30px 80px -24px rgb(0 0 0 / 0.8);
  text-align: left;
}

.window .line {
  /* Every sample stays on one line: the type shrinks with the field, and for a long sample
     (motion.js fitLine). */
  font: clamp(18px, 2.9vw, 26px) / 1.45 var(--serif);
  min-height: calc(1.45em + 48px);
  white-space: nowrap;
  padding: 24px 28px;
}

/* Each typed letter resolves out of a soft blur (Beautiful UI's StreamText). */
.window .ch {
  animation: appear 240ms var(--ease-out) backwards;
}

@keyframes appear {
  from {
    opacity: 0.15;
    filter: blur(3px);
  }
}

/* A fixed letter: the typed one rises away as the right one settles in its place. */
.window mark {
  position: relative;
  display: inline-block;
}

.window mark > span {
  display: inline-block;
  animation: arrive 380ms var(--ease-out) backwards;
}

.window mark::before {
  content: attr(data-old);
  position: absolute;
  inset: 0 auto auto 0;
  color: var(--ink);
  opacity: 0;
  animation: leave 380ms var(--ease-out);
}

@keyframes arrive {
  from {
    opacity: 0;
    transform: translateY(0.3em);
    filter: blur(3px);
  }
}

@keyframes leave {
  from {
    opacity: 1;
    transform: none;
    filter: none;
  }
  to {
    opacity: 0;
    transform: translateY(-0.4em);
    filter: blur(3px);
  }
}

/* A fixed word gets the app's wine underline: it draws in, stays a moment, then fades. */
.window .fixed {
  position: relative;
}

.window .fixed::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.06em;
  height: 2px;
  border-radius: 1px;
  background: var(--wine);
  transform-origin: left;
  opacity: 0;
  animation: underline 1600ms var(--ease-out);
}

@keyframes underline {
  0% {
    opacity: 0.9;
    transform: scaleX(0);
  }
  20%,
  75% {
    opacity: 0.9;
    transform: scaleX(1);
  }
  100% {
    opacity: 0;
    transform: scaleX(1);
  }
}

/* Between sentences the text is selected, as with a drag across it, and then deleted. The selection
   has the page's wine, and the caret hides while it shows, as in a macOS text field. */
.window .text {
  border-radius: 2px;
  background: linear-gradient(rgb(224 96 124 / 0.38), rgb(224 96 124 / 0.38)) no-repeat left / 0% 100%;
  transition: background-size 160ms var(--ease-out);
}

.window .selected .text {
  background-size: 100% 100%;
}

.window .selected .caret {
  visibility: hidden;
}

/* The caret holds still while typing and blinks while it waits. */
.caret {
  display: inline-block;
  width: 2px;
  height: 1.05em;
  margin-left: 1px;
  border-radius: 1px;
  vertical-align: -0.15em;
  background: var(--ink);
  animation: blink 1s step-end infinite;
}

.caret.typing {
  animation: none;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}

/* Icons: filled system logos, and Hugeicons strokes for the rest. None of them moves. */
.icon {
  flex: none;
  width: 1.25em;
  height: 1.25em;
}

/* The download: the visitor's system first, the others right under it. */
.actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  margin-top: 64px;
}

.actions .button {
  margin-bottom: 8px;
}

.button.primary {
  gap: 10px;
  height: 50px;
  padding: 0 24px 0 20px;
  border-radius: 13px;
  font-size: 15.5px;
  transition-property: transform, box-shadow, opacity;
  transition-duration: 200ms;
}

.button.primary .icon {
  width: 20px;
  height: 20px;
}

/* Under the button: the other systems, as quiet links. */
.also {
  display: flex;
  align-items: center;
  gap: 14px;
  color: var(--faint);
  font-size: 13.5px;
}

.platform {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  text-decoration: none;
  transition: color 150ms ease;
}

.platform .icon {
  width: 14px;
  height: 14px;
}

/* The numbers, for the chosen language or the one under the pointer. Digits roll to new values. */
.numbers {
  position: relative;
  padding: 40px 0 112px;
  text-align: center;
}

/* The thread from the chosen string's flag to its book, as wide as the harp: in the string's color,
   with a soft glow. It fades out over the shelf's title and in again under it, as if it passed behind. */
.thread {
  position: absolute;
  top: 0;
  left: calc(50% - 50vw);
  width: 100vw;
  height: 100%;
  pointer-events: none;
  filter: drop-shadow(0 0 3px var(--hue)) drop-shadow(0 0 10px var(--hue));
  transition: --hue 320ms var(--ease-out);
  mask-image: linear-gradient(#000 calc(var(--above) - 14px), transparent var(--above), transparent var(--below), #000 calc(var(--below) + 10px));
}

/* A typed color, so the glow and the line change color together, not the line alone. */
@property --hue {
  syntax: "<color>";
  inherits: true;
  initial-value: #fff;
}

.thread stop {
  stop-color: var(--hue);
}

.thread path {
  fill: none;
  stroke: url(#thread-fade);
  stroke-width: 2;
  stroke-linecap: round;
}

/* The headings over the numbers and over the shelf. */
.numbers-title {
  margin-top: 0;
  font-size: clamp(30px, 3.4vw, 44px);
  letter-spacing: -0.02em;
}

.shelf-title {
  margin-top: 96px;
}

/* The books on a shelf, spine out. Each is a box in 3D, a cover and a spine: closed, it is turned so
   the spine faces out; open, it turns to show the cover, with the spine still in sight. The books after
   the open one slide aside by the cover's width: they move, the row keeps its size. */
.shelf {
  --cover: 156px;
  --height: 232px;
  --aside: calc(var(--cover) * 0.94 - 6px);
  display: flex;
  justify-content: safe center;
  align-items: flex-end;
  gap: 4px;
  margin-top: 44px;
  padding: 16px var(--aside) 12px 0;
  /* The shelf board under the books: a lit front edge on a dark board. */
  background: linear-gradient(to bottom, transparent calc(100% - 12px), rgb(255 255 255 / 0.1) calc(100% - 12px) calc(100% - 11px), #121214 calc(100% - 11px));
  perspective: 1400px;
  overflow-x: auto;
  scrollbar-width: none;
}

.book {
  position: relative;
  flex: none;
  width: var(--spine);
  height: calc(var(--height) - var(--dip));
  border-radius: 3px;
  color: #fff;
  text-align: left;
  text-decoration: none;
  transition: translate 320ms var(--ease-in-out);
}

.book[data-after] {
  translate: var(--aside) 0;
}

.book-box {
  position: absolute;
  inset: 0 auto 0 calc(var(--spine) / 2);
  width: var(--cover);
  transform-style: preserve-3d;
  transform-origin: 0 50%;
  transform: rotateY(90deg);
  transition:
    transform 320ms var(--ease-in-out),
    scale 160ms var(--ease-out);
}

.book[data-open] .book-box {
  transform: rotateY(20deg);
}

.book:active .book-box {
  scale: 0.98;
}

.book-cover,
.book-spine {
  position: absolute;
  top: 0;
  height: 100%;
  backface-visibility: hidden;
  border-radius: 2px;
}

.book-cover {
  left: 0;
  width: 100%;
  background: var(--color);
  box-shadow: 0 18px 28px -14px rgb(0 0 0 / 0.9);
  transform: translateZ(calc(var(--spine) / 2));
}

.book-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

/* The fold by the spine and a fine edge, over the cover. */
.book-cover::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow:
    inset 4px 0 0 rgb(0 0 0 / 0.25),
    inset 0 0 0 1px rgb(255 255 255 / 0.12);
  pointer-events: none;
}

/* A cloth spine in the cover's color: rounded by light from the left, with a band at the head and foot. */
.book-spine {
  left: calc(var(--spine) / -2);
  width: var(--spine);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 22px 0 20px;
  background:
    linear-gradient(to bottom, transparent 11px, rgb(255 255 255 / 0.22) 11px 12px, transparent 12px calc(100% - 12px), rgb(255 255 255 / 0.22) calc(100% - 12px) calc(100% - 11px), transparent calc(100% - 11px)),
    linear-gradient(90deg, rgb(0 0 0 / 0.35), rgb(255 255 255 / 0.08) 35%, transparent 60%, rgb(0 0 0 / 0.4)),
    var(--color);
  color: rgb(255 255 255 / 0.92);
  transform: rotateY(-90deg);
}

.book-spine cite {
  overflow: hidden;
  max-height: 100%;
  font: 400 13px/1 var(--serif);
  text-overflow: ellipsis;
  white-space: nowrap;
  writing-mode: vertical-rl;
}

/* The open book's title, author and score, under the shelf. */
.shelf-caption {
  margin-top: 18px;
  color: var(--muted);
  font-size: 15px;
  animation: enter 320ms var(--ease-out);
}

.shelf-caption cite {
  color: var(--ink);
  font-style: italic;
}

.shelf-caption strong {
  color: var(--ink);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
  .book,
  .book-box {
    transition: none;
  }
}

/* The numbers in a frame of fine lines, as the facts below them. */
.stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-top: 40px;
  border-block: 1px solid var(--line);
}

.stats > div {
  padding: 32px 16px 34px;
}

.stats > div + div {
  border-left: 1px solid var(--line);
}

.stats strong {
  display: block;
  font: 400 clamp(32px, 5vw, 56px) / 1.15 var(--serif);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

.stats strong > span {
  display: inline-block;
  height: 1.15em;
  vertical-align: top;
}

.digit {
  overflow: hidden;
}

.strip {
  display: flex;
  flex-direction: column;
  transition: transform 700ms var(--ease-out);
}

.strip > span {
  height: 1.15em;
}

.stats > div > span {
  display: block;
  margin-top: 6px;
  color: var(--muted);
  font-size: 14px;
  text-wrap: pretty;
}

/* The harp: a curtain of light strings, one per language over its flag, wider than the text column.
   The pointer plucks them; the canvas is opaque black, as the page. */
/* The curtain runs from edge to edge of the screen; the strings and flags keep a 1240px row. */
.harp {
  position: relative;
  width: 100vw;
  margin: 96px 0 0 calc(50% - 50vw);
}

.harp-strings {
  height: 420px;
  touch-action: pan-y;
  cursor: crosshair;
}

.harp-strings canvas {
  display: block;
  width: 100%;
  height: 100%;
  /* The curtain fades out at its sides instead of stopping at the canvas edge. */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
}

.harp-flags {
  display: grid;
  grid-template-columns: repeat(19, minmax(0, 1fr));
  width: min(100%, 1240px);
  margin: 6px auto 0;
}

.harp-flags [role="radio"] {
  display: grid;
  place-items: center;
  height: 34px;
  border-radius: 8px;
  cursor: pointer;
  outline: none;
}

.harp-flags .flag {
  width: min(26px, 70%);
  height: auto;
  aspect-ratio: 4 / 3;
  border-radius: 3px;
  opacity: 0.5;
  filter: saturate(0.7);
  transition:
    opacity 200ms ease,
    filter 200ms ease,
    scale 200ms var(--ease-out);
}

.harp-flags [aria-checked="true"] .flag {
  opacity: 1;
  filter: none;
  scale: 1.15;
}

.harp-flags [role="radio"]:focus-visible {
  box-shadow: 0 0 0 2px rgb(255 255 255 / 0.6);
}

.harp-current {
  display: none;
}

.flag-wheel,
.flag-wheel-name {
  display: none;
}

/* Until the first click or key, the page is silent (browsers play nothing before one): this button
   says the harp has sound, and its click is that first one. */
.sound {
  position: absolute;
  top: 12px;
  right: max(16px, calc(50% - 620px + 16px));
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 12px 0 10px;
  border: 0;
  border-radius: 999px;
  background: rgb(0 0 0 / 0.5);
  box-shadow: 0 0 0 1px rgb(255 255 255 / 0.14);
  color: var(--muted);
  font: 13px var(--font);
  cursor: pointer;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  transition:
    color 150ms ease,
    scale 150ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .sound:hover {
    color: var(--ink);
  }
}

.sound:active {
  scale: 0.96;
}

.sound .icon {
  width: 16px;
  height: 16px;
}

.sound:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgb(255 255 255 / 0.6);
}



/* Three facts, each with its icon, in a frame of fine lines. */
.facts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-block: 1px solid var(--line);
}

.facts > div {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 340px;
  padding: 0 28px 44px;
  overflow: hidden;
}

.facts > div + div {
  border-left: 1px solid var(--line);
}

/* Each fact's icon, drawn large in light behind its title and running off the cell's edge. It glows in
   the fact's colors and fades out toward the text, and breathes slowly. */
.fact-light {
  position: absolute;
  top: -24px;
  left: 36%;
  width: 300px;
  height: 300px;
  opacity: 0.5;
  filter: drop-shadow(0 0 6px var(--glow-b)) drop-shadow(0 0 22px var(--glow-a));
  -webkit-mask-image: linear-gradient(to bottom, #000 35%, transparent 92%);
  mask-image: linear-gradient(to bottom, #000 35%, transparent 92%);
  animation: breathe 7s ease-in-out infinite alternate;
  pointer-events: none;
}

@keyframes breathe {
  to {
    opacity: 0.36;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fact-light {
    animation: none;
  }
}

/* A light that runs slowly around an edge: a short arc of colors on a hairline, and a soft halo of the
   same arc around it. The element sets --arc (color stops between 0deg and 180deg); a child
   .halo carries the blur, as a blur on the ring itself would be cut away by its own mask. CSS, not
   shaders: a few edges do not need WebGL contexts. */
@property --turn {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.edge {
  isolation: isolate;
}

.edge::before,
.edge > .halo::before {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -1;
  padding: var(--width, 1px);
  border-radius: inherit;
  background: conic-gradient(from var(--turn), transparent 0deg, var(--arc), transparent 180deg);
  mask:
    linear-gradient(#000 0 0) content-box exclude,
    linear-gradient(#000 0 0);
  animation: turn var(--period, 9s) linear infinite;
  pointer-events: none;
}

.edge > .halo {
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  opacity: var(--glow, 0.55);
  filter: blur(var(--blur, 12px));
  pointer-events: none;
}

.edge > .halo::before {
  --width: var(--halo-width, 4px);
}

@keyframes turn {
  to {
    --turn: 360deg;
  }
}

@media (prefers-reduced-motion: reduce) {
  .edge::before,
  .edge > .halo::before {
    animation: none;
  }
}

.facts h2 {
  position: relative;
  font-size: 21px;
}


/* The closing: the price, then one card per system, the visitor's first. */
.get {
  position: relative;
  margin: 160px 0;
  padding: 88px 40px 64px;
  border-radius: 28px;
  background: radial-gradient(80% 60% at 50% 0%, rgb(255 255 255 / 0.05), transparent 70%), var(--raised);
  box-shadow: var(--ring);
  text-align: center;
  scroll-margin-top: 24px;
  --arc: #ff1f38 30deg, #ffdb29 70deg, #38f261 105deg, #1accff 135deg, #9e33ff 165deg;
  --period: 16s;
  --blur: 18px;
  --glow: 0.45;
  --halo-width: 3px;
}

.get > * {
  position: relative;
  z-index: 1;
}

.get h2 {
  font-size: clamp(32px, 5vw, 48px);
  letter-spacing: -0.02em;
}

.offer {
  margin-top: 32px;
  color: var(--muted);
}

.offer strong {
  color: var(--ink);
  font: 400 56px/1 var(--serif);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.get > .muted {
  max-width: 600px;
  margin: 16px auto 0;
}

.systems {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  max-width: 760px;
  margin: 56px auto 0;
}

.system {
  display: grid;
  justify-items: start;
  gap: 4px;
  padding: 22px;
  border-radius: 18px;
  background: var(--surface);
  box-shadow: var(--ring);
  color: var(--ink);
  text-align: left;
  text-decoration: none;
  transition:
    scale 150ms var(--ease-out),
    background-color 200ms ease;
}

.system:active {
  scale: 0.96;
}

.system[data-mine] {
  background: rgb(255 255 255 / 0.06);
  box-shadow:
    0 0 0 1px rgb(255 255 255 / 0.4),
    0 18px 50px -20px rgb(255 255 255 / 0.25);
}

.system > .icon {
  width: 28px;
  height: 28px;
  margin-bottom: 12px;
}

.system-name {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 17px;
  font-weight: 500;
}

.system-get {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 16px;
  padding: 7px 12px 7px 10px;
  border-radius: 9px;
  background: var(--line);
  font-size: 13px;
  font-weight: 500;
}

.system[data-mine] .system-get {
  background: var(--ink);
  color: var(--canvas);
}

.system-get .icon {
  width: 16px;
  height: 16px;
}

.buy {
  margin-left: 4px;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: rgb(255 255 255 / 0.3);
  text-underline-offset: 4px;
  transition: text-decoration-color 150ms ease;
}

/* The footer: the light once more, rising from the bottom, under a large faint wordmark. */
footer {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  margin-inline: calc(50% - 50vw);
  padding: 96px calc(50vw - 50%) 40px;
  border-top: 1px solid var(--line);
}

/* Rays of the spectrum rising from below the page (GodRays in App.jsx), fading out upwards. */
.aurora {
  position: absolute !important;
  inset: 0;
  z-index: -1;
  opacity: 0.8;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 65%);
  mask-image: linear-gradient(to bottom, transparent, #000 65%);
}

.wordmark {
  display: block;
  width: clamp(300px, 60vw, 760px);
  height: auto;
  margin: 0 auto 40px;
  opacity: 0.2;
  -webkit-user-select: none;
  user-select: none;
}

/* The copyright, and the page's language as a quiet select with a globe. */
.footer-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* A flag's name, in Base UI's Tooltip: its own name, then the page language's. */
.tip {
  display: flex;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 8px;
  background: #161618;
  box-shadow:
    0 0 0 1px rgb(255 255 255 / 0.1),
    0 10px 30px -8px rgb(0 0 0 / 0.7);
  color: var(--ink);
  font: 13px/1.4 var(--font);
  white-space: nowrap;
  transform-origin: var(--transform-origin);
  transition:
    opacity 140ms var(--ease-out),
    scale 140ms var(--ease-out);
}

.tip span {
  color: var(--muted);
}

.tip[data-starting-style],
.tip[data-ending-style] {
  opacity: 0;
  scale: 0.96;
}

.tip[data-instant] {
  transition: none;
}

/* The page's language: Base UI's Select, with the names in a small menu over the page. */
.site-language {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 10px;
  border: 0;
  border-radius: 10px;
  background: rgb(255 255 255 / 0.04);
  box-shadow: var(--ring);
  color: var(--muted);
  font: 13px var(--font);
  cursor: pointer;
  transition: color 150ms ease;
}

.site-language .icon {
  width: 16px;
  height: 16px;
}

.site-language:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgb(255 255 255 / 0.5);
}

.site-language[data-popup-open] {
  color: var(--ink);
}

.site-language-arrows {
  display: flex;
}

.menu-positioner {
  z-index: 10;
  outline: none;
}

.menu {
  min-width: var(--anchor-width);
  padding: 4px;
  border-radius: 12px;
  background: #161618;
  box-shadow:
    0 0 0 1px rgb(255 255 255 / 0.1),
    0 16px 40px -8px rgb(0 0 0 / 0.7);
  transform-origin: var(--transform-origin);
  transition:
    opacity 150ms var(--ease-out),
    scale 150ms var(--ease-out);
}

.menu[data-starting-style],
.menu[data-ending-style] {
  opacity: 0;
  scale: 0.96;
}

.menu[data-side="none"] {
  transition: none;
}

.menu-list {
  max-height: min(var(--available-height), 360px);
  overflow-y: auto;
  scroll-padding-block: 4px;
  scrollbar-width: thin;
  scrollbar-color: rgb(255 255 255 / 0.2) transparent;
  outline: none;
}

.menu-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  height: 32px;
  padding: 0 8px 0 10px;
  border-radius: 8px;
  color: var(--ink);
  font-size: 13.5px;
  cursor: default;
  outline: none;
  user-select: none;
}

.menu-check {
  display: flex;
}

.menu-check .icon {
  width: 16px;
  height: 16px;
}

@media (max-width: 640px) {
  body {
    padding: 0 16px;
  }

  .hero {
    padding: 56px 0 64px;
  }

  .lead {
    font-size: 16px;
  }

  .window {
    margin-top: 48px;
  }

  .actions {
    margin-top: 48px;
  }

  .numbers {
    padding: 24px 0 72px;
  }

  /* Two rows, of ten and nine, on a phone. */
  .flags {
    gap: 3px;
    margin: 24px 0 0;
  }

  .flags [role="radio"],
  .flags .pill,
  .flags .glide {
    width: 31px;
    height: 28px;
    border-radius: 7px;
  }

  .flags .flag {
    width: 22px;
    height: 16px;
  }

  .window .line {
    min-height: calc(26px + 44px);
    font-size: 18px;
    padding: 22px 20px;
  }

  .stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .stats > div {
    padding: 22px 10px;
  }

  .stats > div:nth-child(3) {
    border-left: 0;
  }

  .stats > div:nth-child(n + 3) {
    border-top: 1px solid var(--line);
  }

  .get {
    margin: 104px 0;
    padding: 48px 18px 36px;
    border-radius: 22px;
  }

  .get h2 {
    font-size: 28px;
  }

  .numbers-title {
    font-size: 24px;
  }

  /* Two lines kept for the caption, so a longer title does not push the page down. */
  .shelf-caption {
    min-height: calc(2 * 1.5em);
    font-size: 14px;
    text-wrap: balance;
  }

  .shelf {
    --cover: 136px;
    --height: 204px;
    margin-inline: -16px;
    padding-inline: 16px;
  }

  .stats strong {
    font-size: 30px;
  }


  .harp {
    margin-top: 40px;
  }

  .harp-strings {
    height: 300px;
  }

  /* A phone shows one large flag for the string last touched; the row stays, unseen, to place the
     strings. */
  .harp-flags {
    height: 0;
    overflow: hidden;
    visibility: hidden;
  }

  .harp-current {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    margin-top: 18px;
    font: 400 22px/1 var(--serif);
    animation: enter 320ms var(--ease-out);
  }

  .harp-current .flag {
    width: 48px;
    height: 36px;
    border-radius: 6px;
  }

  /* Less light behind the headline and lead on a narrow screen, where they cross the rainbow. */
  .stage .light.lit {
    opacity: 0.7;
  }

  .harp-flags [role="radio"] {
    height: 26px;
  }



  .facts,
  .systems {
    grid-template-columns: 1fr;
  }

  .facts > div + div {
    border-left: 0;
    border-top: 1px solid var(--line);
  }

  .facts > div {
    min-height: 220px;
  }

  .fact-light {
    left: auto;
    right: -48px;
    width: 220px;
    height: 220px;
  }

  .systems {
    gap: 12px;
  }





}

/* The About page: one readable column. */
.prose {
  padding: 56px 0 72px;
}

.prose > p {
  max-width: 640px;
}

/* The title is the logo, and its cursor blinks as in a text field. */
.prose .title .brandmark {
  font-size: clamp(47px, 9vw, 76px);
}

.title .bar {
  animation: blink 1.06s step-end infinite;
}

@media (prefers-reduced-motion: reduce) {
  .title .bar {
    animation: none;
  }
}

.prose .lead {
  margin: 16px 0 0;
  max-width: none;
}

.prose h2 {
  margin: 40px 0 8px;
  font-size: 22px;
}

.prose p + p {
  margin-top: 8px;
}

/* The blog: a list of posts, and each post in the same readable column as About. */
.posts {
  display: grid;
  gap: 1px;
  max-width: 720px;
  margin: 32px 0 0;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--line);
  list-style: none;
}

.posts a {
  display: grid;
  gap: 4px;
  padding: 20px 22px;
  background: var(--canvas);
  color: var(--ink);
  text-decoration: none;
  transition: background-color 150ms var(--ease-out);
}

.posts time,
.eyebrow {
  color: var(--faint);
  font: 12px/1.4 var(--mono);
}

.posts b {
  font: 400 22px/1.25 var(--serif);
  text-wrap: balance;
}

.posts span {
  color: var(--muted);
  font-size: 14px;
  text-wrap: pretty;
}

.post {
  max-width: 680px;
}

.post .eyebrow a {
  color: inherit;
}

.post h1 {
  margin-top: 12px;
  font-size: clamp(32px, 5.6vw, 48px);
  line-height: 1.1;
  text-wrap: balance;
}

.post p,
.post li {
  font-size: 16px;
  line-height: 1.65;
  text-wrap: pretty;
}

.post p + p,
.post h2 + p {
  margin-top: 12px;
}

.post kbd {
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--surface);
  font: 0.86em var(--font);
  white-space: nowrap;
}

.post code {
  font: 0.9em var(--mono);
}

.try {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 40px;
  padding: 20px 22px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--raised);
}

.try p {
  max-width: 420px;
  margin: 0;
}

.try .button {
  background: var(--ink);
  color: var(--canvas);
}

/* What Typeet is built on, as a wall of tiles: each a mark or flags, its name, what it gives, its license. */
.wall {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  max-width: 820px;
  margin: 16px 0 12px;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--line);
  list-style: none;
}

.wall a {
  display: flex;
  flex-direction: column;
  gap: 4px;
  height: 100%;
  padding: 18px 18px 16px;
  background: var(--canvas);
  color: var(--ink);
  text-decoration: none;
  transition: background-color 150ms var(--ease-out);
}

.wall .name {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  font-weight: 600;
}

.wall .name > img {
  height: 18px;
  width: auto;
}

.mini-flags {
  display: flex;
  gap: 3px;
}

.mini-flags img {
  border-radius: 2px;
  outline: 1px solid var(--outline);
  outline-offset: -1px;
}

.wall .for {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
  text-wrap: pretty;
}

.wall .license {
  margin-top: auto;
  padding-top: 10px;
  color: var(--faint);
  font: 11px/1.4 var(--mono);
}

@media (hover: hover) and (pointer: fine) {
  .posts a:hover,
  .wall a:hover {
    background: var(--raised);
  }
}

@media (max-width: 720px) {
  .wall {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 420px) {
  .wall {
    grid-template-columns: 1fr;
  }
}

.prose > * {
  animation: enter 700ms var(--ease-out) backwards;
}

.prose > :nth-child(2) {
  animation-delay: 80ms;
}

.prose > :nth-child(n + 3) {
  animation-delay: 160ms;
}

/* Hover only where there is a real pointer: a tap must not leave a hover look behind. */
@media (hover: hover) and (pointer: fine) {
  .button:hover {
    opacity: 0.88;
  }

  .flags [role="radio"]:hover {
    opacity: 1;
    filter: none;
  }

  .button.primary:hover {
    opacity: 1;
    box-shadow: 0 10px 34px -10px rgb(255 255 255 / 0.4);
  }

  .platform:hover {
    color: var(--ink);
  }

  .menu-item[data-highlighted] {
    background: rgb(255 255 255 / 0.08);
  }

  .system:hover {
    background: rgb(255 255 255 / 0.06);
  }

  .buy:hover {
    text-decoration-color: var(--ink);
  }

  .site-language:hover,
  .quiet-link:hover {
    color: var(--ink);
  }
}

/* Reduced Motion: fades stay (--rise and --soft are 0); nothing moves or blinks. */
@media (prefers-reduced-motion: reduce) {

  .button:active {
    transform: none;
  }

  .caret {
    animation: none;
  }

  .window .fixed::after {
    animation-name: fade;
  }

  .flags [role="radio"]:active {
    transform: none;
  }

  .system:active {
    scale: none;
  }
}

@keyframes fade {
  0%,
  75% {
    opacity: 0.9;
  }
  100% {
    opacity: 0;
  }
}
