/*
 * Deskdex, the website.
 *
 * One stylesheet, hand written, no framework and no build step: the whole site is four
 * static files, which is the right size for a page whose job is to explain an app and
 * get out of the way.
 *
 * The palette, the radii and the type scale are the app's own (see client/src/styles
 * /index.css). That is deliberate. Somebody who reads this page and then opens the app
 * should not feel that they have gone somewhere else, and a marketing site with its own
 * look is the commonest way an independent project ends up feeling like two projects.
 *
 * Things this file does not do, for reasons that are not fashion:
 *   no gradients, no glass, no glow. The app shows people money and a page about it
 *     should read like an instrument rather than a product launch;
 *   no shadows. Depth is a 1px border, which is how the app's own panels do it;
 *   no transitions on hover. A page that animates when the cursor passes over it is a
 *     page that is performing rather than answering;
 *   no webfont. The system stack renders instantly and the first paint carries no
 *     flash of unstyled text, which matters more than a typeface.
 */

:root {
  --ink-950: #08090c;
  --ink-900: #0e1117;
  --ink-850: #151922;
  --ink-800: #1e232f;
  --ink-700: #303849;
  --ink-500: #78849c;
  --ink-400: #8c97ae;
  --ink-300: #aeb8cb;
  --ink-200: #e2e7f2;
  --ink-100: #f6f8ff;
  --accent: #6a98ff;
  --accent-dim: #8ab0ff;
  --gain: #4cc496;
  --line: rgba(255, 255, 255, 0.09);
  --radius: 10px;
  --wrap: 1080px;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
    sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}

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

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

body {
  margin: 0;
  background: var(--ink-950);
  color: var(--ink-300);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .skeleton {
    animation: none;
  }
}

/*
 * A figure that has arrived is in the bright ink, whatever the reader's motion setting.
 *
 * These two rules were inside the reduced-motion block above, which is a nesting mistake
 * rather than a decision: a number's colour has nothing to do with whether the reader
 * asked for less animation, and for everybody who had not asked, every figure on the
 * page rendered in the body ink instead of the heading ink.
 */
.figures .figure {
  color: var(--ink-100);
}

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

a {
  color: var(--accent);
  text-decoration: none;
}
a:hover,
a:focus-visible {
  color: var(--accent-dim);
  text-decoration: underline;
}
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

h1,
h2,
h3 {
  color: var(--ink-100);
  font-weight: 650;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0;
}
h1 {
  font-size: clamp(30px, 6vw, 46px);
}
h2 {
  font-size: clamp(23px, 3.4vw, 30px);
}
h3 {
  font-size: 18px;
  letter-spacing: -0.01em;
}
p {
  margin: 0;
}

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 20px;
}

/* The one small-caps label style, borrowed from the app, where it marks every panel. */
.label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-500);
}

.num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ the header */

/*
 * Solid, not frosted. A translucent blurred bar over scrolling content is the single
 * most recognisable piece of borrowed styling on the web right now, it costs a
 * compositor pass on every frame of every scroll, and the thing it is for — seeing that
 * there is content under the header — is not worth either. One ink, one hairline.
 */
header.top {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--ink-950);
  border-bottom: 1px solid var(--line);
}
.top .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 58px;
  gap: 16px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--ink-100);
  font-weight: 650;
  letter-spacing: -0.01em;
}
.brand:hover {
  text-decoration: none;
}
.brand img {
  width: 26px;
  height: 26px;
  border-radius: 6px;
}
.top nav {
  display: flex;
  align-items: center;
  gap: 18px;
  font-size: 15px;
}
.top nav a.quiet {
  color: var(--ink-400);
}
@media (max-width: 640px) {
  .top nav a.quiet {
    display: none;
  }
}

/* ------------------------------------------------------------------ buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 18px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
}
.btn-primary {
  background: var(--accent);
  color: #08090c;
}
.btn-primary:hover,
.btn-primary:focus-visible {
  background: var(--accent-dim);
  color: #08090c;
  text-decoration: none;
}
.btn-quiet {
  background: transparent;
  border-color: var(--ink-700);
  color: var(--ink-200);
}
.btn-quiet:hover,
.btn-quiet:focus-visible {
  border-color: var(--ink-500);
  color: var(--ink-100);
  text-decoration: none;
}

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

.hero {
  padding: 56px 0 8px;
}
.hero .cols {
  display: grid;
  /*
   * The words take slightly more than half and the screenshot column is sized to the
   * screenshot rather than to the grid, so the picture fills its side instead of sitting
   * in the middle of an empty one. `start` rather than `center`: with a short lead the
   * two columns are different heights and centring the picture left a band of nothing
   * under the buttons and another one over the caption.
   */
  grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  gap: 48px;
  align-items: start;
}
.hero p.lead {
  font-size: 19px;
  color: var(--ink-300);
  margin-top: 18px;
  /*
   * Two lines on a desktop and four on a phone, which is the budget.
   *
   * The eyetracking work on this is old and has not moved: about four fifths of viewing
   * time is spent above the fold, and the page has roughly ten seconds to say what it is
   * before the departure rate collapses. The first version of this paragraph was five
   * lines, which on a phone pushed the buttons and the screenshot — the two things that
   * prove any of it — off the first screen entirely.
   */
  max-width: 30em;
}
.hero .actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 26px;
}
.hero .asof {
  margin-top: 16px;
  font-size: 13px;
  color: var(--ink-500);
}
/* An inline link in the quiet ink, underlined so it is still obviously a link. */
a.quiet-link {
  color: var(--ink-400);
  text-decoration: underline;
  text-decoration-color: var(--ink-700);
  text-underline-offset: 2px;
}
a.quiet-link:hover,
a.quiet-link:focus-visible {
  color: var(--ink-200);
  text-decoration-color: var(--ink-500);
}
.shot {
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  background: var(--ink-900);
}
.shot.phone {
  max-width: 300px;
  margin-inline: auto;
}
/*
 * A screenshot of a whole phone screen is 1:1.7, and three of those down a page leave
 * columns of empty space beside the text they illustrate. `tall` crops them to a
 * consistent 4:5 from the top, which is the part of any of these screens that carries
 * the point, and keeps the rows the same shape as each other.
 */
.shot.tall img {
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: top center;
}
.shot.wide {
  max-width: 100%;
}
figure {
  margin: 0;
}
figcaption {
  font-size: 13px;
  color: var(--ink-500);
  margin-top: 10px;
}

@media (max-width: 860px) {
  .hero {
    padding-top: 32px;
  }
  .hero .cols {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }
  /* The screenshot is the proof, so it goes as close to the headline as the stack
     allows rather than after a screen of scrolling. */
  .hero .cols > figure {
    max-width: 320px;
  }
  /* Both buttons the same width once they are stacked. Two tap targets of different
     widths under each other read as a primary action and an afterthought, and the
     second one here is the one that shows somebody the product. */
  .hero .actions .btn {
    flex: 1 1 100%;
  }
}

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

.figures {
  margin: 48px 0 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 26px 0;
}
.figures ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 22px;
}
/*
 * `display` on a class selector beats the browser's own `[hidden] { display: none }`, so
 * setting `hidden` on this list did nothing and four skeleton boxes sat under the
 * failure note pulsing forever. Anything that can be hidden from script needs this.
 */
.figures ul[hidden] {
  display: none;
}
.figures .big {
  font-size: 28px;
  font-weight: 700;
  color: var(--ink-100);
  line-height: 1.1;
}
.figures .cap {
  font-size: 13px;
  color: var(--ink-500);
  margin-top: 4px;
}
.figures .note {
  font-size: 13px;
  color: var(--ink-500);
  margin-top: 18px;
  max-width: 60em;
}
@media (max-width: 720px) {
  .figures ul {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
  }
}

.skeleton {
  display: inline-block;
  height: 1em;
  width: 3.4em;
  border-radius: 4px;
  background: var(--ink-800);
  animation: pulse 1.4s ease-in-out infinite;
}
@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.45;
  }
}

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

section.band {
  padding: 62px 0;
  border-bottom: 1px solid var(--line);
}
/* The header is sticky, so an anchor has to leave room for it or the heading it jumped
   to is the one thing hidden behind the bar. */
section[id] {
  scroll-margin-top: 74px;
}
section.band > .wrap > .label {
  margin-bottom: 14px;
}
.rows {
  display: grid;
  gap: 54px;
  margin-top: 40px;
}
.row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 40px;
  align-items: start;
}
.row.flip > figure {
  order: -1;
}
.row h3 {
  margin-bottom: 10px;
}
.row p + p {
  margin-top: 12px;
}
.row .small {
  font-size: 15px;
  color: var(--ink-400);
}
@media (max-width: 860px) {
  .row,
  .row.flip {
    grid-template-columns: minmax(0, 1fr);
    gap: 22px;
  }
  .row.flip > figure {
    order: 0;
  }
}

/* A definition list for "this figure is made like this". Two columns on a wide screen,
   stacked on a phone, and no bullets: every line here is a claim, not an item. */
dl.rules {
  margin: 26px 0 0;
  display: grid;
  gap: 22px;
}
dl.rules > div {
  display: grid;
  grid-template-columns: 148px minmax(0, 1fr);
  gap: 20px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}
dl.rules dt {
  color: var(--ink-100);
  font-weight: 650;
  font-size: 16px;
}
dl.rules dd {
  margin: 0;
  font-size: 16px;
  color: var(--ink-400);
}
@media (max-width: 720px) {
  dl.rules > div {
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
  }
}

ul.plain {
  list-style: none;
  margin: 24px 0 0;
  padding: 0;
  display: grid;
  gap: 16px;
  max-width: 62em;
}
ul.plain li {
  padding-left: 18px;
  position: relative;
  color: var(--ink-400);
}
ul.plain li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.66em;
  width: 6px;
  height: 1px;
  background: var(--ink-700);
}
ul.plain b {
  color: var(--ink-200);
  font-weight: 650;
}

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

.install {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 22px;
  margin-top: 34px;
}
.install > div {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
  background: var(--ink-900);
}
.install h3 {
  font-size: 16px;
  margin-bottom: 12px;
}
.install ol {
  margin: 0;
  padding-left: 20px;
  font-size: 15px;
  color: var(--ink-400);
}
.install li + li {
  margin-top: 8px;
}
.install .here {
  border-color: var(--accent);
}
.install .here h3::after {
  content: " · you are on this";
  color: var(--accent);
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 0;
}
@media (max-width: 860px) {
  .install {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ------------------------------------------------------------------ closing + footer */

.closing {
  padding: 62px 0;
  text-align: center;
}
.closing p {
  margin: 16px auto 0;
  max-width: 40em;
  color: var(--ink-400);
}
.closing .actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 26px;
  flex-wrap: wrap;
}

footer.bottom {
  border-top: 1px solid var(--line);
  padding: 34px 0 54px;
  font-size: 14px;
  color: var(--ink-500);
}
footer.bottom .links {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  margin-bottom: 18px;
}
footer.bottom p + p {
  margin-top: 12px;
}
footer.bottom .fine {
  font-size: 13px;
  max-width: 62em;
}

/* ------------------------------------------------------------------ text pages */

article.page {
  padding: 46px 0 70px;
  max-width: 44em;
}
article.page h1 {
  font-size: clamp(27px, 4.4vw, 36px);
}
article.page .updated {
  font-size: 14px;
  color: var(--ink-500);
  margin-top: 10px;
}
article.page h2 {
  font-size: 20px;
  margin-top: 38px;
}
article.page p,
article.page li {
  margin-top: 14px;
  color: var(--ink-300);
}
article.page ul {
  padding-left: 20px;
}

/* ------------------------------------------------------------------ skip link */

/*
 * Present for everybody, visible only when it has focus. The header has four links
 * before the content starts, which is four tab stops on every page for somebody using a
 * keyboard or a switch.
 */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 20;
  background: var(--ink-850);
  border: 1px solid var(--ink-700);
  border-radius: var(--radius);
  color: var(--ink-100);
  padding: 10px 14px;
}
.skip:focus {
  left: 12px;
  top: 12px;
}

/* ------------------------------------------------------------------ questions */

/*
 * A plain list of questions and answers, all of them open.
 *
 * Not an accordion. Everything here is short, the reader is deciding whether to trust
 * the thing, and a page that makes somebody click eight times to read eight short
 * paragraphs is optimising for its own tidiness. Open also means findable: in the page
 * with the browser's own search, and by a search engine, which indexes what is rendered.
 */
dl.qa {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 26px 40px;
  margin: 34px 0 0;
}
dl.qa > div {
  border-top: 1px solid var(--line);
  padding-top: 16px;
}
dl.qa dt {
  color: var(--ink-100);
  font-size: 17px;
  font-weight: 650;
  letter-spacing: -0.01em;
  margin: 0 0 8px;
}
dl.qa dd {
  margin: 0;
  font-size: 15px;
  color: var(--ink-400);
  line-height: 1.6;
}
@media (max-width: 760px) {
  dl.qa {
    grid-template-columns: minmax(0, 1fr);
    gap: 20px;
  }
}

/* ------------------------------------------------------------------ who makes this */

/* One column of prose where the feature rows have two, because there is no screenshot
   of a person and a picture beside this paragraph would be decoration. */
.row.narrow {
  grid-template-columns: minmax(0, 64ch);
}
