/*
 * Copyright 2026 Mist Tecnologia LTDA. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Adapted from The Monospace Web
 *   Copyright (c) Oskar Wickstrom — MIT
 *   https://github.com/owickstrom/the-monospace-web
 *
 * The same design system the Airlock dashboard uses, reduced to what a
 * document needs: everything lands on a character grid, 1ch horizontally and
 * --line-height vertically. For a tool whose primary interface is a terminal,
 * that is the honest aesthetic, and it costs no framework and no build step —
 * this site is HTML and CSS, served as written.
 */

@font-face {
  font-family: "JetBrains Mono";
  src: url("jetbrains-mono-latin.woff2") format("woff2");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

:root {
  --font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --line-height: 1.2rem;
  --border-thickness: 2px;

  /* The fixed bar's height, named because three things must agree on it: the
     bar, the body's top padding, and the scroll offset for anchored headings.
     Two and a half lines is what fits a bordered button with air around it. */
  --topbar-height: calc(var(--line-height) * 2.5);

  --text-color: #000;
  --text-color-alt: #666;
  --background-color: #fff;
  --background-color-alt: #eee;

  /* The one accent, and it is used for one thing: the status notice. Never to
     decorate. 8.04:1 on white. */
  --color-danger: #a11212;

  --font-weight-normal: 500;
  --font-weight-medium: 600;
  --font-weight-bold: 800;

  font-family: var(--font-family);
  font-optical-sizing: auto;
  font-weight: var(--font-weight-normal);
  font-variant-numeric: tabular-nums lining-nums;
  font-size: 16px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --text-color: #fff;
    --text-color-alt: #aaa;
    --background-color: #000;
    --background-color-alt: #111;
    --color-danger: #e05252; /* 5.50:1 on black — selected, not flipped */
  }
}

* {
  box-sizing: border-box;
}

html {
  background: var(--background-color);
  color: var(--text-color);
}

body {
  margin: 0 auto;
  /* Top padding clears the fixed bar and its rule, then leaves a line of air.
     Derived from --topbar-height so changing the bar cannot leave the first
     paragraph tucked underneath it. */
  padding: calc(var(--topbar-height) + var(--border-thickness) + var(--line-height)) 2ch
    calc(var(--line-height) * 2);
  /* A document width, unlike the dashboard: prose past 80ch is hard to read. */
  max-width: 80ch;
  line-height: var(--line-height);
}

body > * + * {
  margin-top: var(--line-height);
}

h1,
h2,
h3 {
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height);
  margin: calc(var(--line-height) * 2) 0 var(--line-height);
  text-transform: uppercase;
}
h1 {
  font-size: 2rem;
  line-height: calc(var(--line-height) * 2);
}
h2 {
  font-size: 1rem;
}
h3 {
  font-size: 1rem;
  color: var(--text-color-alt);
}

p,
ul,
ol {
  margin: 0 0 var(--line-height);
}

a {
  color: var(--text-color);
  text-decoration-thickness: var(--border-thickness);
  text-underline-offset: 2px;
}
a:hover {
  background: var(--background-color-alt);
}

strong {
  font-weight: var(--font-weight-bold);
}

code {
  font-family: var(--font-family);
  font-weight: var(--font-weight-medium);
  background: var(--background-color-alt);
  padding: 0 0.5ch;
}

pre {
  border: var(--border-thickness) solid var(--text-color);
  padding: var(--line-height) 1ch;
  overflow-x: auto;
  margin: 0 0 var(--line-height);
}
pre code {
  background: none;
  padding: 0;
}

ul {
  list-style-type: square;
  padding-left: 2ch;
}
ol {
  padding-left: 3ch;
}
li {
  margin-bottom: calc(var(--line-height) / 2);
}

hr {
  border: none;
  height: var(--line-height);
  margin: calc(var(--line-height) * 1.5) 0;
  position: relative;
}
hr:after {
  content: "";
  position: absolute;
  top: calc(var(--line-height) / 2 - var(--border-thickness));
  left: 0;
  width: 100%;
  border-top: calc(var(--border-thickness) * 3) double var(--text-color);
}

table {
  border-collapse: collapse;
  width: 100%;
  margin-bottom: var(--line-height);
}
th,
td {
  padding: calc(var(--line-height) / 2) 1ch;
  text-align: left;
  vertical-align: top;
  line-height: var(--line-height);
}
thead th {
  text-transform: uppercase;
  font-weight: var(--font-weight-bold);
  border-bottom: calc(var(--border-thickness) * 2) double var(--text-color);
}
tbody tr + tr td {
  border-top: 1px solid var(--text-color-alt);
}

/* ---- Fixed top bar -------------------------------------------------------- */

/*
 * Full-bleed, but its contents align to the same 80ch column as the document,
 * so the wordmark sits directly above the <h1> rather than floating off at the
 * viewport edge.
 *
 * Its height is --topbar-height rather than whatever the tallest child happens
 * to measure, so the body padding and the anchor scroll offset below can be
 * derived from it instead of guessed at and left to drift.
 */
.topbar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 10;
  /* Opaque on purpose. A translucent bar over a character grid turns text into
     interference the moment anything scrolls under it. */
  background: var(--background-color);
  border-bottom: var(--border-thickness) solid var(--text-color);
}
.topbar-inner {
  display: flex;
  align-items: center;
  gap: 2ch;
  height: var(--topbar-height);
  max-width: 80ch;
  margin: 0 auto;
  padding: 0 2ch;
}
.topbar-mark {
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--text-color);
  /* Pushes everything after it to the right edge. */
  margin-right: auto;
}
.topbar-links {
  display: flex;
  gap: 2ch;
  margin: 0;
  padding: 0;
  list-style: none;
}
.topbar-links a {
  color: var(--text-color-alt);
  text-decoration: none;
  /* One word each, on one line. A nav that wraps turns a 2.5-line bar into a
     4-line one and shoves the whole page down with it. */
  white-space: nowrap;
}
.topbar-links a:hover {
  color: var(--text-color);
  text-decoration: underline;
}
.topbar-cta {
  border: var(--border-thickness) solid var(--text-color);
  /* Minus the border, so the button is exactly one line-height of content. */
  padding: 0 calc(1ch - var(--border-thickness));
  text-transform: uppercase;
  font-weight: var(--font-weight-medium);
  text-decoration: none;
  background: var(--text-color);
  color: var(--background-color);
  white-space: nowrap;
}
.topbar-cta:hover {
  background: var(--background-color);
  color: var(--text-color);
}
.topbar a:focus-visible {
  outline: 2px solid var(--text-color);
  outline-offset: 2px;
}

/*
 * Below roughly 60ch the wordmark, three links and the button stop fitting.
 * The links go and the button stays: the links are shortcuts to content a
 * scroll reaches anyway, and the button is the reason the bar exists.
 */
@media (max-width: 60ch) {
  .topbar-links {
    display: none;
  }
}

.topbar-back {
  color: var(--text-color-alt);
  text-decoration: none;
  white-space: nowrap;
}
.topbar-back:hover {
  color: var(--text-color);
  text-decoration: underline;
}

/*
 * Anchored headings must clear the fixed bar, or following a link leaves the
 * heading hidden underneath it and the section looks like it starts mid-
 * sentence. One extra line of air so it does not sit flush against the rule.
 */
:target {
  scroll-margin-top: calc(var(--topbar-height) + var(--border-thickness) + var(--line-height));
}

.masthead {
  border-bottom: var(--border-thickness) solid var(--text-color);
  padding-bottom: var(--line-height);
}
.masthead h1 {
  margin: 0;
}
.tagline {
  color: var(--text-color-alt);
}

/*
 * The status notice is the one place colour appears, and it is deliberately
 * near the top. Airlock is early, and a landing page that buries that would be
 * selling something the documentation contradicts.
 */
.status {
  border: var(--border-thickness) solid var(--color-danger);
  padding: var(--line-height) 1ch;
}
.status strong {
  color: var(--color-danger);
}

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

.cols {
  display: flex;
  flex-wrap: wrap;
  gap: 0 3ch;
}
.cols > * {
  flex: 1 1 30ch;
}

footer {
  border-top: var(--border-thickness) solid var(--text-color);
  padding-top: var(--line-height);
  color: var(--text-color-alt);
}

figure {
  margin: 0 0 var(--line-height);
}
figure pre {
  margin-bottom: calc(var(--line-height) / 2);
}
figcaption {
  color: var(--text-color-alt);
}

/* ---- The invite page ------------------------------------------------------ */

/*
 * One page, one job: the form is the content, so it sits in the middle of the
 * viewport rather than at the top of a document. Narrower than the document
 * width too — a form is a column of fields, not prose, and 80ch of empty input
 * reads as a mistake.
 */
body.standalone {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100vh;
  max-width: 64ch;
}

/*
 * The lede's call to action, which is all that is left on the home page now
 * that the form has a page of its own. Filled, because it is the same action
 * as the bar's button and the two should not disagree about how it looks.
 */
.lede-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2ch;
}
.button {
  border: var(--border-thickness) solid var(--text-color);
  padding: calc(var(--line-height) / 2 - var(--border-thickness)) calc(2ch - var(--border-thickness));
  text-transform: uppercase;
  font-weight: var(--font-weight-medium);
  text-decoration: none;
  background: var(--text-color);
  color: var(--background-color);
  white-space: nowrap;
}
.button:hover {
  background: var(--background-color);
  color: var(--text-color);
}
.button:active {
  transform: translate(2px, 2px);
}
.button:focus-visible {
  outline: 2px solid var(--text-color);
  outline-offset: 2px;
}

/* ---- Beta signup ---------------------------------------------------------- */

.cta {
  border: var(--border-thickness) solid var(--text-color);
  padding: var(--line-height) 1ch;
}
.cta h2 {
  margin-top: 0;
}
.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1ch;
}
.cta-row input {
  flex: 1 1 28ch;
}
.cta input,
.cta button {
  border: var(--border-thickness) solid var(--text-color);
  padding: calc(var(--line-height) / 2 - var(--border-thickness)) calc(1ch - var(--border-thickness));
  font: inherit;
  font-variant-numeric: inherit;
  height: calc(var(--line-height) * 2);
  background: var(--background-color);
  color: var(--text-color);
  line-height: normal;
  appearance: none;
  border-radius: 0;
}
.cta button {
  text-transform: uppercase;
  font-weight: var(--font-weight-medium);
  cursor: pointer;
}
.cta button:hover {
  background: var(--text-color);
  color: var(--background-color);
}
.cta button:active {
  transform: translate(2px, 2px);
}
.cta input:focus-visible,
.cta button:focus-visible {
  outline: 2px solid var(--text-color);
  outline-offset: 2px;
}
.cta label {
  display: block;
  text-transform: uppercase;
}

/*
 * Fields stack full-width rather than sitting beside the button. With four of
 * them a side-by-side row would wrap into a ragged grid at most widths, and a
 * stack reads as a single column of things to fill in — which is what it is.
 */
.cta input,
.cta textarea {
  display: block;
  width: 100%;
}
.cta form label + input,
.cta form label + textarea {
  margin-top: calc(var(--line-height) / 2);
}
.cta form input + label,
.cta form textarea + label {
  margin-top: var(--line-height);
}

/*
 * The submit is the one inverted control on the page. In a design system with
 * no accent colour, filled-versus-outlined is the only way to say "this is the
 * action" — so it is spent here and nowhere else, apart from the bar's copy of
 * the same button.
 */
.cta button[type="submit"] {
  width: 100%;
  margin-top: var(--line-height);
  background: var(--text-color);
  color: var(--background-color);
}
.cta button[type="submit"]:hover {
  background: var(--background-color);
  color: var(--text-color);
}
.cta button[type="submit"][disabled],
.cta button[type="submit"][disabled]:hover {
  background: var(--text-color);
  color: var(--background-color);
}
/* The note is about the form, not part of it, so it gets a line of its own. */
.cta form + p {
  margin-top: var(--line-height);
}

/*
 * The honeypot. Moved off-screen rather than hidden with display:none or the
 * hidden attribute, both of which a bot can cheaply detect and skip. Nothing
 * here is a layout decision; it exists to be invisible.
 */
.trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/*
 * The outcome, revealed after submit — a confirmation, or a message to send by
 * hand when the request never left. A rule rather than a nested box: it is the
 * same request, answered, not a separate offer.
 */
.fallback {
  margin-top: var(--line-height);
  padding-top: var(--line-height);
  border-top: var(--border-thickness) solid var(--text-color);
}
.cta textarea,
.fallback textarea {
  display: block;
  width: 100%;
  border: var(--border-thickness) solid var(--text-color);
  padding: calc(var(--line-height) / 2 - var(--border-thickness)) calc(1ch - var(--border-thickness));
  font: inherit;
  background: var(--background-color);
  color: var(--text-color);
  border-radius: 0;
  resize: vertical;
}
.cta textarea:focus-visible,
.fallback textarea:focus-visible {
  outline: 2px solid var(--text-color);
  outline-offset: 2px;
}
.cta button[disabled] {
  opacity: 0.6;
  cursor: default;
}
.cta button[disabled]:hover {
  background: var(--background-color);
  color: var(--text-color);
}

/* ---- Screenshot ----------------------------------------------------------- */

/*
 * The screenshot breaks out of the 80ch prose column. A dense table shrunk to
 * text width is unreadable, and an unreadable screenshot of a data-dense tool
 * argues against the tool.
 *
 * Sized from the body width rather than 100vw: vw includes the scrollbar, so
 * the usual centring trick overflows by ~15px and gives the page a horizontal
 * scrollbar it should never have.
 */
.shot {
  /* Three-way clamp: as wide as the prose plus a generous margin, never wider
     than the viewport less a scrollbar's worth, never absurd on an ultrawide. */
  width: min(calc(100% + 60ch), calc(100vw - 2rem), 1400px);
  margin: 0 auto var(--line-height);
  position: relative;
  left: 50%;
  transform: translateX(-50%);
}
.shot img {
  display: block;
  width: 100%;
  height: auto;
  border: var(--border-thickness) solid var(--text-color);
}

/*
 * Tables scroll inside their own box rather than widening the page. Monospace
 * columns have a hard minimum width, so on a narrow screen the table pushed the
 * document sideways — the one thing a page body must never do.
 */
.table-wrap {
  overflow-x: auto;
  margin-bottom: var(--line-height);
}
.table-wrap table {
  margin-bottom: 0;
}
