/* ==========================================================================
   Axoniverse — site styles

   All colours, sizes, spacing, and motion come from tokens.css. Do not
   introduce literal values here; add or adjust a token instead.
   Rendered reference: design/system.html
   ========================================================================== */

/* ==========================================================================
   Base
   ========================================================================== */

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

html {
  scroll-behavior: smooth;
  /* keep anchored sections clear of the fixed header */
  scroll-padding-top: var(--space-24);
}

body {
  margin: 0;
  background: var(--surface-base);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  /* Font smoothing is left at the browser default. Forcing greyscale
     antialiasing thins glyphs, which is what light-on-dark type needs and
     exactly what dark-on-light type does not. */
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-heading);
  line-height: var(--leading-tight);
  margin: 0;
  text-wrap: balance;
}

p {
  margin: 0;
}

/* Emphasis is a colour shift from secondary to primary, plus one weight step.
   Dark type needed two steps, because light-on-dark glyphs bloom and emphasis
   has to out-shout that bloom. Dark ink on paper already sits heavier, so the
   same two steps read as shouting. */
strong {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
}

a {
  color: inherit;
  text-decoration: none;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

figure {
  margin: 0;
}

canvas {
  display: block;
}

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

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

.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-4);
  z-index: 100;
  padding: var(--space-3) var(--space-4);
  background: var(--accent);
  color: var(--accent-contrast);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.skip-link:focus {
  top: var(--space-4);
}

/* ==========================================================================
   Shared atoms
   ========================================================================== */

/* The one place semibold earns its keep. Twelve pixels, uppercase and widely
   tracked, is the weakest text on the page, and unlike body copy it gains
   nothing from the optical weight that dark ink has on paper. */
.eyebrow {
  font-family: var(--font-display);
  font-size: var(--text-eyebrow);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--accent);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-6);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--accent-contrast);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  white-space: nowrap;
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease),
    background-color var(--duration-fast) var(--ease),
    box-shadow var(--duration-fast) var(--ease);
}

.btn:hover {
  background: var(--accent-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow-accent);
}

.btn--sm {
  padding: var(--space-2) var(--space-4);
}

/* ==========================================================================
   Navigation
   ========================================================================== */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  border-bottom: 1px solid transparent;
  transition: background-color var(--duration-medium) var(--ease),
    border-color var(--duration-medium) var(--ease);
}

.nav.is-stuck {
  background: color-mix(in srgb, var(--surface-base) 82%, transparent);
  backdrop-filter: blur(14px);
  border-bottom-color: var(--border-subtle);
  box-shadow: var(--shadow-sm);
}

.nav__inner {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  height: calc(var(--unit) * 4.5);
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-display);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
}

/* The mark is a transparent PNG used as a mask so it inherits its colour. */
.wordmark__mark {
  width: calc(var(--unit) * 2);
  height: calc(var(--unit) * 2);
  flex: none;
  background-color: var(--text-primary);
  -webkit-mask: url("assets/logo-mark.png") center / contain no-repeat;
  mask: url("assets/logo-mark.png") center / contain no-repeat;
}

.nav__links {
  display: flex;
  gap: var(--space-8);
  margin-left: auto;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.nav__links > a,
.nav__trigger {
  position: relative;
  transition: color var(--duration-fast) var(--ease);
}

.nav__links > a::after,
.nav__trigger::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -5px;
  width: 100%;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-medium) var(--ease);
}

.nav__links > a:hover,
.nav__trigger:hover,
.nav__trigger[aria-expanded="true"] {
  color: var(--text-primary);
}

.nav__links > a:hover::after,
.nav__trigger:hover::after,
.nav__trigger[aria-expanded="true"]::after {
  transform: scaleX(1);
}

/* ---- Products dropdown ---- */

.nav__menu {
  position: relative;
}

.nav__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.nav__chevron {
  width: 0.75em;
  height: 0.75em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform var(--duration-fast) var(--ease);
}

.nav__trigger[aria-expanded="true"] .nav__chevron {
  transform: rotate(180deg);
}

/* Hangs from the trigger's centre. The transparent top padding bridges the gap
   to the panel, so the pointer can travel down without the menu closing. */
.nav__dropdown {
  position: absolute;
  top: 100%;
  left: 50%;
  z-index: 1;
  min-width: calc(var(--unit) * 17);
  padding-top: var(--space-3);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, calc(var(--space-1) * -1));
  transition: opacity var(--duration-fast) var(--ease),
    transform var(--duration-fast) var(--ease),
    visibility 0s linear var(--duration-fast);
}

.nav__trigger[aria-expanded="true"] + .nav__dropdown,
html:not(.js) .nav__menu:hover .nav__dropdown,
html:not(.js) .nav__menu:focus-within .nav__dropdown {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
  transition-delay: 0s;
}

.nav__panel {
  padding: var(--space-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  box-shadow: var(--shadow-lg);
}

.nav__item {
  display: grid;
  gap: var(--space-1);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  transition: background-color var(--duration-fast) var(--ease);
}

.nav__item:hover,
.nav__item:focus-visible {
  background: var(--surface-overlay);
}

.nav__item-name {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.nav__item[aria-current="page"] .nav__item-name {
  color: var(--accent);
}

.nav__item-note {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}

@media (prefers-reduced-motion: reduce) {
  .nav__dropdown {
    transform: translate(-50%, 0);
  }
}

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 100svh;
  padding: var(--space-24) 0;
  overflow: hidden;
  text-align: center;
}

/* Held higher than the dark theme used. There the field was bright strokes on
   a dark ground and had to be dimmed; here it is dark ink on paper, and the
   same dimming washes it out entirely. */
.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0.9;
}

.hero__glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    ellipse 70% 55% at 50% 45%,
    color-mix(in srgb, var(--accent) 13%, transparent),
    transparent 70%
  );
}

.hero__inner {
  position: relative;
  z-index: 1;
}

.hero__title {
  font-size: var(--text-display);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-display);
  /* Holds the statement to two balanced lines instead of one stretched line. */
  max-width: 21ch;
  margin-inline: auto;
}

.hero__cue {
  position: absolute;
  bottom: var(--space-8);
  left: 50%;
  translate: -50% 0;
  z-index: 1;
  display: grid;
  place-items: center;
  width: var(--space-8);
  height: var(--space-12);
}

.hero__cue-line {
  width: 1px;
  height: var(--space-8);
  background: linear-gradient(to bottom, transparent, var(--text-tertiary));
  transform-origin: top;
  animation: cue 2.4s var(--ease) infinite;
}

@keyframes cue {
  0% {
    opacity: 0;
    scale: 1 0.3;
  }
  40% {
    opacity: 1;
    scale: 1 1;
  }
  100% {
    opacity: 0;
    scale: 1 1;
  }
}

/* ==========================================================================
   Screens — one beat of the story per viewport
   ========================================================================== */

.screen {
  display: grid;
  align-content: center;
  min-height: 100svh;
  padding-block: var(--section-y);
}

.screen--center {
  text-align: center;
}

/* A standard band of content, for pages denser than the one-beat-per-screen
   homepage. */
.section {
  padding-block: var(--section-y);
}

.screen--alt,
.section--alt {
  background: var(--surface-sunken);
  border-block: 1px solid var(--border-subtle);
}

/* ---- measured content blocks ---- */

.block > * + * {
  margin-top: var(--space-6);
}

/* Headings sit closer to the eyebrow that labels them than to body copy. */
.block .eyebrow + .headline-lg,
.block .eyebrow + .headline-xl,
.block .eyebrow + .body-xl {
  margin-top: var(--space-4);
}

.block--wide {
  max-width: var(--measure);
}

/* Full container width, for a long statement that would otherwise run to four
   lines in the standard measure. */
.block--full {
  max-width: none;
}

/* Multi-paragraph prose stays left-aligned even when the screen around it is
   centred. It runs the full container so each paragraph lands in two or three
   lines at the larger size rather than stacking up into a tall column. */
.block--prose {
  max-width: none;
  text-align: left;
}

/* ---- type roles within a screen ---- */

.headline-xl {
  font-size: var(--text-h1);
}

.headline-lg {
  font-size: var(--text-h2);
  font-weight: var(--weight-regular);
}

.body-xl {
  font-size: var(--text-body-xl);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

.body-lg {
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

/* ---- a set of statements read at one size and one colour ----
   The copy is one continuous thought, not a heading with supporting text, so
   every line matches the section heading size used on the next screen. The
   only emphasis is weight on the two key terms; nothing here changes colour. */

/* Sized in multiples of the line size to the longest sentence on the
   homepage, the closing screen's second one, which is about 30 times the
   size wide. Where the container is narrower than that, the lines wrap into
   balanced pairs. */
.say {
  max-width: calc(var(--text-h2) * 30.5);
  margin-inline: auto;
}

/* Highlight is colour, not weight — these sit at the same weight as the rest
   of the line, so the block still reads as one continuous statement.
   box-decoration-break keeps the gradient intact if a term wraps a line. */
.say strong {
  font-weight: inherit;
  background-image: var(--gradient-accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.say__line {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  font-weight: var(--weight-regular);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-heading);
  color: var(--text-primary);
  text-wrap: balance;
}

/* The gap is what separates a set of lines into distinct beats. */
.say__gap {
  margin-top: clamp(var(--space-12), 6vw, var(--space-24));
}

/* A line that continues the one above it rather than starting a new beat. */
.say__tight {
  margin-top: var(--space-4);
}

.say__gradient {
  background-image: var(--gradient-accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.say .btn {
  margin-top: var(--space-8);
}

/* Manifesto line — the one place a statement stands entirely on its own. */
/* Symmetrical air: the space below only applies when copy follows, so a pull
   quote that ends a section does not add a trailing gap. */
.pull + * {
  margin-top: var(--space-16);
}

.pull {
  max-width: 19.5em;
  margin: var(--space-16) auto 0;
  font-family: var(--font-display);
  font-size: var(--text-h2);
  font-weight: var(--weight-regular);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-heading);
  text-align: center;
  text-wrap: balance;
}

/* ==========================================================================
   Cards
   ========================================================================== */

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

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

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

/* The cards are a separate beat from the statement above them. */
.block + .grid {
  margin-top: var(--space-16);
}

.card {
  container-type: inline-size;
  padding: var(--space-6);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  text-align: left;
  transition: background-color var(--duration-medium) var(--ease),
    border-color var(--duration-medium) var(--ease),
    box-shadow var(--duration-medium) var(--ease),
    transform var(--duration-medium) var(--ease);
}

/* A raised card is already white, so hover cannot lift it any further up the
   surface ladder. The shadow does the lifting and the tint marks the state. */
.card:hover {
  background: var(--surface-overlay);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

/* One heading treatment for every card, so headings and the body copy beneath
   them line up across the row. Keeping them to a single line is what holds
   that alignment, so where a card is too narrow for the full size the heading
   scales to the card: the longest heading is about 8.4 times its size wide. */
.card__head {
  font-family: var(--font-display);
  font-size: min(var(--text-xl), 100cqi / 8.6);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-heading);
  line-height: var(--leading-tight);
  margin-bottom: var(--space-4);
  background-image: var(--gradient-accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.card__body {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

/* ==========================================================================
   BPU flow diagram — input into the core, result out
   ========================================================================== */

.flow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  margin-top: var(--space-16);
}

.flow__node {
  display: grid;
  place-items: center;
  width: calc(var(--unit) * 9.5);
  height: calc(var(--unit) * 5.5);
  flex: none;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
}

.flow__core {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  width: calc(var(--unit) * 14);
  height: calc(var(--unit) * 14);
  flex: none;
  border: 1px solid var(--accent-border);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 4%, transparent);
}

.flow__net {
  width: 60%;
  height: auto;
}

.flow__edges path {
  fill: none;
  stroke: var(--accent);
  stroke-opacity: 0.28;
  stroke-width: 1;
}

.flow__nodes circle {
  fill: var(--accent);
}

.flow__label {
  font-family: var(--font-display);
  font-size: var(--text-eyebrow);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-secondary);
}

.flow__label--core {
  color: var(--accent);
}

.flow__link {
  position: relative;
  width: calc(var(--unit) * 5);
  height: 1px;
  flex: none;
  background: var(--border-strong);
}

.flow__pulse {
  position: absolute;
  top: 50%;
  left: 0;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px 2px color-mix(in srgb, var(--accent) 45%, transparent);
  animation: flow-x 2.8s var(--ease) infinite;
}

.flow__pulse--delayed {
  animation-delay: 1.4s;
}

@keyframes flow-x {
  0% {
    left: 0;
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  88% {
    opacity: 1;
  }
  100% {
    left: 100%;
    opacity: 0;
  }
}

.flow__caption {
  flex-basis: 100%;
  max-width: 34em;
  margin: var(--space-8) auto 0;
  color: var(--text-tertiary);
  font-size: var(--text-lg);
  text-align: center;
}

/* ==========================================================================
   Closing
   ========================================================================== */

.closing {
  position: relative;
  background-image: radial-gradient(
    ellipse 60% 80% at 50% 100%,
    color-mix(in srgb, var(--accent) 9%, transparent),
    transparent 70%
  );
}


/* ==========================================================================
   Footer
   ========================================================================== */

.footer {
  padding-top: var(--space-12);
  border-top: 1px solid var(--border-subtle);
  background: var(--surface-sunken);
}

.footer__inner {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8);
  justify-content: space-between;
  align-items: flex-start;
  padding-bottom: var(--space-8);
}

.footer__tagline {
  margin-top: var(--space-3);
  color: var(--text-tertiary);
  font-size: var(--text-sm);
}

.footer__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
}

.footer__email {
  color: var(--text-primary);
  font-size: var(--text-sm);
  border-bottom: 1px solid var(--border-subtle);
  padding-bottom: 2px;
  transition: border-color var(--duration-fast) var(--ease),
    color var(--duration-fast) var(--ease);
}

.footer__email:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.footer__social {
  display: flex;
  gap: var(--space-6);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.footer__social a {
  transition: color var(--duration-fast) var(--ease);
}

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

.footer__legal {
  padding-block: var(--space-6);
  border-top: 1px solid var(--border-subtle);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
}

/* ==========================================================================
   Scroll reveal
   ========================================================================== */

.js .reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--duration-slow) var(--ease),
    transform var(--duration-slow) var(--ease);
}

.js .reveal.is-visible {
  opacity: 1;
  transform: none;
}

.grid .reveal:nth-child(2) {
  transition-delay: 0.09s;
}

.grid .reveal:nth-child(3) {
  transition-delay: 0.18s;
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 1000px) {
  .grid--3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* Two columns don't divide three cards evenly; let the last fill the row. */
  .grid--3 > :last-child {
    grid-column: 1 / -1;
  }

  .flow__link {
    width: calc(var(--unit) * 3);
  }

  .flow__core {
    width: calc(var(--unit) * 12);
    height: calc(var(--unit) * 12);
  }

  .flow__node {
    width: calc(var(--unit) * 8);
  }
}

@media (max-width: 860px) {
  .nav__links {
    display: none;
  }

  .nav__inner .btn {
    margin-left: auto;
  }
}

/* The smallest phones have no room for the wordmark and a full-size button
   side by side, so the header tightens rather than run off the edge. */
@media (max-width: 374px) {
  .nav__inner {
    gap: var(--space-3);
  }

  .wordmark {
    gap: var(--space-2);
  }

  .nav__inner .btn--sm {
    padding-inline: var(--space-3);
    font-size: var(--text-xs);
  }
}

@media (max-width: 720px) {
  /* The flow reads top to bottom once there is no room for it side by side. */
  .flow {
    flex-direction: column;
  }

  .flow__node,
  .flow__core {
    width: min(100%, calc(var(--unit) * 16));
  }

  .flow__link {
    width: 1px;
    height: calc(var(--unit) * 3.5);
  }

  .flow__pulse {
    top: 0;
    left: 50%;
    animation-name: flow-y;
  }

  @keyframes flow-y {
    0% {
      top: 0;
      opacity: 0;
    }
    12% {
      opacity: 1;
    }
    88% {
      opacity: 1;
    }
    100% {
      top: 100%;
      opacity: 0;
    }
  }
}

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

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

  .grid--3 > :last-child {
    grid-column: auto;
  }

  .card {
    padding: var(--space-4);
  }

  .footer__inner {
    flex-direction: column;
    gap: var(--space-8);
  }
}

/* ==========================================================================
   Reduced motion
   ========================================================================== */

@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;
  }
}

/* The opening needs clearance for the fixed header. */
.section--opening {
  padding-top: calc(var(--space-24) + var(--space-12));
}

.section--closing {
  padding-bottom: var(--space-24);
}

.section--closing .btn {
  margin-top: var(--space-4);
}

/* ==========================================================================
   Stack — the device as separated layers
   ========================================================================== */

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: calc(var(--unit) * 34);
  margin: var(--space-16) auto 0;
}

.stack__layer {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
}

.stack__layer--core {
  border-color: var(--accent-border);
  background: linear-gradient(
    to right,
    color-mix(in srgb, var(--accent) 7%, var(--surface-raised)),
    var(--surface-raised)
  );
}

.stack__index {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}

.stack__name {
  font-family: var(--font-display);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
}

.stack__layer--core .stack__name {
  color: var(--accent);
}

/* ==========================================================================
   Chain — a linear path of labelled stages with a signal running through it
   ========================================================================== */

.chain {
  position: relative;
  margin-top: var(--space-16);
  padding-block: var(--space-4);
}

.chain__list {
  position: relative;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  align-items: start;
}

/* The rail sits behind the nodes, inset so it starts and ends at the first
   and last dot rather than running off the edges. */
.chain__list::before {
  content: "";
  position: absolute;
  top: 5px;
  left: 10%;
  right: 10%;
  height: 1px;
  background: var(--border-strong);
}

.chain__node {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  text-align: center;
}

.chain__dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--surface-base);
  border: 1px solid var(--border-strong);
}

.chain__node--core .chain__dot {
  width: 15px;
  height: 15px;
  margin-top: -2px;
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 14%, transparent);
}

.chain__label {
  max-width: 13ch;
  font-family: var(--font-display);
  font-size: var(--text-eyebrow);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-secondary);
}

.chain__node--core .chain__label {
  color: var(--accent);
}

.chain__pulse {
  position: absolute;
  top: calc(var(--space-4) + 5px);
  left: 10%;
  width: 7px;
  height: 7px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 12px 3px color-mix(in srgb, var(--accent) 45%, transparent);
  animation: chain-run 4.2s var(--ease) infinite;
}

@keyframes chain-run {
  0% {
    left: 10%;
    opacity: 0;
  }
  8% {
    opacity: 1;
  }
  88% {
    opacity: 1;
  }
  100% {
    left: 90%;
    opacity: 0;
  }
}

/* ==========================================================================
   Numbered steps
   ========================================================================== */

.steps {
  display: grid;
  gap: var(--space-4);
  margin-top: var(--space-16);
}

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

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

.step {
  padding: var(--space-6);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
}

.step__index {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--accent);
  margin-bottom: var(--space-2);
}

.step__title {
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-heading);
  margin-bottom: var(--space-3);
}

.step__body {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

/* ==========================================================================
   Chain and step responsiveness
   ========================================================================== */

@media (max-width: 1000px) {
  .steps--5 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

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

@media (max-width: 680px) {
  /* The chain reads top to bottom once the labels no longer fit side by side. */
  .chain__list {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    gap: var(--space-6);
    justify-items: start;
  }

  .chain__list::before {
    top: 10%;
    bottom: 10%;
    left: 5px;
    right: auto;
    width: 1px;
    height: auto;
  }

  .chain__node {
    flex-direction: row;
    align-items: center;
    gap: var(--space-4);
    text-align: left;
  }

  .chain__label {
    max-width: none;
  }

  .chain__pulse {
    top: 10%;
    left: calc(5px + 1px);
    animation-name: chain-run-y;
  }

  @keyframes chain-run-y {
    0% {
      top: 10%;
      opacity: 0;
    }
    8% {
      opacity: 1;
    }
    88% {
      opacity: 1;
    }
    100% {
      top: 90%;
      opacity: 0;
    }
  }

  .steps--5,
  .steps--4 {
    grid-template-columns: minmax(0, 1fr);
  }
}
