/*
  Header, hero and portfolio cards from the Cruip Stellar theme (stellar-html), reduced to what
  this page uses and recolored teal. Licensed, see CRUIP-LICENSE.md beside this file.
*/

:root {
  --page: #0f172a;
  --text: #f1f5f9;
  --text-muted: #cbd5e1;
  --lead: #e2e8f0;
  --text-strong: #ffffff;
  --accent: #2dd4bf;
  --accent-strong: #14b8a6;
  --accent-soft: #99f6e4;
  --accent-glow: rgb(20 184 166 / 0.45);
  --eyebrow-bg: #1e293b;
  --heading: #e2e8f0;
  --heading-edge: rgb(226 232 240 / 0.7);
  --btn: #ffffff;
  --btn-edge: rgb(255 255 255 / 0.8);
  --btn-text: #0f172a;
  --btn-arrow: #0f766e;
  --rule-strong: #334155;
  --glow-opacity: 0.6;
  --card: #0f172a;
  --card-edge: #1e293b;
  --card-edge-hover: #334155;
  --card-glow: rgb(20 184 166 / 0.25);
  --card-spot: #94a3b8;
  --star-rgb: 255 255 255;
  color-scheme: dark;
}

@media (prefers-color-scheme: light) {
  :root {
    --page: #f8fafc;
    --text: #0f172a;
    --text-muted: #475569;
    --lead: #475569;
    --text-strong: #020617;
    --accent: #0d9488;
    --accent-strong: #0d9488;
    --accent-soft: #5eead4;
    --accent-glow: rgb(20 184 166 / 0.3);
    --eyebrow-bg: #ffffff;
    --heading: #0f172a;
    --heading-edge: rgb(15 23 42 / 0.7);
    --btn: #0f172a;
    --btn-edge: rgb(15 23 42 / 0.85);
    --btn-text: #ffffff;
    --btn-arrow: #5eead4;
    --rule-strong: #cbd5e1;
    --glow-opacity: 0.35;
    --card: #ffffff;
    --card-edge: #e2e8f0;
    --card-edge-hover: #cbd5e1;
    --card-glow: rgb(20 184 166 / 0.1);
    --card-spot: #0d9488;
    --star-rgb: 13 148 136;
    color-scheme: light;
  }

  /* White cards on a near white page need a soft shadow to stand off it. */
  .card {
    box-shadow: 0 1px 2px rgb(15 23 42 / 0.04), 0 8px 24px -12px rgb(15 23 42 / 0.12);
  }
}

/* Inter 4.1 variable, roman, Latin subset. SIL Open Font License, see fonts/INTER-LICENSE.txt. */
@font-face {
  font-family: Inter;
  src: url("fonts/InterVariable-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

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

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

body {
  margin: 0;
  background: var(--page);
  color: var(--text);
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-feature-settings: "calt", "cv11";
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
}

a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 0.125rem;
}

.container {
  max-width: 72rem;
  margin: 0 auto;
  padding: 0 1rem;
}

/* Header */
.site-header {
  position: absolute;
  z-index: 30;
  width: 100%;
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 4rem;
}

.wordmark {
  font-size: 1.125rem;
  font-weight: 800;
  color: var(--text);
  text-decoration: none;
}

.nav-list {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-list a {
  display: inline-block;
  padding: 0.75rem 0.25rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-muted);
  text-decoration: none;
}

.nav-list a:hover {
  color: var(--text-strong);
}

main {
  position: relative;
  isolation: isolate;
}

/* Stars from particles.js, behind the content of whatever holds them. */
.particles {
  position: absolute;
  z-index: -1;
  inset: 0;
  pointer-events: none;
}

/* Card stars show only on the active card and on hover, as in Stellar's carousel. */
.card .particles {
  opacity: 0;
  transition: opacity 500ms ease-in-out;
}

.cards:not([data-ready]) .card:first-child .particles,
.card.is-active .particles,
.card:hover .particles {
  opacity: 1;
}

/* Stellar's blurred shape: a soft diagonal beam that rises from lower left toward the first card. */
.beam {
  position: absolute;
  z-index: -1;
  top: calc(100% - 4.5rem);
  left: -4rem;
  opacity: 0.7;
  filter: blur(40px);
  pointer-events: none;
}

/* The hero stars span the full width, behind the header, and run a little past the glow. */
.particles--hero {
  inset: auto;
  top: 0;
  left: 0;
  width: 100%;
  height: 38rem;
}

/* Hero */
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

.hero > .container {
  position: relative;
}

/*
  Spans the full width and fades out toward both sides and softly at the bottom, so no edge or
  corner shows at any width. The stock near-white core is dropped and the whole glow dimmed.
*/
.hero__glow {
  --fade-x: linear-gradient(to right, transparent, #000 30%, #000 70%, transparent);
  --fade-y: linear-gradient(to bottom, #000 60%, transparent);
  position: absolute;
  z-index: -1;
  inset: 0;
  pointer-events: none;
  opacity: var(--glow-opacity);
  background: url("glow-bottom.svg") center bottom / 2146px 744px no-repeat;
  -webkit-mask-image: var(--fade-x), var(--fade-y);
  -webkit-mask-composite: source-in;
  mask-image: var(--fade-x), var(--fade-y);
  mask-composite: intersect;
}

.hero__content {
  max-width: 48rem;
  margin: 0 auto;
  padding: 8rem 0 4rem;
  text-align: center;
}

.eyebrow {
  margin: 0 0 1.5rem;
}

.eyebrow span {
  display: inline-flex;
  padding: 0.125rem 0.75rem;
  border: 1px solid transparent;
  border-radius: 9999px;
  background:
    linear-gradient(var(--eyebrow-bg), var(--eyebrow-bg)) padding-box,
    linear-gradient(var(--accent-strong), var(--accent-soft) 75%, transparent) border-box;
  box-shadow: 0 0 12px var(--accent-glow);
  color: var(--text-muted);
  font-size: 0.875rem;
  font-weight: 500;
}

/* Silver gradient type shared by the hero heading, section headings and card names. */
.h1,
.h2 {
  background: linear-gradient(to right, var(--heading-edge), var(--heading), var(--heading-edge));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.h1 {
  margin: 0;
  padding-bottom: 1rem;
  font-size: 2.75rem;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.017em;
}

.lead {
  margin: 0 0 2rem;
  color: var(--lead);
  font-size: 1.125rem;
  line-height: 1.5;
  letter-spacing: -0.017em;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 20rem;
  min-height: 2.5rem;
  padding: 0.625rem 1.25rem;
  border: 1px solid transparent;
  border-radius: 9999px;
  background: linear-gradient(to right, var(--btn-edge), var(--btn), var(--btn-edge));
  color: var(--btn-text);
  font-size: 0.875rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

/* Stellar sets only a background color here, which the gradient hides, so the face does not change. */
.btn:hover {
  background-color: var(--btn);
}

.btn:focus-visible {
  outline-offset: 2px;
}

.btn__arrow {
  margin-left: 0.25rem;
  color: var(--btn-arrow);
  letter-spacing: 0;
}

.btn:hover .btn__arrow {
  transform: translateX(0.125rem);
}

/* Section headings */
.h2 {
  margin: 0;
  padding-bottom: 1rem;
  font-size: 2.25rem;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.017em;
}

/* Portfolio */
.portfolio {
  position: relative;
  isolation: isolate;
  padding: 4rem 0 2rem;
}

.section-label {
  display: inline-flex;
  padding-bottom: 0.75rem;
  background: linear-gradient(to right, var(--accent-strong), var(--accent-soft));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: 500;
}

.section-intro {
  max-width: 48rem;
  margin: 0 auto;
  padding-bottom: 3rem;
  text-align: center;
}

.section-lead {
  margin: 0;
  color: var(--text-muted);
  font-size: 1.125rem;
  line-height: 1.5;
}

/*
  Portfolio carousel, after Stellar's "Spot issues faster" section. A scroll-snap track instead of
  Swiper: three cards and a peek of the next, fading out at the right edge, arrows below.
  carousel.js marks the first visible card .is-active, which Stellar's active slide does.
*/
.carousel {
  position: relative;
}

.cards {
  --gap: 1.5rem;
  /* Room right of the container for the fourth card to peek into, none when the screen is narrow. */
  --peek: clamp(0px, calc((100vw - 72rem) / 2 - 1rem), 12rem);
  position: relative;
  display: flex;
  gap: var(--gap);
  margin: 0 calc(-1 * var(--peek)) 0 0;
  padding: 0;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  list-style: none;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - max(var(--peek), 4rem)), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - max(var(--peek), 4rem)), transparent);
}

.cards::-webkit-scrollbar {
  display: none;
}

.cards.at-end,
.cards:not(.is-scrollable) {
  -webkit-mask-image: none;
  mask-image: none;
}

.carousel__nav {
  display: flex;
  justify-content: flex-end;
  gap: 1rem;
  margin-top: 1.5rem;
}

.carousel__nav[hidden] {
  display: none;
}

.carousel__btn {
  display: grid;
  width: 2.5rem;
  height: 2.5rem;
  place-items: center;
  border: 0;
  border-radius: 9999px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.carousel__btn:hover {
  color: var(--text-strong);
}

.carousel__btn:disabled {
  opacity: 0.35;
  cursor: default;
}

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

.carousel__btn svg {
  width: 1rem;
  height: 1rem;
  fill: currentColor;
}

/*
  Stellar card: a one pixel edge around a rounded panel, with a teal glow rising from the bottom
  center. The link stretches over the whole card, so the card is the click target.
*/
.card {
  position: relative;
  flex: 0 0 calc((100% - var(--peek) - 2 * var(--gap)) / 3);
  min-width: 16rem;
  scroll-snap-align: start;
  padding: 1px;
  overflow: hidden;
  border-radius: 1.5rem;
  background: var(--card-edge);
}

/*
  Pointer tracking, from the Stellar highlighter. highlighter.js sets --mouse-x and --mouse-y on
  each card. The edge light shows on every card while the pointer is over the grid. The soft
  glow shows only on the card under the pointer. Without the script both sit off the card.
*/
.card::before,
.card::after {
  content: "";
  position: absolute;
  pointer-events: none;
  opacity: 0;
  transition: opacity 500ms;
}

.card::before {
  z-index: 30;
  top: -12rem;
  left: -12rem;
  width: 24rem;
  height: 24rem;
  border-radius: 9999px;
  background: var(--accent);
  filter: blur(100px);
  transform: translate(var(--mouse-x, -999px), var(--mouse-y, -999px));
}

.card::after {
  z-index: 10;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(250px circle at var(--mouse-x, -999px) var(--mouse-y, -999px), var(--card-spot), transparent);
}

.cards:hover .card::after {
  opacity: 1;
}

.card:hover::before {
  opacity: 0.2;
}

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

.card__body {
  position: relative;
  isolation: isolate;
  z-index: 20;
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 1.5rem;
  overflow: hidden;
  border-radius: inherit;
  background: var(--card);
}

.card__icon {
  display: grid;
  width: 3.5rem;
  height: 3.5rem;
  margin-bottom: 0.75rem;
  place-items: center;
  border-radius: 9999px;
  background: var(--eyebrow-bg);
  box-shadow: inset 0 0 0 1px var(--card-edge-hover);
}

.card__icon img {
  display: block;
  width: 1.75rem;
  height: 1.75rem;
  object-fit: contain;
}

.card__body::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: 50%;
  bottom: 0;
  width: 33%;
  aspect-ratio: 1;
  border-radius: 9999px;
  background: var(--card-edge);
  filter: blur(60px);
  transform: translate(-50%, 50%);
  pointer-events: none;
  transition: background 500ms ease-in-out;
}

/* Only the active card is lit, as with Stellar's active slide. Without the script that is the first. */
.cards:not([data-ready]) .card:first-child .card__body::before,
.card.is-active .card__body::before {
  background: var(--accent-strong);
}

.card__name {
  color: var(--text-strong);
  margin: 0 0 0.25rem;
  padding-bottom: 0.25rem;
  font-size: 1.125rem;
  font-weight: 700;
  line-height: 1.33;
}

.card__line {
  flex-grow: 1;
  margin: 0 0 0.75rem;
  color: var(--text-muted);
  line-height: 1.5;
}

.card__link {
  align-self: flex-end;
  color: var(--text-muted);
  font-size: 0.875rem;
  font-weight: 500;
  text-decoration: none;
}

.card__link::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

.card__link::after {
  content: "->" / "";
  display: inline-block;
  margin-left: 0.25rem;
  color: var(--accent);
  letter-spacing: 0;
}

.card__link:focus-visible {
  outline: none;
}

.card:hover {
  background: var(--card-edge-hover);
}

.card:hover .card__link {
  color: var(--text-strong);
}

.card:hover .card__link::after {
  transform: translateX(0.125rem);
}

@media (prefers-reduced-motion: no-preference) {
  .btn,
  .btn__arrow {
    transition: color 150ms ease-in-out, transform 150ms ease-in-out;
  }

  .nav-list a,
  .card,
  .card__link,
  .card__link::after {
    transition: background 150ms ease-in-out, color 150ms ease-in-out, transform 150ms ease-in-out;
  }
}

/* About */
.section {
  padding: 4rem 0;
  scroll-margin-top: 4rem;
}

/* Left-aligned section under the carousel, where Stellar's beam comes to rest. */
.why__content {
  max-width: 48rem;
}

.why__list {
  display: grid;
  gap: 1rem;
  margin: 2rem 0 0;
  padding: 0;
  color: var(--text-muted);
  line-height: 1.6;
  list-style: none;
}

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

.why__list a {
  color: var(--accent);
}

.principles__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 2rem;
  margin: 2rem 0 0;
  padding: 0;
  list-style: none;
}

.principles__list p {
  margin: 0;
  color: var(--text-muted);
  line-height: 1.6;
}

.principles__name {
  margin: 0 0 0.5rem;
  color: var(--text-strong);
  font-size: 1.125rem;
  font-weight: 700;
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 1.5rem;
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.footer-links a {
  color: var(--text-muted);
  text-decoration: none;
}

.footer-links a:hover {
  color: var(--text-strong);
}

footer p {
  margin: 0;
}

.about__content {
  max-width: 48rem;
  margin: 0 auto;
  text-align: center;
}

.about__content .h2 {
  margin-bottom: 0.5rem;
}

.about__content p {
  margin: 0 0 1rem;
  color: var(--lead);
  font-size: 1.125rem;
  line-height: 1.6;
  /* Left aligned on phones, where the paragraphs run to several lines; centered from 640px */
  text-align: left;
}

/* Line breaks without one word last lines; browsers without support wrap as before. */
.h1,
.h2,
.lead,
.section-lead {
  text-wrap: balance;
}

.card__line,
.about__content p {
  text-wrap: pretty;
}

/* Faded hairline: drawn at the top edge, so it takes no space and adds nothing to read */
.about,
footer {
  position: relative;
}

.about::before,
footer::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  max-width: 72rem;
  height: 1px;
  margin: 0 auto;
  background: linear-gradient(to right, transparent, var(--rule-strong), transparent);
}

/* Footer */
footer {
  max-width: 72rem;
  margin: 0 auto;
  padding: 2rem 1rem;
  color: var(--text-muted);
  font-size: 0.875rem;
  text-align: center;
}

@media (min-width: 640px) {
  .container {
    padding: 0 1.5rem;
  }

  .btn {
    width: auto;
    max-width: none;
  }

  .about__content p {
    text-align: center;
  }
}

@media (min-width: 768px) {
  .portfolio {
    padding: 4rem 0;
  }

  .section-intro {
    padding-bottom: 4rem;
  }

  .h2 {
    font-size: 2.75rem;
  }

}

@media (min-width: 768px) {
  .site-header__inner {
    height: 5rem;
  }

  .nav-list {
    gap: 2.5rem;
  }

  .hero__content {
    padding: 13rem 0 6rem;
  }

  .h1 {
    font-size: 3.5rem;
    line-height: 1;
  }

  .section {
    padding: 5rem 0 6rem;
    scroll-margin-top: 5rem;
  }

  /* Follows the portfolio's 4rem bottom: 136px from the last card to the About heading */
  .about {
    padding-top: 4.5rem;
  }
}

@media (max-width: 767px) {
  .card {
    flex-basis: 80%;
  }
}
