/*
  The page borrows the app's palette exactly: the same blue-black spine, the same indigo, the same
  Inter. Someone who lands here from a search and then installs should recognise the thing they
  installed. One variable font covers every weight used.
*/

@font-face {
  font-family: 'Inter';
  src: url('fonts/inter.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('fonts/mono.woff2') format('woff2-variations');
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: oklch(0.17 0.014 262);
  --bg-lift: oklch(0.21 0.016 262);
  --band: oklch(0.20 0.015 262);
  --line: oklch(0.30 0.017 262);
  --ink: oklch(0.94 0.006 262);
  --ink-dim: oklch(0.75 0.014 262);
  --accent: oklch(0.79 0.10 279);
  --accent-deep: oklch(0.55 0.17 274);

  --measure: 66ch;
  --gap: clamp(1rem, 3vw, 2rem);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Inter', system-ui, sans-serif;
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.65;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; display: block; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--ink); }

code {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 0.86em;
  background: oklch(0.26 0.016 262);
  border-radius: 5px;
  padding: 0.15em 0.4em;
  white-space: nowrap;
}

.wrap { width: min(100% - 2.5rem, 62rem); margin-inline: auto; }
.wrap-wide { width: min(100% - 1.5rem, 78rem); margin-inline: auto; }

h1, h2, h3 {
  line-height: 1.15;
  letter-spacing: -0.022em;
  text-wrap: balance;
  margin: 0;
}

p { text-wrap: pretty; }

/*
  Disclosure, first thing on the page.
  Stated plainly and once, in the page's own voice rather than as a warning strip: it is context a
  reader deserves before deciding to install, not a legal banner to dismiss.
*/
.disclosure {
  border-bottom: 1px solid oklch(0.46 0.09 274);
  /* A clear tonal step off the page, so the band reads as its own thing rather than as the
     top of the hero. Kept short of an alert colour: this is context, not a warning. */
  background: oklch(0.33 0.07 274);
  text-align: center;
}

.disclosure p {
  /* Narrower than the page's measure: centred text is harder to track across a long line. */
  width: min(100% - 2.5rem, 52rem);
  margin-inline: auto;
  padding-block: 1.15rem;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
  text-wrap: balance;
}

.disclosure strong,
.disclosure a { color: var(--accent); }

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

.hero {
  padding-top: clamp(3.5rem, 9vw, 6.5rem);
  padding-bottom: 0;
  text-align: center;
  /* A single soft pool of the accent behind the mark, rather than a gradient across the page. */
  background:
    radial-gradient(70rem 34rem at 50% -12rem, oklch(0.32 0.07 274 / 0.5), transparent 65%);
}

.mark {
  width: clamp(2.75rem, 6vw, 3.5rem);
  color: var(--accent);
  margin-inline: auto;
  margin-bottom: 1.5rem;
}

.hero h1 {
  font-size: clamp(2.25rem, 6.4vw, 4rem);
  font-weight: 700;
}

.lede {
  max-width: 42rem;
  margin: 1.1rem auto 0;
  color: var(--ink-dim);
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
}

.cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
  margin-top: 2rem;
}

.button {
  display: inline-block;
  padding: 0.7rem 1.5rem;
  border-radius: 9px;
  background: var(--accent-deep);
  color: oklch(0.98 0.005 274);
  font-weight: 600;
  text-decoration: none;
  border: 1px solid transparent;
  transition: transform 160ms var(--ease), background 160ms var(--ease);
}
.button:hover { background: oklch(0.60 0.17 274); color: oklch(0.99 0 0); transform: translateY(-1px); }
.button:active { transform: translateY(0); }

.button.ghost {
  background: transparent;
  border-color: var(--line);
  color: var(--ink);
}
.button.ghost:hover { background: var(--bg-lift); border-color: var(--accent); }

/* --------------------------------------------------------------- phones */

.shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--gap);
  align-items: end;
  margin-top: clamp(2.5rem, 6vw, 4rem);
  padding-bottom: clamp(3rem, 7vw, 5rem);
}

/*
  Natural aspect, never cropped. A fixed height with object-fit would clip the app's own content,
  which is the thing the screenshot exists to show.
*/
.phone {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: 22px;
  padding: 6px;
  background: var(--bg-lift);
  overflow: hidden;
}
.phone img { border-radius: 16px; }
.phone.lift { transform: translateY(-1.75rem); }

.phone figcaption {
  padding: 0.7rem 0.5rem 0.2rem;
  text-align: center;
  color: var(--ink-dim);
  font-size: 0.875rem;
}

@media (max-width: 620px) {
  .phone.lift { transform: none; }
  .shots > .phone:nth-child(3) { display: none; }
}

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

section { padding-block: clamp(3rem, 8vw, 5.5rem); }

section h2 {
  font-size: clamp(1.6rem, 3.4vw, 2.25rem);
  font-weight: 650;
  max-width: 22ch;
}

.intro {
  max-width: var(--measure);
  margin-top: 0.9rem;
  color: var(--ink-dim);
}

.aside {
  max-width: var(--measure);
  margin-top: 2rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--line);
  color: var(--ink-dim);
  font-size: 0.95rem;
}

.band { background: var(--band); border-block: 1px solid var(--line); }

/* ------------------------------------------------------------------ demo */

/*
  A video, not an animated GIF. The same eight seconds costs a fraction as much to send and can be
  paused, and the codec handles a screen recording of text far better than a palette of 256 colours.
  Muted, looping and inline so it plays without asking and without hijacking the page.
*/
.demo {
  width: min(100%, 66rem);
  margin: 2.25rem auto 0;
}

.demo video {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--bg-lift);
}

.demo figcaption {
  margin-top: 0.75rem;
  text-align: center;
  color: var(--ink-dim);
  font-size: 0.9rem;
}

/*
  A control shows up only for someone who asked for less motion, since for everyone else the loop
  needs no interaction. Autoplay cannot be undone from CSS, so the script at the end of the page does
  the pausing and adds this class.
*/
.demo video.paused-for-motion { cursor: pointer; }

/* ---------------------------------------------------------------- lists */

/*
  Two columns exactly, not auto-fit. Rows in adjacent columns wrap to different heights, so any
  vertical rule between them reads as broken; the horizontal rules carry the structure instead.
*/
.matrix {
  margin: 2.25rem 0 0;
  display: grid;
  grid-template-columns: 1fr;
  column-gap: clamp(1.5rem, 4vw, 3.5rem);
  border-top: 1px solid var(--line);
}

@media (min-width: 56rem) {
  .matrix { grid-template-columns: 1fr 1fr; }
}

.matrix > div {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.15rem;
  padding: 0.8rem 0;
  border-bottom: 1px solid var(--line);
}

/* Once there is room, the label sits beside its value rather than above it. */
@media (min-width: 30rem) {
  .matrix > div {
    grid-template-columns: 7rem 1fr;
    gap: 1.25rem;
    align-items: baseline;
  }
}

.matrix dt { font-weight: 600; }
.matrix dd { margin: 0; color: var(--ink-dim); }

.pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--gap);
  margin-top: 2.75rem;
}

/*
  A genuine sequence, so it is numbered. The rungs happen in order and the order is the content.
*/
.ladder {
  list-style: none;
  counter-reset: rung;
  padding: 0;
  margin: 2.25rem 0 0;
  display: grid;
  gap: 1.75rem;
}

.ladder li {
  counter-increment: rung;
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  /* Column gap only. The heading and the paragraph sit on separate grid rows, so a row gap here
     would open a hole between a heading and the text it introduces. */
  gap: 0 1rem;
  align-items: start;
}

.ladder li::before {
  content: counter(rung);
  display: grid;
  place-items: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  border: 1px solid var(--line);
  color: var(--accent);
  font-size: 0.9rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.ladder h3 { grid-column: 2; font-size: 1.0625rem; font-weight: 650; }
.ladder p { grid-column: 2; margin: 0.35rem 0 0; color: var(--ink-dim); }
.ladder code { display: inline-block; margin-top: 0.5rem; }

/*
  Side by side once there is room, so the section is not one narrow column in a wide band. In three
  columns the marker moves above the heading: kept beside it, it eats a third of an already narrow
  column and the prose wraps every four words.
*/
@media (min-width: 56rem) {
  .ladder { grid-template-columns: repeat(3, 1fr); gap: 2.5rem; }
  /* Without this the stretched grid item spreads its slack between the rows, so the three
     headings land at three different heights. */
  .ladder li { grid-template-columns: 1fr; gap: 0.7rem; align-content: start; }
  .ladder h3,
  .ladder p { grid-column: 1; }
}


/* ---------------------------------------------------------------- split */

.split {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.65fr);
  gap: clamp(1.5rem, 5vw, 4rem);
  align-items: start;
}
.split p { max-width: var(--measure); color: var(--ink-dim); }
.split h2 + p { margin-top: 1rem; }

@media (max-width: 52rem) {
  .split { grid-template-columns: 1fr; }
  .split .phone { max-width: 20rem; }
}

/* -------------------------------------------------------------- install */

.install {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 15rem);
  gap: clamp(1.5rem, 5vw, 3.5rem);
  align-items: center;
}
.install p { max-width: 38rem; color: var(--ink-dim); margin-top: 1rem; }
.install strong { color: var(--ink); }

.qr {
  width: 100%;
  border-radius: 14px;
  border: 1px solid var(--line);
}

@media (max-width: 46rem) {
  .install { grid-template-columns: 1fr; justify-items: start; }
  .qr { max-width: 15rem; }
}

.fineprint { font-size: 0.875rem; color: var(--ink-dim); }

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

footer {
  border-top: 1px solid var(--line);
  padding-block: 2.5rem 3.5rem;
}
footer p { max-width: var(--measure); color: var(--ink-dim); font-size: 0.9375rem; }
footer .fineprint { margin-top: 1rem; }

/* ------------------------------------------------------------- a11y */

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  .button:hover { transform: none; }
}
