/* Vesper landing page — layout only. Every colour, size, space and radius
 * below resolves from a Nocturne token in nocturne.css.
 *
 * Written mobile-first: the single-column case is the base, then two media
 * queries for the only two structural changes the brief specifies —
 * capabilities to 2 columns at 768px, everything to its stated ratio at
 * 1024px. Type scales continuously via clamp() rather than per breakpoint. */

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

/* Header ---------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  /* Restored to what brief.md § 5 specifies. It was briefly removed while
     chasing rectangular tile artefacts, on the theory that backdrop-filter's
     composited layer caused them. A control page with no gradients, shadows,
     transparency, filters, blend modes, sticky positioning or webfont —
     nothing but flat #161826 and text — showed the same artefacts, and the
     stakeholder's own screenshot of the affected view is clean while a photo
     of the monitor is not. The artefact is therefore introduced after the
     frame buffer, in the display pipeline, and no CSS here causes it. */
  background: rgb(var(--rgb-bg) / 0.82);
  backdrop-filter: blur(14px);
  /* A permanent hairline. This was a CSS scroll-driven animation
     (animation-timeline: scroll()) that faded it in over the first 80px —
     removed: scroll-driven animations put the document scroller on the
     compositor, and that was one of only two rare features this page used
     while it showed rectangular tile artefacts that no other site did. Not
     worth a rendering risk for a line that appears one screen-height in. */
  border-bottom: 1px solid var(--color-divider);
}

.site-header .container {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding-block: var(--space-3);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-right: auto;
  color: var(--color-text);
  text-decoration: none;
}

.brand-mark {
  width: 22px;
  height: 22px;
  flex: none;
  border-radius: 3px;
  background: linear-gradient(140deg, var(--color-accent-400), var(--color-accent-700));
  transform: rotate(45deg);
  box-shadow: 0 0 18px rgb(var(--rgb-accent) / 0.45);
}

.brand-name {
  font-family: var(--font-heading);
  font-size: 19px;
  font-weight: 600; /* logotype, not a heading */
  letter-spacing: -0.01em;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--space-6);
}

/* Under 768px the nav is the wordmark plus the button — stated. */
.nav-link {
  display: none;
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
  text-decoration: none;
  transition: color var(--transition);
}

.nav-link:hover {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Hero ------------------------------------------------------------------ */

.hero {
  display: grid;
  gap: clamp(32px, 5vw, 56px);
  align-items: center;
  padding-block: var(--section-rhythm) var(--section-rhythm);
}

.hero-eyebrow {
  margin-bottom: var(--space-6);
}

.hero h1 {
  max-width: 15ch;
  margin-block: 0 22px;
}

.hero-lead {
  max-width: 46ch;
  margin-bottom: 34px;
  color: var(--color-text-muted);
  font-size: var(--fs-lead);
  line-height: 1.6;
  text-wrap: pretty;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.hero-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: var(--space-8);
}

/* Hero graphic — the page's signature, supplied as icon.svg (see
 * decisions.md). Vector, so it stays crisp at any size; only its box is set
 * here. Below the copy while stacked so the H1 leads, beside it at 1024px. */
.hero-art {
  display: block;
  width: 100%;
  /* height: auto is load-bearing, not tidiness: the <img> carries width/height
     attributes, and the height one applied and overrode aspect-ratio, so the
     square artwork rendered 425x466 — stretched 9.6% vertically, turning its
     circles into ovals. */
  height: auto;
  /* brief.md § 6 caps this at ~420px in the stacked bands; raised on the
     stakeholder's request to make the graphic bigger. */
  max-width: 470px;
  margin-inline: auto;
  aspect-ratio: 1;
}

/* Gradient dither ------------------------------------------------------- */

/* The two large gradient areas — the hero's glow and the contact wash — sweep
 * continuously between colours, so they necessarily pass through values a
 * 6-bit panel cannot show. Snapping fixes flat fills (see nocturne.css) but
 * cannot fix a ramp. A faint sheet of fractal noise gives the panel a colour
 * that already varies per pixel, so its own coarse dithering has no flat run
 * to break into blocks.
 *
 * Scoped to these two sections rather than the whole page: everywhere else is
 * now a snapped flat fill and needs nothing. Plain compositing, no blend mode.
 * Inline SVG, so no request and no asset. */
.hero,
.contact {
  position: relative;
}

.hero::after,
.contact::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.045;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
}

@media (prefers-reduced-transparency: reduce) {
  .hero::after,
  .contact::after {
    display: none;
  }
}

/* Capabilities ---------------------------------------------------------- */

.caps {
  padding-bottom: var(--section-rhythm);
}

.section-head {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: clamp(26px, 4vw, 38px);
}

.section-deck {
  max-width: 34ch;
  color: var(--color-text-muted);
  font-size: 15px;
  text-wrap: pretty;
}

.caps-grid {
  display: grid;
  gap: clamp(14px, 2vw, 20px);
}

.cap-card {
  gap: var(--space-4);
  padding: var(--space-6); /* 26px — stated */
  transition: border-color var(--transition);
}

.cap-card:hover {
  border-color: rgb(var(--rgb-accent) / 0.3);
}

.cap-kicker {
  font-family: var(--font-heading);
  font-size: var(--fs-2xs);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent);
}

.cap-card p {
  color: var(--color-text-muted);
  font-size: 14px;
  line-height: 1.6;
}

.cap-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-4);
}

/* Why ------------------------------------------------------------------- */

.why {
  display: grid;
  gap: clamp(28px, 4vw, 56px);
  align-items: start;
  padding-bottom: var(--section-rhythm);
}

.why-intro {
  max-width: 38ch;
  margin-top: var(--space-4);
  color: var(--color-text-muted);
  line-height: 1.65;
  text-wrap: pretty;
}

/* Rows, not cards — the structural contrast with the capabilities grid. */
.why-list {
  display: grid;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: why;
}

.why-row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-5);
  padding-block: 22px;
  border-top: 1px solid var(--color-divider);
  counter-increment: why;
}

.why-row:last-child {
  border-bottom: 1px solid var(--color-divider);
}

.why-row::before {
  content: "0" counter(why) / ""; /* empty alt: decorative to a screen reader */
  font-family: var(--font-heading);
  font-size: var(--fs-xs);
  color: var(--color-accent);
}

.why-row h3 {
  margin-bottom: 6px;
  font-size: var(--fs-h4);
}

.why-row p {
  /* Capped measure: without it the row runs to ~90 characters in the stacked
     bands, where it has the full container width to itself. In em, not ch —
     Inter's '0' is wide, so 72ch computes to ~658px here and constrains
     nothing. 36em lands around 70 characters. */
  max-width: 36em;
  color: var(--color-text-muted);
  font-size: var(--fs-sm);
  line-height: 1.6;
}

/* Contact --------------------------------------------------------------- */

.contact {
  border-top: 1px solid var(--color-divider);
  background: linear-gradient(
    180deg,
    rgb(var(--rgb-accent) / 0.07),
    transparent 55%
  );
}

.contact .container {
  display: grid;
  gap: clamp(32px, 5vw, 64px);
  align-items: start;
  padding-block: var(--section-rhythm);
}

.contact-lead {
  max-width: 34ch;
  margin-block: var(--space-4) 28px;
  color: var(--color-text-muted);
  line-height: 1.65;
  text-wrap: pretty;
}

.contact-note {
  color: var(--color-text-muted);
  font-size: 13.5px;
}

.contact-card {
  padding: clamp(20px, 4vw, 32px); /* 32px at desktop — stated */
  border-radius: var(--radius-lg); /* stated */
}

.contact-form {
  display: grid;
  gap: var(--space-4);
}

.field-pair {
  display: grid;
  gap: var(--space-4);
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: center;
  margin-top: var(--space-1);
}

.form-privacy {
  color: var(--color-text-muted);
  font-size: 12.5px;
}

.form-error {
  color: var(--color-accent-300);
  font-size: var(--fs-sm);
}

/* Success state — replaces the form in place, no reload. */
.contact-success {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  padding-block: 18px;
}

.contact-success h3 {
  font-size: 24px;
}

.contact-success p {
  max-width: 42ch;
  color: var(--color-text-muted);
  font-size: var(--fs-sm);
}

.contact-success h3:focus-visible {
  outline-offset: 6px;
}

/* Footer ---------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--color-divider);
}

.site-footer .container {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding-block: var(--space-6);
  color: var(--color-text-muted);
  font-size: var(--fs-xs);
}

.footer-brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--color-text);
}

.footer-mark {
  width: 14px;
  height: 14px;
  border-radius: 2px;
  background: linear-gradient(140deg, var(--color-accent-400), var(--color-accent-700));
  transform: rotate(45deg);
}

.footer-name {
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 600;
}

/* 768px — capabilities to 2 columns, nav links return, form to 2 columns,
 * footer to one row. Stated. */
@media (min-width: 768px) {
  .nav-link {
    display: inline-flex;
  }

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

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

  .site-footer .container {
    flex-direction: row;
    align-items: center;
    gap: var(--space-6);
  }

  .footer-brand {
    margin-right: auto;
  }
}

/* 1024px — the four stated column ratios. */
@media (min-width: 1024px) {
  .hero {
    grid-template-columns: 1.15fr 0.85fr;
  }

  .hero-art {
    max-width: none;
    /* A little larger than its grid column, bled symmetrically. 6% a side is
       the most that is safe: at 1024px the column's right edge is the
       container's, so the bleed eats the 32px page padding — 6% of a 384px
       column is 23px, leaving 9px. The artwork carries ~10% empty margin
       inside its own viewBox, so this grows the visible circle without
       crowding the copy. */
    width: 112%;
    margin-inline: -6%;
  }

  .caps-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .why {
    grid-template-columns: 0.9fr 1.1fr;
  }

  .why > div:first-child {
    position: sticky;
    top: 108px;
  }

  .contact .container {
    grid-template-columns: 0.85fr 1.15fr;
  }
}
