/* ==========================================================================
   RPSoft - site stylesheet

   One stylesheet for the whole site. No JS anywhere, no third-party requests.
   The tokens below are the only place colour and rhythm are defined.

   The palette is lifted from the applications themselves so the site and the
   products read as one thing:
     --surface     Tessera treemap background   (UI/TreemapControl.cs)
     --surface-2   Tessera directory border
     --accent      Tessera selection accent
     --accent-net  NetScanner "host online" dot
   ========================================================================== */

:root {
  /* Dark-only site. Without this, form controls, scrollbars and the like render
     in the browser's light defaults against a dark page. */
  color-scheme: dark;

  /* Colour */
  --bg:          #0f1114;
  --surface:     #14161a;
  --surface-2:   #1e2125;
  --line:        #2a2e35;
  --line-soft:   #21242a;
  --text:        #e8eaed;
  --text-dim:    #9aa1ab;
  /* #6b727c measured 3.89:1 on --bg and 3.73:1 on --surface, failing WCAG AA for
     normal text. It carries CTA microcopy, figure captions, the footer and table
     headers, so it has to pass: this is 4.81:1 and 4.61:1. */
  --text-faint:  #7a818c;

  --accent:         #00b0ff;   /* site default, and Tessera */
  --accent-ink:     #04202b;   /* text placed on top of --accent */
  /* Per-product tokens below are never overridden, so a product card keeps its own
     colour even inside another product's page (the cross-sell blocks). */
  --accent-tess:    #00b0ff;
  --accent-net:     #2ecc71;   /* NetScanner */
  --accent-ink-net: #06240f;
  --accent-amp:     #3ee07e;   /* Ampere */
  --accent-ink-amp: #052414;
  --warn:           #e2b341;

  /* Type. Inter first to match both apps, falling back to the system stack
     so the site never makes a network request for a font. */
  --font: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas,
          "Liberation Mono", monospace;

  /* Rhythm */
  --measure:   68rem;
  --narrow:    46rem;
  --pad:       clamp(1.25rem, 4vw, 2.5rem);
  --gap:       1.5rem;
  --radius:    10px;
  --radius-sm: 6px;
}

/* Per-product accent. Set with <body data-product="netscanner">. */
[data-product="netscanner"] {
  --accent: var(--accent-net);
  --accent-ink: var(--accent-ink-net);
}

/* Ampere's own green (Styles/Theme.axaml) — close to NetScanner's, which is why
   the hub tells them apart with the Free badge rather than by hue. 10.96:1 on the
   page background. */
[data-product="ampere"] {
  --accent: var(--accent-amp);
  --accent-ink: var(--accent-ink-amp);
}

/* ---------------------------------------------------------------- reset -- */

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: clamp(1rem, 0.97rem + 0.15vw, 1.0625rem);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

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

h1, h2, h3 {
  line-height: 1.2;
  letter-spacing: -0.02em;
  margin: 0 0 0.5em;
  font-weight: 600;
}
h1 { font-size: clamp(2rem, 1.4rem + 2.9vw, 3.25rem); letter-spacing: -0.03em; }
h2 { font-size: clamp(1.45rem, 1.25rem + 1vw, 2rem); }
h3 { font-size: 1.125rem; }
p  { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

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

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

code, kbd, samp, pre { font-family: var(--mono); font-size: 0.9em; }

code {
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  border-radius: 4px;
  padding: 0.1em 0.4em;
  color: var(--text);
}

pre {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 1rem 1.15rem;
  overflow-x: auto;
  margin: 0 0 1.25rem;
}
pre code { background: none; border: 0; padding: 0; }

hr { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* ------------------------------------------------------------- skiplink -- */

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: var(--accent-ink);
  padding: 0.7rem 1.1rem;
  font-weight: 600;
  border-radius: 0 0 var(--radius-sm) 0;
  z-index: 100;
}
.skip:focus { left: 0; }

/* --------------------------------------------------------------- layout -- */

.wrap {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--pad);
}
/* Narrow text sections keep the page's outer container so their left edge
   lines up with the hero, and cap the reading measure on the children
   instead of re-centring a narrower box. */
.wrap--narrow > * { max-width: var(--narrow); }

section { padding-block: clamp(3rem, 7vw, 5.5rem); }
section + section { border-top: 1px solid var(--line-soft); }

.stack > * + * { margin-top: 1.5rem; }

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

.site-head {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line-soft);
}

.site-head > .wrap {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  min-height: 60px;
  flex-wrap: wrap;
}

.wordmark {
  font-weight: 600;
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
  color: var(--text);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  flex: none;
}
.wordmark::before {
  content: "";
  width: 11px;
  height: 11px;
  border-radius: 2px;
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

.site-nav {
  margin-left: auto;
  display: flex;
  flex-wrap: wrap;          /* must wrap, or the nav forces the page wider than a phone */
  gap: 0.5rem 1.35rem;
  align-items: center;
  font-size: 0.9375rem;
  padding-bottom: 0.35rem;
}

/* On a narrow screen the nav drops to its own full-width row under the
   wordmark rather than being squeezed against it. */
@media (max-width: 32rem) {
  .site-nav { margin-left: 0; width: 100%; padding-bottom: 0.75rem; }
  .site-head > .wrap { padding-top: 0.75rem; }
}
.site-nav a {
  color: var(--text-dim);
  text-decoration: none;
  white-space: nowrap;
}
.site-nav a:hover { color: var(--text); }
.site-nav a[aria-current="page"] { color: var(--text); }

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

.hero {
  position: relative;
  padding-block: clamp(3.5rem, 9vw, 7rem) clamp(2.5rem, 6vw, 4rem);
  overflow: hidden;
}
.hero::before {
  content: "";
  position: absolute;
  inset: -40% 0 auto;
  height: 520px;
  background: radial-gradient(
    ellipse 60% 100% at 50% 0%,
    color-mix(in srgb, var(--accent) 13%, transparent),
    transparent 70%
  );
  pointer-events: none;
}
.hero > * { position: relative; }

/* A hero with no CTA row (the hub, where the cards below are the call to action)
   would otherwise leave a large dead gap under the lede. */
.hero--bare { padding-bottom: 0; }
.hero--bare + section { padding-top: clamp(2rem, 4vw, 3rem); }

.hero .lede {
  font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.3125rem);
  color: var(--text-dim);
  max-width: 46ch;
  margin-bottom: 2rem;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 1rem;
}

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

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  align-items: center;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font: inherit;
  font-weight: 600;
  padding: 0.75rem 1.35rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  border: 1px solid transparent;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.btn--buy {
  background: var(--accent);
  color: var(--accent-ink);
}
.btn--buy:hover {
  background: color-mix(in srgb, var(--accent) 85%, white);
  transform: translateY(-1px);
}
.btn--ghost {
  border-color: var(--line);
  color: var(--text);
  background: var(--surface);
}
.btn--ghost:hover { border-color: var(--text-faint); background: var(--surface-2); }

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

/* ---------------------------------------------------------------- chips -- */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.chips li {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  color: var(--text-dim);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: 0.2rem 0.7rem;
}

/* ----------------------------------------------------------------- shot -- */

figure.shot { margin: 0; }

figure.shot img {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: 0 24px 60px -20px rgb(0 0 0 / 0.75);
}

figure.shot video {
  width: 100%;
  height: auto;             /* without this the height attribute letterboxes it */
  display: block;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: 0 24px 60px -20px rgb(0 0 0 / 0.75);
}

/* An autoplaying loop is motion the viewer did not ask for. With no JS on the
   site, the swap is done in CSS: reduced-motion gets the final frame as a
   still image instead. */
.motion-still { display: none; }

@media (prefers-reduced-motion: reduce) {
  /* Must out-specify `figure.shot video` above, or the video stays visible
     and the viewer gets both it and the still. */
  figure.shot video.motion-video { display: none; }
  .motion-still { display: block; }
}

figure.shot figcaption {
  margin-top: 0.85rem;
  font-size: 0.875rem;
  color: var(--text-faint);
  text-align: center;
}

.shot--bleed { max-width: 78rem; margin-inline: auto; }

/* Ampere's window is 330x128. Its screenshots are captured at that size, so they are
   shown at it — upscaling a 330px image to 1200px would be a blurry mess, and the
   true size makes the "small on purpose" point better than the caption does. */
.stage {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(2rem, 7vw, 5rem) 1.25rem;
  display: grid;
  place-items: center;
  gap: 1.5rem;
}

figure.shot--actual img {
  width: auto;
  max-width: 100%;
  margin-inline: auto;
  border: 0;
  border-radius: 4px;
  box-shadow: 0 16px 44px -14px rgb(0 0 0 / 0.85);
}

/* Two true-size shots on one stage — the playlist and equalizer drawers, shown
   together because only one of them can be open at a time. Wraps to stacked on a
   narrow screen; neither image is ever scaled up. */
.stage--pair { padding-inline: clamp(1rem, 4vw, 2.5rem); }

.stage__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: center;
  gap: clamp(1.5rem, 4vw, 3rem);
  width: 100%;
}

/* ---------------------------------------------------------------- cards -- */

/* auto-fit: a third or fourth product needs no CSS change */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--gap);
}
.grid--tight { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 1rem; }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

a.card {
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
a.card:hover {
  border-color: color-mix(in srgb, var(--card-accent, var(--accent)) 55%, var(--line));
  transform: translateY(-2px);
}

.card h3 { margin: 0; font-size: 1.25rem; }
.card p { color: var(--text-dim); margin: 0; }
.card .go {
  margin-top: auto;
  padding-top: 0.35rem;
  color: var(--card-accent, var(--accent));
  font-weight: 600;
  font-size: 0.9375rem;
}

/* Product cards carry their own accent, so the hub previews each product. */
.card--tessera    { --card-accent: var(--accent-tess); }
.card--netscanner { --card-accent: var(--accent-net); }
.card--ampere     { --card-accent: var(--accent-amp); }

.card__title {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

/* Free vs paid is the distinction a visitor actually cares about — it carries more
   weight here than the two greens being similar. */
.badge-free {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--card-accent, var(--accent));
  background: color-mix(in srgb, var(--card-accent, var(--accent)) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-accent, var(--accent)) 45%, transparent);
  border-radius: 100px;
  padding: 0.15rem 0.6rem;
  white-space: nowrap;
}

.card__mark {
  width: 34px;
  height: 34px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--card-accent, var(--accent)) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-accent, var(--accent)) 40%, transparent);
  display: grid;
  place-items: center;
}
.card__mark svg { width: 18px; height: 18px; display: block; }

/* --------------------------------------------------------------- points -- */

.points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: 1.25rem 2rem;
}
/* For short lists in a full-width container: caps at two columns so a
   four-item list lands as a clean 2x2 rather than 3 plus an orphan. */
.points--duo { grid-template-columns: repeat(auto-fit, minmax(min(100%, 27rem), 1fr)); }

.points li { padding-left: 1.35rem; position: relative; color: var(--text-dim); }
.points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 6px;
  height: 6px;
  border-radius: 2px;
  background: var(--accent);
}
.points li strong { color: var(--text); font-weight: 600; }

/* ---------------------------------------------------------------- table -- */

.table-scroll { overflow-x: auto; }

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
  min-width: 34rem;
}
caption {
  text-align: left;
  color: var(--text-faint);
  font-size: 0.875rem;
  padding-bottom: 0.75rem;
}
th, td {
  text-align: left;
  padding: 0.75rem 1rem 0.75rem 0;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: top;
}
th {
  color: var(--text);
  font-weight: 600;
  white-space: nowrap;
}
thead th {
  border-bottom-color: var(--line);
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
td { color: var(--text-dim); }
tbody tr:last-child th, tbody tr:last-child td { border-bottom: 0; }

/* spec table: key/value, no header row */
.specs { min-width: 0; }
.specs th { width: 40%; color: var(--text-dim); font-weight: 400; white-space: normal; }
.specs td { color: var(--text); }

/* -------------------------------------------------------------- callout -- */

.callout {
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  background: var(--surface);
  border-radius: var(--radius-sm);
  padding: 1.25rem 1.4rem;
}
.callout h3 { margin-top: 0; }
.callout--warn { border-left-color: var(--warn); }
.callout--warn h3 { color: var(--warn); }

/* ------------------------------------------------------------------ faq -- */

.faq { border-top: 1px solid var(--line-soft); }
.faq > div {
  border-bottom: 1px solid var(--line-soft);
  padding-block: 1.5rem;
}
.faq h3 { margin-bottom: 0.4rem; }
.faq p { color: var(--text-dim); }

/* ------------------------------------------------------------- cta band -- */

.band {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(1.75rem, 5vw, 3rem);
  text-align: center;
}
.band h2 { margin-bottom: 0.4rem; }
.band p { color: var(--text-dim); max-width: 44ch; margin-inline: auto; }
.band .cta-row { justify-content: center; margin-top: 1.5rem; }

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

.site-foot {
  border-top: 1px solid var(--line);
  padding-block: 2.5rem 3rem;
  font-size: 0.9375rem;
  color: var(--text-faint);
}
.site-foot .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 2.5rem;
  align-items: baseline;
}
.site-foot nav {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-left: auto;
}
.site-foot a { color: var(--text-dim); text-decoration: none; }
.site-foot a:hover { color: var(--text); text-decoration: underline; }

/* ---------------------------------------------------------------- prose -- */

.prose h2 { margin-top: 2.5rem; }
.prose h2:first-child { margin-top: 0; }
.prose ul { color: var(--text-dim); padding-left: 1.2rem; }
.prose li { margin-bottom: 0.5rem; }
.prose li strong { color: var(--text); }

.updated {
  font-size: 0.875rem;
  color: var(--text-faint);
  font-family: var(--mono);
}
