/* Everything visual here comes from ../docs/BRAND.md rather than being chosen
 * on this page. A landing page that invents its own colours is a landing page
 * for a different product, and this one is quoting an application the visitor
 * is about to install.
 *
 * Same reasoning as ad/src/theme.ts, and the same reason both live in this
 * repository: in a separate one they would drift out of step with the brand
 * they are quoting and nothing would say so. */

:root {
  color-scheme: dark;

  /* Brand. One hue, for the mark, links, focus rings and emphasis. It never
     encodes a verdict; that is what the tiers below are for, and a green
     "Download" button would teach the opposite of what the app teaches. */
  --signal: #4fbbdb;
  --signal-dim: #2e9cbc;

  --ground: #07080a;
  --surface: #12171a;
  --glass: rgb(18 23 26 / 0.72);

  --text-bright: #fafafa;
  --text-body: #d4d4d8;

  /* BRAND.md's Dim, and not the four-step ramp in ad/src/theme.ts. That ramp is
     for a film, where the faintest step carries type at a hundred pixels; here
     the same value would set a footer at fourteen and land near 3:1 against the
     ground. Dim is 7.5:1 and the step below it 5.2:1, so the hierarchy survives
     and both are still readable by someone who is not on a good monitor in a
     dark room. */
  --text-dim: #90a1a8;
  --text-faint: #78848a;

  --line-hair: rgb(255 255 255 / 0.07);
  --line-edge: rgb(255 255 255 / 0.11);

  /* Data only, straight from the rule table. Muted rather than traffic-light,
     because saturated primaries are what the scamware end of this category
     looks like. */
  --tier-free: #5fae79;
  --tier-rebuild: #c9a63c;
  --tier-yours: #d4854a;
  --tier-keep: #c25f57;

  /* No webfont, deliberately. Every visitor this page is written for is on the
     operating system whose interface font it is asking to look like, so the
     stack resolves natively, renders on the first paint and costs no request
     to a third party. */
  --sans: 'Segoe UI Variable Text', 'Segoe UI', 'Inter', system-ui, -apple-system, sans-serif;
  --sans-display: 'Segoe UI Variable Display', 'Segoe UI', 'Inter', system-ui, sans-serif;
  --mono: 'Cascadia Mono', Consolas, 'JetBrains Mono', ui-monospace, monospace;

  --gutter: clamp(1.25rem, 5vw, 3rem);
  --measure: 68ch;
}

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

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

body {
  margin: 0;
  background-color: var(--ground);
  /* Only the fall of light from the top edge. The colour comes from the pools
     in the backdrop, and running two systems for one job is how a background
     becomes busy. */
  background-image: linear-gradient(180deg, rgb(255 255 255 / 0.028), transparent 42%);
  background-repeat: no-repeat;
  background-attachment: fixed;
  color: var(--text-body);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.6;
  font-feature-settings: 'tnum';
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ── Type roles ─────────────────────────────────────────────────────────────
   From the table in BRAND.md. The negative tracking is what makes a display
   size look set rather than merely enlarged. */

h1,
h2,
h3 {
  color: var(--text-bright);
  margin: 0;
  text-wrap: balance;
}

h1 {
  font-family: var(--sans-display);
  font-weight: 650;
  letter-spacing: -0.035em;
  line-height: 1.02;
  font-size: clamp(2.75rem, 6.4vw, 4.5rem);
}

h2 {
  font-family: var(--sans-display);
  font-weight: 650;
  letter-spacing: -0.028em;
  line-height: 1.1;
  font-size: clamp(1.9rem, 3.6vw, 2.65rem);
}

h3 {
  font-weight: 650;
  letter-spacing: -0.02em;
  font-size: 1.0625rem;
  line-height: 1.4;
}

p {
  margin: 0;
  max-width: var(--measure);
}

a {
  color: var(--signal);
  text-decoration-color: rgb(79 187 219 / 0.35);
  text-underline-offset: 3px;
}

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

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

strong {
  color: var(--text-bright);
  font-weight: 600;
}

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

code {
  font-size: 0.9em;
  color: var(--text-body);
  background: rgb(255 255 255 / 0.045);
  border: 1px solid var(--line-hair);
  border-radius: 4px;
  padding: 0.08em 0.36em;
}

.label {
  font-family: var(--mono);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--signal);
  margin: 0;
}

.lede {
  font-size: clamp(1.125rem, 1.9vw, 1.3125rem);
  line-height: 1.5;
  color: var(--text-body);
}

.dim {
  color: var(--text-dim);
}

.faint {
  color: var(--text-faint);
}

/* ── Backdrop ───────────────────────────────────────────────────────────────
   The same painted depth the application uses instead of Mica: two faint pools
   in the brand hue, the mark oversized and running off the edge, and two
   percent of noise to kill the banding a large low-contrast gradient shows on
   an eight bit panel. Centred would be a splash screen; continuing past the
   frame is what reads as a watermark. */

.backdrop {
  position: fixed;
  inset: 0;
  z-index: -10;
  overflow: hidden;
  pointer-events: none;
}

.bd-pool {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
}

.bd-pool-a {
  top: -22vh;
  left: -14vw;
  width: 78vw;
  height: 78vh;
  background: rgb(79 187 219 / 0.055);
}

.bd-pool-b {
  right: -20vw;
  bottom: -26vh;
  width: 70vw;
  height: 70vh;
  background: rgb(46 156 188 / 0.04);
}

.bd-mark {
  position: absolute;
  right: -13%;
  bottom: -20%;
  height: 122vh;
  width: 122vh;
  max-width: 96vw;
  opacity: 0.038;
  transform-origin: 70% 70%;
  animation: backdrop-drift 110s ease-in-out infinite;
}

/* Reading room, and the reason the mark can be this large. An ellipse of the
   ground colour over the middle, opaque at its centre and gone by its edge, so
   text has the contrast of a flat dark background while the mark keeps the
   corners. Without it the cells read as banding rather than as a watermark. */
.bd-scrim {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    64rem 46rem at 46% 42%,
    rgb(7 8 10 / 0.92),
    rgb(7 8 10 / 0.66) 42%,
    transparent 76%
  );
}

.bd-grain {
  position: absolute;
  inset: 0;
  opacity: 0.022;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Almost two minutes a cycle. Slow enough that no single glance catches it
   moving and no two glances find quite the same picture. */
@keyframes backdrop-drift {
  0%,
  100% {
    transform: scale(1) rotate(0deg);
  }
  50% {
    transform: scale(1.045) rotate(-0.6deg);
  }
}

/* ── Frame ──────────────────────────────────────────────────────────────── */

.wrap {
  width: 100%;
  max-width: 1140px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip {
  position: absolute;
  left: -9999px;
}

.skip:focus {
  left: var(--gutter);
  top: 0.75rem;
  z-index: 60;
  background: var(--surface);
  border: 1px solid var(--line-edge);
  border-radius: 8px;
  padding: 0.5rem 0.9rem;
  color: var(--text-bright);
}

nav {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid transparent;
  transition: background-color 0.25s ease, border-color 0.25s ease;
}

nav.stuck {
  background: rgb(7 8 10 / 0.72);
  backdrop-filter: blur(16px);
  border-bottom-color: var(--line-hair);
}

.nav-row {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  height: 4.25rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--text-bright);
  font-weight: 650;
  letter-spacing: -0.02em;
  font-size: 1.0625rem;
}

.brand svg {
  width: 22px;
  height: 22px;
  display: block;
}

.nav-links {
  display: flex;
  gap: 1.5rem;
  margin-left: auto;
  align-items: center;
}

/* :not(.btn), because a bare `.nav-links a` also outranks `.btn-primary` and
   quietly repaints the download button's label in secondary grey. */
.nav-links a:not(.btn) {
  color: var(--text-dim);
  text-decoration: none;
  font-size: 0.9375rem;
}

.nav-links a:not(.btn):hover {
  color: var(--text-bright);
}

@media (max-width: 860px) {
  .nav-links a:not(.btn) {
    display: none;
  }
}

/* ── Buttons ────────────────────────────────────────────────────────────────
   A flat rectangle of colour is the difference between a button and a link
   wearing a background. The gradient, the bright inner lip and the shadow
   beneath are the same three things the application's own primary uses. */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  border-radius: 10px;
  padding: 0.7rem 1.15rem;
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 550;
  text-decoration: none;
  white-space: nowrap;
  transition: background-image 0.15s ease, background-color 0.15s ease, transform 0.05s ease;
}

.btn-primary {
  color: #0b0e10;
  background-image: linear-gradient(180deg, #6fcbe6 0%, #3fb0d2 100%);
  box-shadow:
    inset 0 1px 0 0 rgb(255 255 255 / 0.38),
    inset 0 -1px 0 0 rgb(0 0 0 / 0.12),
    0 1px 2px 0 rgb(0 0 0 / 0.45),
    0 0 0 1px rgb(79 187 219 / 0.22);
}

.btn-primary:hover {
  background-image: linear-gradient(180deg, #86d8ee 0%, #4fbbdb 100%);
}

.btn-primary:active {
  background-image: linear-gradient(180deg, #3fb0d2 0%, #369cbb 100%);
  transform: translateY(0.5px);
}

.btn-ghost {
  color: var(--text-body);
  border: 1px solid var(--line-edge);
  background: rgb(255 255 255 / 0.03);
  box-shadow: inset 0 1px 0 0 rgb(255 255 255 / 0.04);
}

.btn-ghost:hover {
  background: rgb(255 255 255 / 0.06);
  color: var(--text-bright);
}

/* ── Cards ──────────────────────────────────────────────────────────────────
   The hairline along the top edge is what makes it read as glass rather than
   as a grey box: real glass catches light on its upper lip. */

.card {
  border: 1px solid var(--line-hair);
  border-radius: 14px;
  background: var(--glass);
  backdrop-filter: blur(20px);
  box-shadow: inset 0 1px 0 0 rgb(255 255 255 / 0.045);
}

/* ── Hero ───────────────────────────────────────────────────────────────── */

.hero {
  padding-block: clamp(3.5rem, 9vw, 7rem) clamp(3rem, 6vw, 5rem);
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  align-items: center;
}

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

.hero h1 {
  margin-top: 1.1rem;
}

.hero .lede {
  margin-top: 1.25rem;
}

/* The promise, and it goes this high on the page on purpose. Everything else
   in this category asks to be trusted with an irreversible action on somebody's
   disk. This one does not have to ask. */
.promise {
  margin-top: 1.75rem;
  padding: 0.9rem 0 0.9rem 1.1rem;
  border-left: 2px solid var(--signal);
  max-width: var(--measure);
}

.promise strong {
  color: var(--text-bright);
}

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

.cta-meta {
  margin-top: 1rem;
  font-size: 0.875rem;
  color: var(--text-faint);
}

/* The finding, not the logo. A stranger decides in the first second whether
   this is another cleaner with a big number on it, and the only thing that
   answers that is the gap between the two figures. */

.finding {
  padding: 1.5rem;
}

.finding-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--line-hair);
}

.finding-path {
  font-family: var(--mono);
  font-size: 0.8125rem;
  color: var(--text-dim);
}

/* Two mono strings sharing one line stop fitting somewhere around a phone, and
   the provenance is the one of the two that can be spared: the sentence under
   the figures says the same thing in words. */
@media (max-width: 520px) {
  .finding-head .label {
    display: none;
  }
}

.finding-row {
  padding-top: 1.15rem;
}

.finding-row + .finding-row {
  margin-top: 0.35rem;
}

.finding-caption {
  font-size: 0.8125rem;
  color: var(--text-dim);
}

.finding-claimed {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.5rem, 3vw, 1.875rem);
  color: var(--text-faint);
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
  margin-top: 0.15rem;
}

.finding-real {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: clamp(2.5rem, 6vw, 3.5rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--signal);
  line-height: 1.05;
  margin-top: 0.15rem;
}

.finding-foot {
  margin-top: 1.35rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line-hair);
  font-size: 0.8125rem;
  color: var(--text-faint);
  max-width: none;
}

/* ── The tier bar ───────────────────────────────────────────────────────────
   The four tiers broken once, and that gap is the mark's empty cell again:
   the part that was given back. Same device as the banner's bottom edge. */

.tierbar {
  display: flex;
  gap: 0;
  height: 3px;
  border-radius: 2px;
  overflow: hidden;
}

.tierbar span {
  display: block;
  height: 100%;
}

/* Same proportions as the bar along the banner's bottom edge, so the device is
   one thing in three places rather than three similar things. */
.tierbar .gap {
  background: transparent;
}

/* ── Sections ───────────────────────────────────────────────────────────── */

section {
  padding-block: clamp(3.5rem, 8vw, 6.5rem);
}

/* The nav is sticky, so an anchor jump parks the heading it was aimed at
   underneath it. Clearing the nav's own height plus a little air. */
section[id] {
  scroll-margin-top: 5.5rem;
}

.section-head {
  display: grid;
  gap: 1rem;
  max-width: 46rem;
}

.section-head h2 {
  margin-top: 0.35rem;
}

/* ── The measurement table ────────────────────────────────────────────────── */

.table-scroll {
  overflow-x: auto;
  margin-top: 2.5rem;
}

table {
  width: 100%;
  border-collapse: collapse;
  min-width: 34rem;
}

th,
td {
  text-align: left;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--line-hair);
}

thead th {
  font-family: var(--mono);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 400;
  color: var(--text-faint);
  border-bottom-color: var(--line-edge);
}

tbody td:first-child {
  color: var(--text-bright);
  font-weight: 550;
}

.col-num {
  text-align: right;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The rule goes on the value rather than on the cell. A cell's text-decoration
   propagates into its ::before, and the restacked mobile layout puts the column
   name there, so striking the cell strikes the word "Claimed" as well. */
td.claimed {
  color: var(--text-faint);
}

td.claimed span {
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}

td.real {
  color: var(--signal);
  font-weight: 600;
}

/* This table is the argument, so on a phone it restacks rather than scrolling
   sideways. A reader who has to drag the only two numbers on the page into
   view has been asked to work for the point being made. */
@media (max-width: 640px) {
  .table-scroll {
    overflow-x: visible;
  }

  table {
    min-width: 0;
  }

  thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  tbody tr {
    display: block;
    padding-block: 1.15rem;
    border-bottom: 1px solid var(--line-hair);
  }

  tbody td {
    border: 0;
    padding: 0.3rem 0;
    text-align: left;
  }

  /* Only the numeric cells become label-and-value rows. The directory cell
     stays a block, because as a flex container its inline `code` chip turns
     into a third flex item and space-between throws the three pieces of one
     sentence at opposite ends of the row. */
  tbody td[data-label] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
  }

  tbody td[data-label]::before {
    content: attr(data-label);
    font-family: var(--sans);
    font-size: 0.875rem;
    font-weight: 400;
    color: var(--text-dim);
  }
}

.table-note {
  margin-top: 1.5rem;
  color: var(--text-dim);
}

.prose {
  display: grid;
  gap: 1.15rem;
  margin-top: 2rem;
}

/* ── Tiers ──────────────────────────────────────────────────────────────── */

.tiers {
  display: grid;
  gap: 1rem;
  margin-top: 2.5rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.tier {
  padding: 1.35rem;
  display: grid;
  gap: 0.55rem;
  align-content: start;
}

.tier-name {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 650;
  letter-spacing: -0.02em;
  color: var(--text-bright);
}

.dot {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: none;
}

.tier-action {
  color: var(--text-body);
  font-size: 0.9375rem;
}

.tier-eg {
  color: var(--text-faint);
  font-size: 0.875rem;
  line-height: 1.5;
}

/* ── Evidence: two directories that look identical and are not ───────────── */

.proof {
  display: grid;
  gap: 1rem;
  margin-top: 2.5rem;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
}

.tree {
  padding: 1.35rem;
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.75;
  color: var(--text-dim);
}

.tree b {
  color: var(--text-bright);
  font-weight: 500;
}

.tree .verdict {
  display: block;
  margin-top: 1rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line-hair);
  font-family: var(--sans);
  font-size: 0.875rem;
  line-height: 1.5;
}

/* ── Figures ────────────────────────────────────────────────────────────── */

.figures {
  display: grid;
  gap: 1rem;
  margin-top: 2.5rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}

.figure {
  padding: 1.35rem;
}

.figure-value {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.75rem, 3.4vw, 2.25rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--text-bright);
  line-height: 1.1;
}

.figure-value.accent {
  color: var(--signal);
}

.figure-label {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: var(--text-dim);
  line-height: 1.5;
}

/* ── Detector list ──────────────────────────────────────────────────────── */

.finds {
  margin: 2.5rem 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line-hair);
}

.finds li {
  display: grid;
  gap: 0.35rem 2rem;
  grid-template-columns: minmax(11rem, 15rem) minmax(0, 1fr);
  padding: 1.25rem 0;
  border-bottom: 1px solid var(--line-hair);
}

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

.finds dt,
.finds .what {
  margin: 0;
}

.finds .what {
  color: var(--text-bright);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.finds .how {
  color: var(--text-dim);
  font-size: 0.9375rem;
  max-width: 60ch;
}

/* ── Download ───────────────────────────────────────────────────────────── */

.downloads {
  display: grid;
  gap: 1rem;
  margin-top: 2.5rem;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
}

.download {
  padding: 1.5rem;
  display: grid;
  gap: 0.7rem;
  align-content: start;
}

.download p {
  color: var(--text-dim);
  font-size: 0.9375rem;
}

.warn {
  margin-top: 2rem;
  padding: 1.25rem 1.4rem;
  border-radius: 12px;
  border: 1px solid rgb(201 166 60 / 0.28);
  background: rgb(201 166 60 / 0.07);
}

.warn h3 {
  color: #e6cf8a;
  margin-bottom: 0.4rem;
}

.warn p {
  color: var(--text-body);
  font-size: 0.9375rem;
}

/* ── Not found ──────────────────────────────────────────────────────────── */

.notfound {
  padding-block: clamp(4rem, 14vh, 9rem) clamp(5rem, 18vh, 11rem);
  max-width: 46rem;
  margin-inline: auto;
}

.notfound h1 {
  margin-top: 0.9rem;
  font-size: clamp(2.5rem, 5.5vw, 3.75rem);
}

.notfound .lede {
  margin-top: 1.25rem;
}

/* ── Footer ─────────────────────────────────────────────────────────────── */

footer {
  border-top: 1px solid var(--line-hair);
  padding-block: 3rem 4rem;
  color: var(--text-faint);
  font-size: 0.875rem;
}

.foot-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem 2.5rem;
  align-items: flex-start;
  justify-content: space-between;
}

footer p {
  max-width: 52ch;
  color: var(--text-faint);
}

footer .tagline {
  color: var(--text-dim);
  font-weight: 550;
}

/* ── Motion ─────────────────────────────────────────────────────────────────
   The reveal is decoration on a page that is entirely readable without it, so
   under reduced motion it does not play at all, and the markup ships visible
   so that a failed script cannot leave the page blank. */

.reveal {
  opacity: 1;
}

.js .reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

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

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

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

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