/* Onixphere site - one shared stylesheet.

   Every design value is a token in the :root block below, and no colour
   literal appears anywhere else in this file. The palette is the app's
   own (renderer/css/base.css and docs/colours.md in the app's repository):
   neutral greys, white washes for every interaction, and no coloured
   primary button. The brand red is not used on the site.

   Order: fonts, tokens, base, shared pieces (layout, wordmark, buttons,
   cards, the clip and still frame, section type), then one block per section. */

/* ---------- fonts ---------- */

@font-face {
  font-family: "Geist";
  src: url("assets/fonts/geist/Geist-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Geist Mono";
  src: url("assets/fonts/geist/GeistMono-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Lineal is for the wordmark only. It blocks rather than swaps: the name
   is short, and must never flash in a fallback font. */
@font-face {
  font-family: "Lineal";
  src: url("assets/fonts/lineal/Lineal-Light.woff2") format("woff2"),
       url("assets/fonts/lineal/Lineal-Light.woff") format("woff");
  font-weight: 300;
  font-style: normal;
  font-display: block;
}

@font-face {
  font-family: "Lineal";
  src: url("assets/fonts/lineal/Lineal-Medium.woff2") format("woff2"),
       url("assets/fonts/lineal/Lineal-Medium.woff") format("woff");
  font-weight: 500;
  font-style: normal;
  font-display: block;
}

/* ---------- tokens ---------- */

:root {
  color-scheme: dark;

  /* Surfaces, back to front. All neutral greys, as in the app. */
  --bg: #131313;
  --panel: #1b1b1b;
  --panel-raised: #232323;
  --line: #2d2d2d;
  /* The frosted header, as the app's small floating surfaces. */
  --glass: rgba(21, 21, 21, 0.85);
  --glass-blur: blur(40px) saturate(170%);

  /* Text, strongest to faintest, then text on a light fill. */
  --heading: #f3f3f3;
  --text: #cccccc;
  --dim: #949494;
  --dim-2: #6e6e6e;       /* Below AA for text: focus rings and icons only. */
  --on-light: #121212;

  /* White washes. Interaction never brings in a hue - hovering, pressing
     and selecting only lighten what is already there. */
  --tint: rgba(255, 255, 255, 0.02);
  --hover: rgba(255, 255, 255, 0.06);
  --selected: rgba(255, 255, 255, 0.08);
  --strong: rgba(255, 255, 255, 0.1);
  --strong-hover: rgba(255, 255, 255, 0.14);
  --selection: rgba(255, 255, 255, 0.16);

  /* The primary button: a light fill with dark text, the site's one solid
     shape. White on hover, a step darker while pressed. */
  --button-primary-bg: #f3f3f3;
  --button-primary-hover: #ffffff;
  --button-primary-active: #d9d9d9;
  /* The secondary button's hairline. */
  --button-edge: rgba(255, 255, 255, 0.14);

  /* Depth. A raised thing's hairline is lit from above: brightest along
     the top, fading towards the bottom. */
  --edge: rgba(255, 255, 255, 0.06);
  --edge-lit: rgba(255, 255, 255, 0.13);
  --edge-fade: rgba(255, 255, 255, 0.02);
  --highlight: rgba(255, 255, 255, 0.05);
  --shadow: rgba(0, 0, 0, 0.5);
  /* The flat black panel a demo clip or still sits in; the stills are drawn
     on the same black (the demo stage's --stage-flat). */
  --clip-bg: #0b0b0c;
  /* Light falling on the hero screenshot, and the wash at the top of the
     hero. White, never red. */
  --hero-glow: rgba(255, 255, 255, 0.06);
  --hero-wash: rgba(255, 255, 255, 0.025);
  /* The logo ring (the app's docs/logo.md, light variant): its two shading
     colours and its glow. Used only by the ring's drawing. */
  --logo-edge: #eef1f5;
  --logo-centre: #ffffff;
  --logo-glow: rgba(225, 240, 255, 0.75);
  /* The ring's outer diameter in the hero: the app's 88px on a phone,
     growing with the page to 120px, small enough that the demo starts on
     a laptop's first screen. */
  --size-hero-mark: clamp(88px, 4vw + 64px, 120px);
  /* Not a visible colour: the opaque fill a CSS mask needs to cut the lit
     hairline out of a gradient. */
  --mask-fill: #000000;

  /* Type */
  --font: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", ui-monospace, Consolas, monospace;
  --font-wordmark: "Lineal", var(--font);
  --size-hero: clamp(40px, 4.2vw + 20px, 72px);
  --size-title: clamp(30px, 2vw + 20px, 40px);
  --size-lead: clamp(18px, 0.4vw + 16px, 20px);
  --size-body: 17px;
  --size-h3: 19px;
  --size-small: 15px;
  --size-fine: 13px;
  --size-prose-h2: 24px;
  --size-price: 56px;
  --size-price-small: 48px;
  --size-wordmark: 26px;
  --size-wordmark-footer: 18px;
  --size-button: 16px;
  --size-button-small: 14px;
  --size-feature-icon: 18px;   /* The app's sidebar icon size. */
  --size-media-toggle: 36px;   /* Play / Pause / Replay: the tap area. */
  --size-media-toggle-icon: 18px;
  --tracking-tight: -0.02em;
  --tracking-eyebrow: 0.08em;
  --tracking-wordmark: 0.02em;

  /* Spacing, in steps of 8px */
  --s1: 8px;
  --s2: 16px;
  --s3: 24px;
  --s4: 32px;
  --s5: 40px;
  --s6: 48px;
  --s8: 64px;
  --s10: 80px;
  --s12: 96px;
  --s20: 160px;
  --section-gap: var(--s20);
  --gutter: var(--s3);

  /* Widths */
  --width: 1120px;
  --width-text: 640px;
  --width-plan: 440px;

  /* Radii */
  --radius-card: 16px;
  --radius-frame: 12px;
  --radius-button: 10px;
  --radius-small: 8px;
  --radius-pill: 999px;

  /* Motion. One duration for every hover and state change; a slower one
     for sections rising into view. */
  --duration: 180ms;
  --duration-reveal: 600ms;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  --header-height: 64px;
}

@media (max-width: 720px) {
  :root {
    --section-gap: var(--s12);
    --gutter: var(--s2);
  }
}

/* ---------- base ---------- */

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

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

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--size-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

::selection {
  background: var(--selection);
  color: var(--heading);
}

/* A jump to #features, or to a section of a legal page, stops below the
   fixed header rather than under it. */
[id] {
  scroll-margin-top: calc(var(--header-height) + var(--s3));
}

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

h1,
h2,
h3,
h4 {
  margin: 0;
  color: var(--heading);
  font-weight: 500;
  letter-spacing: var(--tracking-tight);
  line-height: 1.05;
  text-wrap: balance;
}

h3,
h4 {
  font-size: var(--size-h3);
  line-height: 1.3;
}

p,
li {
  text-wrap: pretty;
}

p {
  margin: 0;
}

a {
  color: var(--heading);
  text-decoration-line: underline;
  text-decoration-color: var(--dim);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  transition: text-decoration-color var(--duration) var(--ease);
}

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

/* As in the app: one quiet ring for keyboard focus, never the default. */
:focus-visible {
  outline: 2px solid var(--dim-2);
  outline-offset: 2px;
}

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--heading);
  background: var(--panel-raised);
  border-radius: 6px;
  box-shadow: inset 0 0 0 1px var(--edge);
  padding: 1px 6px;
}

.skip-link {
  position: absolute;
  left: var(--s2);
  top: -100px;
  z-index: 100;
  padding: var(--s1) var(--s2);
  background: var(--panel-raised);
  border-radius: var(--radius-button);
}

.skip-link:focus {
  top: var(--s2);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---------- shared: layout ---------- */

.container {
  width: 100%;
  max-width: calc(var(--width) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.narrow {
  max-width: calc(var(--width-text) + 2 * var(--gutter));
}

.section {
  padding-top: var(--section-gap);
}

.centered {
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

/* ---------- shared: section type ---------- */

.eyebrow {
  margin-bottom: var(--s2);
  color: var(--dim);
  font-size: var(--size-fine);
  font-weight: 500;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

.section-head {
  max-width: var(--width-text);
}

.section-title {
  font-size: var(--size-title);
}

.lead {
  font-size: var(--size-lead);
  line-height: 1.55;
}

.section-head .lead {
  margin-top: var(--s3);
}

.fine {
  color: var(--dim);
  font-size: var(--size-small);
}

/* The small line under every Download button. */
.download-note {
  margin-top: var(--s2);
  color: var(--dim);
  font-size: var(--size-fine);
  line-height: 1.7;
}

.text-link {
  display: inline-block;
  margin-top: var(--s3);
  font-size: var(--size-small);
}

/* Running text: the legal pages and the longer pricing sections. */
.prose h2 {
  margin-top: var(--s8);
  font-size: var(--size-prose-h2);
  line-height: 1.25;
}

.prose p,
.prose ul {
  margin-top: var(--s2);
}

.prose ul {
  padding-left: 1.25em;
}

.prose li + li {
  margin-top: var(--s1);
}

.prose li::marker {
  color: var(--dim);
}

.prose strong {
  color: var(--heading);
  font-weight: 500;
}

/* ---------- shared: wordmark ---------- */

/* As in the app's sidebar: one size and colour for the whole name, Lineal
   Light, with the opening O in Lineal Medium. Upright, never transformed. */
.wordmark {
  font-family: var(--font-wordmark);
  font-weight: 300;
  font-style: normal;
  text-transform: none;
  letter-spacing: var(--tracking-wordmark);
  line-height: 1;
  color: var(--heading);
}

.wordmark-initial {
  font-weight: 500;
}

/* ---------- shared: buttons ---------- */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s1);
  height: 48px;
  padding: 0 var(--s3);
  border: 0;
  border-radius: var(--radius-button);
  font: inherit;
  font-size: var(--size-button);
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--duration) var(--ease),
              color var(--duration) var(--ease);
}

.button-primary {
  color: var(--on-light);
  background: var(--button-primary-bg);
}

.button-primary:hover {
  background: var(--button-primary-hover);
}

.button-primary:active {
  background: var(--button-primary-active);
}

.button-secondary {
  color: var(--heading);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--button-edge);
}

.button-secondary:hover {
  background: var(--strong);
}

.button-secondary:active {
  background: var(--hover);
}

/* A button script reveals: hidden until then, whatever its display. */
.button[hidden] {
  display: none;
}

.button-small {
  height: 36px;
  padding: 0 var(--s2);
  font-size: var(--size-button-small);
  border-radius: var(--radius-small);
}

.button-wide {
  width: 100%;
}

/* A button whose action isn't open yet - Download and Buy until launch. A
   span, not a link, so there is nothing to follow; dimmed, with no hover,
   so it never looks pressable. */
.button-soon,
.button-soon:hover,
.button-soon:active {
  color: var(--dim);
  background: var(--strong);
  cursor: default;
}

/* The Play / Pause / Replay button on the demo clips (setToggle in
   script.js): the icon alone, with no pill or fill behind it, dim until
   pointed at. Its box is larger than the icon so it
   stays easy to tap; the word is its tooltip and accessible name. */
.media-toggle {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--size-media-toggle);
  height: var(--size-media-toggle);
  /* Pulls the tap area back by its padding, so the icon itself lines up
     with the frame's edge and nothing around it moves. */
  margin: calc((var(--size-media-toggle-icon) - var(--size-media-toggle)) / 2);
  padding: 0;
  border: 0;
  border-radius: var(--radius-small);
  background: none;
  color: var(--dim);
  cursor: pointer;
  transition: color var(--duration) var(--ease);
}

.media-toggle:hover {
  color: var(--heading);
}

.media-toggle:active {
  color: var(--dim);
}

.media-toggle[hidden] {
  display: none;
}

.media-toggle-icon {
  width: var(--size-media-toggle-icon);
  height: var(--size-media-toggle-icon);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.media-toggle-fill {
  fill: currentColor;
  stroke: none;
}

.button-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s2);
}

/* ---------- shared: cards ---------- */

/* A card carries a hairline lit from above: a gradient from --edge-lit at
   the top to --edge-fade at the bottom, masked down to a 1px ring. */
.card {
  position: relative;
  background: var(--panel);
}

.card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  padding: 1px;
  border-radius: inherit;
  background: linear-gradient(180deg, var(--edge-lit), var(--edge-fade));
  -webkit-mask: linear-gradient(var(--mask-fill), var(--mask-fill)) content-box,
                linear-gradient(var(--mask-fill), var(--mask-fill));
  -webkit-mask-composite: xor;
  mask: linear-gradient(var(--mask-fill), var(--mask-fill)) content-box,
        linear-gradient(var(--mask-fill), var(--mask-fill));
  mask-composite: exclude;
  pointer-events: none;
}

.card {
  border-radius: var(--radius-card);
}

/* ---------- shared: demo clips and stills ---------- */

/* A clip or still rendered from the app. It brings its own window,
   backdrop and captions, so it is shown bare: a flat black panel with no
   shadow, since a long soft shadow on a near-black page bands into a
   murky patch. The stills are drawn on that same black, so image and
   frame are one panel. */
.clip-frame {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-frame);
  background: var(--clip-bg);
}

.clip-video,
.clip-still {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* With script, the clip itself is a play and pause control. */
.js .clip-video {
  cursor: pointer;
}

/* A feature row's clip (initFeatureClip in script.js) or still, set below
   the row's text. */
.feature-clip,
.feature-still {
  margin: var(--s8) 0 0;
}

/* Under a feature clip: its button, at the right as under the hero clip. */
.clip-bar {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--s3);
}

/* ---------- site header ---------- */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  height: var(--header-height);
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: inset 0 -1px 0 var(--edge);
  transition: background-color var(--duration) var(--ease),
              box-shadow var(--duration) var(--ease);
}

/* With JavaScript, the bar is clear over the top of the page until it
   scrolls. Without it, the bar stays frosted so text never runs under it. */
.js .site-header:not(.is-scrolled):not(.is-open) {
  background: transparent;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.site-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  height: 100%;
}

.site-brand {
  display: inline-flex;
  align-items: center;
  font-size: var(--size-wordmark);
  text-decoration: none;
}

.site-actions {
  display: flex;
  align-items: center;
  gap: var(--s3);
}

.site-nav ul {
  display: flex;
  gap: var(--s3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav a {
  color: var(--dim);
  font-size: var(--size-small);
  text-decoration: none;
  transition: color var(--duration) var(--ease);
}

.site-nav a:hover {
  color: var(--heading);
}

.site-menu-button {
  display: none;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  color: var(--dim);
  background: transparent;
  border: 0;
  border-radius: var(--radius-small);
  cursor: pointer;
  transition: background-color var(--duration) var(--ease),
              color var(--duration) var(--ease);
}

.site-menu-button:hover {
  color: var(--heading);
  background: var(--strong);
}

.site-menu-button:active {
  background: var(--hover);
}

.site-menu-button svg {
  width: 18px;
  height: 18px;
}

@media (max-width: 640px) {
  .site-actions,
  .site-nav ul {
    gap: var(--s2);
  }

  .js .site-menu-button {
    display: inline-flex;
  }

  .js .site-nav {
    position: absolute;
    top: var(--header-height);
    left: 0;
    right: 0;
    display: none;
    padding: var(--s1) var(--gutter) var(--s3);
    background: var(--glass);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    box-shadow: inset 0 -1px 0 var(--edge);
  }

  .js .site-header.is-open .site-nav {
    display: block;
  }

  .js .site-nav ul {
    flex-direction: column;
    gap: 0;
  }

  .js .site-nav a {
    display: block;
    padding: 12px 0;
    font-size: var(--size-body);
  }
}

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

.site-footer {
  padding: var(--s8) 0 var(--s6);
  box-shadow: inset 0 1px 0 var(--edge);
  font-size: var(--size-small);
}

.site-footer-inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s4);
}

.site-footer-brand .wordmark {
  font-size: var(--size-wordmark-footer);
}

.site-footer-brand p {
  max-width: 32em;
  margin-top: var(--s1);
  color: var(--dim);
}

.site-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer-links a {
  color: var(--dim);
  text-decoration: none;
  transition: color var(--duration) var(--ease);
}

.site-footer-links a:hover {
  color: var(--heading);
}

.site-footer-copyright {
  width: 100%;
  margin-top: var(--s3);
  color: var(--dim);
  font-size: var(--size-fine);
}

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

.hero {
  padding-top: calc(var(--header-height) + var(--s12));
  text-align: center;
  background: radial-gradient(ellipse 80% 60% at 50% 0%, var(--hero-wash), transparent 70%);
}

/* The logo ring above the headline. The view box is 1.5 x the diameter so
   the glow has room; the negative side and top margins take that room back
   out of the layout, so the ring sits as if it were a diameter-sized box. */
.hero-mark {
  --d: var(--size-hero-mark);
  display: block;
  width: calc(var(--d) * 1.5);
  height: calc(var(--d) * 1.5);
  margin: calc(var(--d) * -0.25) auto calc(var(--d) * -0.25 + var(--s6));
  overflow: visible;
}

.hero-title {
  margin: 0 auto;
  font-size: var(--size-hero);
}

/* The headline's two sentences, one to a line where they fit. */
.hero-title-line {
  display: block;
}

.hero-lead {
  max-width: 34em;
  margin: var(--s3) auto 0;
}

.hero-actions {
  margin-top: var(--s5);
}

/* A statement leading into the demo, not fine print: set apart from the
   download note above it and at the lead's size, so the two never read
   as one block. */
.hero-principle {
  margin-top: var(--s6);
  color: var(--dim);
  font-size: var(--size-lead);
  line-height: 1.4;
}

.hero-principle strong {
  color: var(--heading);
  font-weight: 500;
}

.hero-shot {
  position: relative;
  isolation: isolate;
  margin: var(--s8) 0 0;
}

/* Under the demo: its four chapters, each a title and one line saying what
   the step is, and the Play / Pause / Replay button. */
.hero-demo-bar {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  margin-top: var(--s3);
  text-align: left;
}

.hero-chapters {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.hero-chapter {
  display: block;
  padding-top: 12px;
  color: var(--dim);
  font-size: var(--size-small);
  text-decoration: none;
  box-shadow: inset 0 1px 0 var(--line);
  transition: color var(--duration) var(--ease),
              box-shadow var(--duration) var(--ease);
}

.hero-chapter:hover {
  color: var(--heading);
}

/* The chapter playing now. */
.hero-chapter[aria-current] {
  color: var(--heading);
  box-shadow: inset 0 1px 0 var(--heading);
}

.hero-chapter-title {
  display: block;
  color: var(--heading);
  font-weight: 500;
}

.hero-chapter-text {
  display: block;
  margin-top: var(--s1);
  font-size: var(--size-fine);
  line-height: 1.5;
}

/* Light falling on the screenshot from above. */
.hero-shot::before {
  content: "";
  position: absolute;
  inset: -12% 6% 30% 6%;
  z-index: -1;
  background: radial-gradient(ellipse at 50% 30%, var(--hero-glow), transparent 70%);
  filter: blur(40px);
  pointer-events: none;
}

@media (max-width: 720px) {
  .hero {
    padding-top: calc(var(--header-height) + var(--s8));
  }

  .hero-actions .button {
    flex: 1 1 100%;
  }

  .hero-shot {
    margin-top: var(--s6);
  }

  .hero-demo-bar {
    flex-direction: column;
    align-items: stretch;
  }

  .hero-demo-bar .media-toggle {
    align-self: flex-start;
  }

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

/* ---------- features ---------- */

/* One feature per row: the text above, set to the left like a section
   head, the media at the full container width beneath it, so the app's
   interface can be read. */
.features-row {
  padding-top: var(--section-gap);
}

.features-text {
  max-width: var(--width-text);
}

/* A feature row's label is the feature's name as the app shows it, so it
   is written as the app writes it - white, a step larger, not uppercase -
   where a section's eyebrow ("Everything else", "Privacy") stays small
   and dim. The headline under it still leads. Before the name, the icon
   the app shows for it, in the label's colour and at the app's size, so
   the site and the app are recognisably the same. */
.features-text .eyebrow {
  display: flex;
  align-items: center;
  gap: var(--s1);
  color: var(--heading);
  font-size: var(--size-button-small);
  letter-spacing: 0;
  text-transform: none;
}

.features-icon {
  flex: none;
  width: var(--size-feature-icon);
  height: var(--size-feature-icon);
}

.features-text h2 {
  font-size: var(--size-title);
}

.features-text p:not(.eyebrow) {
  margin-top: var(--s3);
}

@media (max-width: 860px) {
  .feature-clip,
  .feature-still {
    margin-top: var(--s5);
  }
}

/* ---------- privacy ---------- */

.privacy-band {
  padding: var(--s12) 0;
  background: var(--panel);
  box-shadow: inset 0 1px 0 var(--edge-lit), inset 0 -1px 0 var(--edge);
}

.privacy-points {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s5);
  margin: var(--s8) 0 0;
  padding: 0;
  list-style: none;
  text-align: left;
}

.privacy-points li {
  padding-top: var(--s3);
  box-shadow: inset 0 1px 0 var(--line);
}

.privacy-points h3 {
  margin-bottom: var(--s1);
}

.privacy-points p {
  color: var(--dim);
  font-size: var(--size-small);
}

@media (max-width: 860px) {
  .privacy-points {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s4);
  }
}

/* ---------- everything it does ---------- */

/* What the page has not already shown, in one grid, under a quiet line
   naming the providers it works with. */
.more-models {
  margin-top: var(--s2);
  color: var(--dim);
  font-size: var(--size-small);
}

.more-models strong {
  color: var(--text);
  font-weight: 500;
}

.more-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s2);
  margin: var(--s8) 0 0;
  padding: 0;
  list-style: none;
}

.more-item {
  padding: var(--s4);
}

.more-item h3 {
  margin-bottom: var(--s1);
}

.more-item p {
  color: var(--dim);
  font-size: var(--size-small);
}

@media (max-width: 860px) {
  .more-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .more-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .more-item {
    padding: var(--s3);
  }
}

/* ---------- closing call ---------- */

.closing {
  padding: var(--section-gap) 0;
  text-align: center;
}

.closing-title {
  font-size: var(--size-hero);
}

.closing-actions {
  margin-top: var(--s5);
}

/* ---------- pricing ---------- */

.pricing-head {
  padding-top: calc(var(--header-height) + var(--s12));
  text-align: center;
}

.pricing-title {
  font-size: var(--size-hero);
}

.pricing-head .lead {
  margin-top: var(--s3);
}

.pricing-plan {
  max-width: var(--width-plan);
  margin: var(--s8) auto 0;
  padding: var(--s5);
  text-align: left;
}

.pricing-name {
  font-size: var(--size-h3);
}

.pricing-price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px var(--s2);
  margin-top: var(--s4);
  font-variant-numeric: tabular-nums;
}

.pricing-now {
  color: var(--heading);
  font-size: var(--size-price);
  font-weight: 500;
  letter-spacing: var(--tracking-tight);
  line-height: 1;
}

.pricing-terms {
  color: var(--dim);
  font-size: var(--size-small);
}

.pricing-note {
  margin-top: var(--s2);
  color: var(--dim);
  font-size: var(--size-small);
  font-variant-numeric: tabular-nums;
}

.pricing-checklist {
  margin: var(--s4) 0;
  padding: var(--s4) 0 0;
  list-style: none;
  box-shadow: inset 0 1px 0 var(--line);
}

.pricing-checklist li {
  display: flex;
  gap: 12px;
  padding: 6px 0;
  font-size: var(--size-small);
}

.pricing-checklist svg {
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 3px;
  color: var(--dim);
}

.pricing-checkout {
  margin-top: var(--s2);
  color: var(--dim);
  font-size: var(--size-fine);
  text-align: center;
}

.pricing-trial {
  display: block;
  margin-top: var(--s3);
  font-size: var(--size-small);
  text-align: center;
}

@media (max-width: 480px) {
  .pricing-plan {
    padding: var(--s3);
  }

  .pricing-now {
    font-size: var(--size-price-small);
  }
}

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

.faq-list {
  margin-top: var(--s6);
  box-shadow: inset 0 1px 0 var(--line);
}

.faq-item {
  box-shadow: inset 0 -1px 0 var(--line);
}

.faq-question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  padding: var(--s3) 0;
  color: var(--heading);
  font-weight: 500;
  cursor: pointer;
  list-style: none;
}

.faq-question::-webkit-details-marker {
  display: none;
}

.faq-question svg {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--dim);
  transition: transform var(--duration) var(--ease),
              color var(--duration) var(--ease);
}

.faq-question:hover svg {
  color: var(--heading);
}

.faq-item[open] .faq-question svg {
  transform: rotate(45deg);
}

.faq-answer {
  max-width: 60ch;
  padding-bottom: var(--s3);
}

/* ---------- legal pages ---------- */

.legal {
  padding-top: calc(var(--header-height) + var(--s10));
  padding-bottom: var(--section-gap);
}

.legal-title {
  font-size: var(--size-title);
}

.legal-updated {
  color: var(--dim);
  font-size: var(--size-small);
}

/* ---------- not found ---------- */

.notfound {
  min-height: 70vh;
  padding-top: calc(var(--header-height) + var(--s20));
  padding-bottom: var(--section-gap);
  text-align: center;
}

.notfound-title {
  font-size: var(--size-title);
}

.notfound .text-link {
  margin-top: var(--s4);
}

/* ---------- motion ---------- */

/* Sections rise into view once. Only with JavaScript, so nothing is ever
   hidden from a page that cannot reveal it. */
.js .reveal {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity var(--duration-reveal) var(--ease-out),
    transform var(--duration-reveal) var(--ease-out);
}

.js .reveal.is-visible {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
  }

  .js .reveal {
    opacity: 1;
    transform: none;
  }
}
