/* Helve marketing site.

   ---------- fonts ----------
   Self-hosted, as BRAND.md requires: neither family is installed by default
   anywhere, so without these the page silently renders in the fallbacks and
   nothing about it is the brand's typography. Both are SIL OFL 1.1; the
   licence texts ship alongside the files in fonts/, which the OFL asks for.

   Archivo is one file, not two. Google serves it as a variable font, so a
   single woff2 covers the whole weight axis and `font-weight: 400 500` tells
   the browser to instance from it rather than fetch a second face. Commit
   Mono is static and does need one file per weight.

   Two weights only, 400 and 500 — BRAND.md: "Nothing heavier." Anything that
   asks for 600+ will be synthesised, which is the visible symptom that a
   rule got broken rather than a silent one.

   font-display: swap — text is readable in the fallback immediately and
   reflows once the face arrives. On a page that is mostly prose, a blocking
   invisible-text period is the worse trade. */

@font-face {
  font-family: "Archivo";
  src: url("fonts/archivo-latin-variable.woff2") format("woff2-variations");
  font-weight: 400 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Commit Mono";
  src: url("fonts/commit-mono-latin-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Commit Mono";
  src: url("fonts/commit-mono-latin-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* ---------- colour ----------
   Colour comes entirely from design/tokens.css, which index.html loads first.
   Nothing below introduces a hex value; the block under :root only maps the
   brand's tokens onto the names this stylesheet uses, and derives the two
   values the brand doesn't ship (a grid line and a bloom) with color-mix from
   tokens that it does. Per design/BRAND.md, tokens.css is the single source of
   colour truth — if something here needs a colour that isn't reachable from a
   token, that is a signal the design is wrong. */

:root {
  /* surfaces — the brand ships exactly two, base and raised, so that is what
     the page uses. Alt sections take the base tone and are separated by their
     border; cards take the raised tone and lift off it. */
  --page: var(--helve-base);
  --surface: var(--helve-raised);
  --border: var(--helve-border);

  /* ink — three levels out of the brand's two. Secondary is the body tone
     stepped toward the page rather than a third colour. */
  --text-primary: var(--helve-text);
  --text-secondary: color-mix(in srgb, var(--helve-text) 80%, var(--helve-base));
  --text-muted: var(--helve-muted);

  --accent: var(--helve-accent);
  --accent-ink: var(--helve-accent-on);

  --radius-sm: var(--helve-radius);
  --radius-lg: var(--helve-radius-lg);

  --wrap: 1120px;

  /* Background. A fine graph-paper grid — structure, which suits a tool for
     infrastructure — plus one warm bloom behind the hero.

     Deliberately one hue: BRAND.md forbids a second accent, so the previous
     blue-and-violet pair is gone, and with it the starfield. That treatment
     belonged to a name that meant the upper air. This one is an axe. */
  --grid-line: color-mix(in srgb, var(--helve-text) 4%, transparent);
  --grid-size: 56px;
  --glow: color-mix(in srgb, var(--helve-accent) 13%, transparent);
  --veil: 88%;

  color-scheme: dark;
}

:root[data-theme="light"] {
  color-scheme: light;
  /* Tobacco on near-white carries far more weight than straw on near-black,
     so the bloom drops rather than being inherited at the same strength. */
  --grid-line: color-mix(in srgb, var(--helve-text) 6%, transparent);
  --glow: color-mix(in srgb, var(--helve-accent) 7%, transparent);
  --veil: 82%;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; animation: none !important; }
}

body {
  margin: 0;
  background: var(--page);
  color: var(--text-primary);
  font-family: var(--helve-sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* ---------- background ----------
   One fixed layer behind everything. Fixed rather than scrolling so it reads
   as a backdrop the content moves across.

   pointer-events:none matters — a full-viewport fixed layer would otherwise
   swallow every click on the page. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
  background-size: var(--grid-size) var(--grid-size);
}

/* Bands let the grid through, so the pattern is continuous down the page
   instead of appearing only in the gaps. Cards stay fully opaque, so body
   text never sits on a patterned surface. */
.band,
.section-alt,
.footer {
  background: color-mix(in srgb, var(--page) var(--veil), transparent);
}

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.wrap.narrow { max-width: 760px; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

code {
  font-family: var(--helve-mono);
  font-size: 0.9em;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1px 5px;
}

.skip {
  position: absolute; left: -9999px;
  background: var(--accent); color: var(--accent-ink);
  padding: 10px 16px; border-radius: var(--radius-sm); z-index: 100;
}
.skip:focus { left: 16px; top: 16px; }

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

/* ---------- nav ---------- */

.nav {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--page) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.nav-inner { display: flex; align-items: center; gap: 24px; height: 62px; }

.brand { display: inline-flex; align-items: center; gap: 9px; color: var(--text-primary); }
.brand:hover { text-decoration: none; }
.brand-name { font-weight: 500; letter-spacing: -0.01em; }

/* The mark is inlined rather than an <img> because the artwork is
   fill="currentColor" — an <img> has no access to the inherited colour and
   would render it black in both themes. Inlining is also what lets it take
   the accent on hover. It is the favicon variant, per BRAND.md: below 48px
   the full-detail mark's waist and beard close up. */
.brand-mark { display: block; flex: none; width: auto; height: 26px; color: var(--text-primary); }
.brand:hover .brand-mark { color: var(--accent); }

.footer-brand { display: inline-flex; align-items: center; gap: 8px; }
.footer-brand .brand-mark { height: 22px; }

.nav-links { display: flex; gap: 22px; margin-left: auto; }
.nav-links a { color: var(--text-secondary); font-size: 14px; }
.nav-links a:hover { color: var(--text-primary); text-decoration: none; }

.nav-actions { display: flex; align-items: center; gap: 10px; }

.icon-btn {
  width: 34px; height: 34px; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text-secondary); cursor: pointer; font-size: 14px;
}
.icon-btn:hover { color: var(--text-primary); }

.btn {
  display: inline-block; padding: 9px 16px; border-radius: var(--radius-sm);
  font-size: 14px; font-weight: 500; border: 1px solid transparent;
  cursor: pointer; font-family: inherit;
}
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { filter: brightness(1.08); }
.btn-ghost {
  background: var(--surface); color: var(--text-primary);
  border-color: var(--border);
}
.btn-ghost:hover { border-color: var(--accent); }

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

.hero {
  position: relative;
  padding: 96px 0 72px;
  text-align: center;
  /* Own stacking context, so the z-index:-1 layer below sits above the
     page-wide grid but still behind this section's own text. */
  isolation: isolate;
  overflow: hidden;
}

/* One bloom, offset, large radius and low alpha — depth behind the headline
   rather than a coloured panel. */
.hero::before {
  content: "";
  position: absolute;
  inset: -25% -10% 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(55% 60% at 28% 8%, var(--glow), transparent 70%),
    radial-gradient(45% 45% at 76% 2%, var(--glow), transparent 72%);
  animation: drift 34s ease-in-out infinite alternate;
}

@keyframes drift {
  from { transform: translate3d(-1.5%, -1%, 0) scale(1); }
  to   { transform: translate3d(1.5%, 1.5%, 0) scale(1.06); }
}

.eyebrow { display: flex; gap: 8px; justify-content: center; margin: 0 0 28px; }

/* Quiet only. Hickory means "you can act on this"; a version badge is not an
   affordance, so these carry no accent. */
.pill {
  font-size: 12px; font-family: var(--helve-mono);
  padding: 4px 10px; border-radius: 999px;
  background: var(--surface); color: var(--text-muted);
  border: 1px solid var(--border);
}

h1 {
  font-size: clamp(34px, 6vw, 58px);
  line-height: 1.1; letter-spacing: -0.03em;
  margin: 0 0 22px; font-weight: 500;
}

.lede {
  font-size: clamp(17px, 2.2vw, 20px);
  color: var(--text-secondary);
  max-width: 640px; margin: 0 auto 34px;
}
.lede strong { color: var(--text-primary); font-weight: 500; }

.cta { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.hero-note { margin-top: 22px; font-size: 14px; color: var(--text-muted); }

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

.band { border-block: 1px solid var(--border); }
.logos {
  display: flex; align-items: center; justify-content: center;
  gap: 28px; padding: 20px 24px; flex-wrap: wrap;
}
/* Sentence case, not tracked-out caps — see BRAND.md, Voice. */
.logo-label { font-size: 13px; color: var(--text-muted); }
.logo-list {
  display: flex; gap: 26px; list-style: none; margin: 0; padding: 0; flex-wrap: wrap;
}
.logo-list li {
  font-family: var(--helve-mono); font-size: 14px; color: var(--text-secondary);
}

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

.section { padding: 84px 0; }
.section-alt { border-block: 1px solid var(--border); }

h2 {
  font-size: clamp(26px, 3.6vw, 36px);
  letter-spacing: -0.02em; margin: 0 0 20px; font-weight: 500;
}
.section-title { text-align: center; margin-bottom: 16px; }

.body { color: var(--text-secondary); font-size: 17px; margin: 0 0 18px; }
.body.center { text-align: center; max-width: 680px; margin: 0 auto 40px; }
.body strong { color: var(--text-primary); font-weight: 500; }

.muted { color: var(--text-muted); }
.small { font-size: 14px; }

/* ---------- feature grid ---------- */

/* min() on the track floor, and min-width:0 on the items. Without both, a
   grid child refuses to shrink below its content (min-width defaults to
   auto) and a track floor wider than a phone viewport overflows the page —
   which silently clips every section, not just the grid. */
.grid {
  display: grid; gap: 16px; margin-top: 44px;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
}
.grid > *, .install > *, .split > * { min-width: 0; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 24px;
  transition: border-color 140ms ease, transform 140ms ease;
}
.card:hover { border-color: var(--accent); transform: translateY(-2px); }
.card h3 { font-size: 16px; margin: 0 0 10px; font-weight: 500; }
.card p { margin: 0; color: var(--text-secondary); font-size: 15px; }

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

.split {
  display: grid; gap: 40px; margin-top: 40px;
  grid-template-columns: 1.15fr 0.85fr; align-items: start;
}
@media (max-width: 860px) { .split { grid-template-columns: 1fr; } }

.checklist {
  list-style: none; margin: 0; padding: 24px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.checklist li {
  position: relative; padding-left: 26px; margin-bottom: 12px;
  color: var(--text-secondary); font-size: 15px;
}
.checklist li:last-child { margin-bottom: 0; }
/* Muted, not a status colour. These are claims about the design, not the
   state of anything running. */
.checklist li::before {
  content: "✓"; position: absolute; left: 0; top: -1px;
  color: var(--text-muted);
}

/* ---------- figure ---------- */

.figure { margin: 0; }
.figure img {
  width: 100%; height: auto; display: block;
  border: 1px solid var(--border); border-radius: var(--radius-lg);
}
figcaption { margin-top: 14px; text-align: center; font-size: 14px; }

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

.install {
  display: grid; gap: 20px; margin-top: 40px;
  grid-template-columns: repeat(auto-fit, minmax(min(360px, 100%), 1fr));
}
.install-block h3 { font-size: 17px; margin: 0 0 6px; font-weight: 500; }
.install-block .muted { font-size: 14px; margin: 0 0 14px; }

pre {
  position: relative; margin: 0; max-width: 100%;
  background: var(--page); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 18px;
  overflow-x: auto;
}
pre code {
  background: none; border: none; padding: 0;
  font-size: 13px; line-height: 1.7; color: var(--text-secondary);
  white-space: pre;
}

.copy {
  position: absolute; top: 10px; right: 10px;
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text-muted); border-radius: var(--radius-sm);
  padding: 4px 10px; font-size: 12px; cursor: pointer;
  font-family: inherit;
}
.copy:hover { color: var(--text-primary); }
/* The one legitimate status use on this page: it reports an outcome. */
.copy[data-copied] { color: var(--helve-running); border-color: var(--helve-running); }

.reqs {
  margin-top: 44px; padding: 26px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.reqs h3 { margin: 0 0 14px; font-size: 17px; font-weight: 500; }
.reqs ul { margin: 0 0 16px; padding-left: 20px; color: var(--text-secondary); }
.reqs li { margin-bottom: 8px; font-size: 15px; }

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

.footer { border-top: 1px solid var(--border); padding: 40px 0; }
.footer-inner {
  display: flex; justify-content: space-between; gap: 24px;
  align-items: flex-start; flex-wrap: wrap;
}
.footer-inner p { margin: 8px 0 0; }
.footer nav { display: flex; gap: 20px; flex-wrap: wrap; }
.footer nav a { color: var(--text-secondary); font-size: 14px; }

@media (max-width: 720px) {
  .nav-links { display: none; }
  .hero { padding: 64px 0 52px; }
  .section { padding: 60px 0; }
}
