/* Section layer. Hero, gap diagram, switcher, collaborate, status, contact, auth shell. */

/* S01 Hero */

.hero {
  position: relative;
  min-height: min(100svh, 900px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-top: 132px;
  padding-bottom: var(--s9);
  border-top: 0;
}

/* Content sits above the spotlight layer. */
.hero .wrap {
  position: relative;
  z-index: 1;
}

.hero__eyebrow {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin-bottom: var(--s6);
}

.hero__eyebrow::after {
  content: "";
  flex: 1;
  height: var(--hair);
  background: linear-gradient(to right, var(--line-strong), transparent);
  max-width: 240px;
}

.hero__title {
  font-size: var(--fs-display);
  letter-spacing: -0.045em;
  font-weight: 800;
  margin-bottom: var(--s6);
}

/* The word "gaps" sits inside a frame with a visible break in it. */
.gapword {
  position: relative;
  display: inline-block;
  padding: 0 0.18em;
  margin-left: 0.06em;
}

.gapword::before,
.gapword::after {
  content: "";
  position: absolute;
  inset-block: -0.06em;
  width: 0.42em;
  border: 2px solid var(--line-strong);
  pointer-events: none;
}

.gapword::before {
  left: 0;
  border-right: 0;
  animation: gap-left 900ms var(--ease) 320ms both;
}

.gapword::after {
  right: 0;
  border-left: 0;
  animation: gap-right 900ms var(--ease) 320ms both;
}

/* The two halves close in on the word on load. Only a from state is declared,
   so the animation always resolves to the rules above, including when reduced
   motion collapses the duration to nothing. */
@keyframes gap-left {
  from {
    transform: translateX(-26px);
    opacity: 0;
  }
}

@keyframes gap-right {
  from {
    transform: translateX(26px);
    opacity: 0;
  }
}

.hero__lead {
  max-width: 58ch;
  font-size: var(--fs-md);
  color: var(--text-2);
  margin-bottom: var(--s7);
}

.hero__actions {
  display: flex;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-bottom: var(--s8);
}

.hero__readout {
  display: flex;
  align-items: stretch;
  border: var(--hair) solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  overflow-x: auto;
  scrollbar-width: none;
}

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

.hero__readout span {
  flex: 1;
  min-width: 116px;
  padding: var(--s3) var(--s4);
  border-right: var(--hair) solid var(--line);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-3);
  text-align: center;
  transition: color var(--t-base) var(--ease), background-color var(--t-base) var(--ease);
}

.hero__readout span:last-child {
  border-right: 0;
}

.hero__readout span:hover {
  color: var(--text);
  background: var(--surface-2);
}

.hero__scroll {
  position: absolute;
  bottom: var(--s5);
  left: var(--gutter);
  display: flex;
  align-items: center;
  gap: var(--s2);
  color: var(--text-3);
}

.hero__scroll .ico {
  animation: nudge 2.6s var(--ease) infinite;
}

@keyframes nudge {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(5px);
  }
}

/* S02 Gap diagram */

.gapmap {
  position: relative;
  width: 100%;
  border: var(--hair) solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  padding: var(--s5);
}

/* The canvas sits under the SVG in the same coordinate space, so the simulated
   packets travel exactly along the drawn connectors. */
.gapmap__stage {
  position: relative;
  width: 100%;
}

.gapmap__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

.gapmap svg {
  position: relative;
  z-index: 1;
  width: 100%;
  height: auto;
  overflow: visible;
}

.gapmap .node-box {
  /* Lets the packets read through the boxes rather than vanishing behind them. */
  fill-opacity: 0.92;
}

.gapmap .node-box {
  fill: var(--surface-2);
  stroke: var(--line-strong);
  stroke-width: 1;
}

.gapmap .node-label {
  fill: var(--text);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Node indicators. Same grammar as the systems status dots: a solid dot in a
   state colour plus a ring that beeps outward. Each node carries its own state. */

.gapmap .node-dot {
  fill: var(--line-strong);
  transition: fill var(--t-slow) var(--ease);
}

.gapmap .node-pulse {
  fill: var(--line-strong);
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

.gapmap .node--ok .node-dot,
.gapmap .node--ok .node-pulse {
  fill: var(--ok);
}
.gapmap .node--warn .node-dot,
.gapmap .node--warn .node-pulse {
  fill: var(--warn);
}
.gapmap .node--err .node-dot,
.gapmap .node--err .node-pulse {
  fill: var(--err);
}
.gapmap .node--info .node-dot,
.gapmap .node--info .node-pulse {
  fill: var(--info);
}

/* The beep starts only once the section has been revealed. */
.is-in .gapmap .node-pulse {
  animation: node-beep 2.6s var(--ease) infinite;
}

.is-in .gapmap .node:nth-of-type(2) .node-pulse {
  animation-delay: 0.32s;
}
.is-in .gapmap .node:nth-of-type(3) .node-pulse {
  animation-delay: 0.64s;
}
.is-in .gapmap .node:nth-of-type(4) .node-pulse {
  animation-delay: 0.16s;
}
.is-in .gapmap .node:nth-of-type(5) .node-pulse {
  animation-delay: 0.48s;
}
.is-in .gapmap .node:nth-of-type(6) .node-pulse {
  animation-delay: 0.8s;
}

@keyframes node-beep {
  0% {
    transform: scale(0.5);
    opacity: 0.5;
  }
  70% {
    transform: scale(3);
    opacity: 0;
  }
  100% {
    transform: scale(3);
    opacity: 0;
  }
}

.gapmap__legend {
  display: flex;
  align-items: center;
  gap: var(--s4);
  flex-wrap: wrap;
}

.gapmap__legend span {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
}

.gapmap .seam {
  stroke: var(--line-strong);
  stroke-width: 1;
  stroke-dasharray: 3 5;
}

.gapmap .seam-label {
  fill: var(--text-3);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.3em;
}

.gapmap .link {
  fill: none;
  stroke: var(--line-strong);
  stroke-width: 1;
  stroke-dasharray: 4 4;
  stroke-dashoffset: 300;
  opacity: 0.9;
}

.is-in .gapmap .link {
  animation: draw 1.5s var(--ease) forwards;
}

.is-in .gapmap .link:nth-of-type(2) {
  animation-delay: 0.14s;
}
.is-in .gapmap .link:nth-of-type(3) {
  animation-delay: 0.28s;
}
.is-in .gapmap .link:nth-of-type(4) {
  animation-delay: 0.42s;
}
.is-in .gapmap .link:nth-of-type(5) {
  animation-delay: 0.56s;
}
.is-in .gapmap .link:nth-of-type(6) {
  animation-delay: 0.7s;
}

@keyframes draw {
  to {
    stroke-dashoffset: 0;
  }
}

.gapmap__meta {
  display: flex;
  justify-content: space-between;
  gap: var(--s4);
  margin-top: var(--s4);
  padding-top: var(--s3);
  border-top: var(--hair) solid var(--line);
}

.gapmap .seam-label {
  letter-spacing: 0.34em;
}

.claim {
  display: flex;
  gap: var(--s4);
  padding-block: var(--s4);
  border-top: var(--hair) solid var(--line);
}

.claim__no {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.2em;
  color: var(--text-3);
  padding-top: 4px;
  flex: none;
  width: 42px;
}

/* S03 Switcher */

/* The switch is a scroll track. The stage inside it is what the reader sees,
   pinned in place while the section is scrolled through. */
.switch {
  position: relative;
}

.switch__stage {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.6fr);
  gap: clamp(24px, 4vw, 56px);
  align-items: start;
}

.switch__list {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  position: relative;
  border-left: var(--hair) solid var(--line);
}

.switch__marker {
  position: absolute;
  left: -1px;
  width: 2px;
  background: var(--text);
  transition: transform var(--t-base) var(--ease), height var(--t-base) var(--ease);
}

.switch__tab {
  display: flex;
  align-items: center;
  gap: var(--s4);
  width: 100%;
  padding: var(--s4) var(--s5);
  text-align: left;
  color: var(--text-3);
  transition: color var(--t-base) var(--ease), background-color var(--t-base) var(--ease);
}

.switch__tab:hover {
  color: var(--text-2);
  background: var(--surface);
}

.switch__tab[aria-selected="true"] {
  color: var(--text);
  background: var(--surface);
}

.switch__tab-index {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.18em;
  color: var(--text-3);
}

.switch__tab-name {
  font-size: var(--fs-lg);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.switch__panel {
  position: relative;
  min-height: 340px;
}

.switch__pane {
  display: none;
}

.switch__pane.is-active {
  display: block;
  animation: pane-in var(--t-base) var(--ease);
}

@keyframes pane-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.switch__readout {
  position: absolute;
  top: var(--s5);
  right: var(--s6);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.18em;
  color: var(--text-3);
  z-index: 2;
}

.switch__headline {
  font-size: var(--fs-xl);
  margin-bottom: var(--s4);
  max-width: 24ch;
}

.points {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  margin-top: var(--s6);
  padding-top: var(--s5);
  border-top: var(--hair) solid var(--line);
}

.points li {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  font-size: var(--fs-sm);
  color: var(--text-2);
}

.points .ico {
  color: var(--ok);
  margin-top: 2px;
}

/* Scroll driven mode, switched on by switcher.js. Applies at every width:
   the stage pins, and each track owns one step of the section's height, so a
   reader walks the four tracks in order and cannot scroll past any of them. */

.switch--scroll {
  height: calc(var(--switch-steps, 4) * 72svh);
}

/* Where the stage comes to rest. Pinning it just under the nav shoved the panel
   against the top edge of the screen, which read as the layout breaking rather
   than as a deliberate hold. Parking it lower leaves air above and lands the
   content nearer the middle of the viewport, where the eye already is.
   switcher.js reads this same computed value, so the two cannot drift. */
.switch--scroll .switch__stage {
  position: sticky;
  top: clamp(104px, 15vh, 190px);
}

.switch--scroll .switch__pane {
  /* Stops the pinned box resizing as tracks of different lengths swap in. */
  min-height: 420px;
}

/* Position through the section, drawn down the tab list beside the marker. */
.switch__marker {
  z-index: 2;
}

.switch__progress {
  position: absolute;
  left: -1px;
  top: 0;
  width: 2px;
  height: 100%;
  z-index: 1;
}

.switch__progress span {
  display: block;
  width: 100%;
  height: var(--switch-progress, 0%);
  background: var(--line-strong);
  transition: height var(--t-micro) linear;
}

/* Narrow screens.

   The old layout put the tabs in a horizontally scrolling row, which left three
   of the four tracks off screen with no hint that they existed. People saw one
   track and assumed that was all of it.

   All four are now laid out as equal columns so the whole set is visible at a
   glance, and the section drives them from the scroll itself: the stage pins to
   the viewport and each track takes one step of the scroll, so nothing can be
   skipped past. Tapping a tab scrolls to that step, which keeps the scroll
   position and the selected track from ever disagreeing. */

@media (max-width: 900px) {
  .switch__stage {
    display: block;
  }

  .switch__list {
    flex-direction: row;
    overflow: visible;
    border-left: 0;
    border-bottom: var(--hair) solid var(--line);
    position: relative;
    gap: 0;
    margin-bottom: var(--s5);
  }

  .switch__marker {
    display: none;
  }

  .switch__tab {
    flex: 1 1 0;
    min-width: 0;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: var(--s3) var(--s1) var(--s4);
    text-align: center;
    border-radius: 0;
  }

  .switch__tab .ico {
    width: 18px;
    height: 18px;
  }

  .switch__tab-index {
    font-size: 0.5625rem;
    opacity: 0.7;
  }

  .switch__tab-name {
    font-size: 0.6875rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-family: var(--font-mono);
    font-weight: 500;
  }

  .switch__tab[aria-selected="true"] {
    background: var(--surface);
  }

  /* The progress line turns horizontal, running under the strip. */
  .switch__progress {
    left: 0;
    right: 0;
    top: auto;
    bottom: -1px;
    width: auto;
    height: 2px;
    background: var(--line);
  }

  .switch__progress span {
    height: 100%;
    width: var(--switch-progress, 0%);
    background: var(--text);
    transition: width var(--t-micro) linear;
  }

  .switch__panel {
    min-height: 0;
  }

  .switch--scroll .switch__pane {
    min-height: 400px;
  }

  .switch__readout {
    display: block;
    top: var(--s4);
    right: var(--s5);
  }
}

/* S04 Collaborate */

.marquee {
  position: relative;
  margin-top: var(--s8);
  padding-block: var(--s4);
  border-block: var(--hair) solid var(--line);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 12%, #000 88%, transparent);
}

.marquee__track {
  display: flex;
  gap: var(--s7);
  width: max-content;
  animation: slide 34s linear infinite;
}

.marquee:hover .marquee__track {
  animation-play-state: paused;
}

.marquee__track span {
  display: flex;
  align-items: center;
  gap: var(--s7);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-3);
  white-space: nowrap;
}

.marquee__track span::after {
  content: "";
  width: 5px;
  height: 5px;
  background: var(--line-strong);
  border-radius: 50%;
}

@keyframes slide {
  to {
    transform: translateX(-50%);
  }
}

.card__lines {
  display: flex;
  gap: var(--s2);
  margin-top: auto;
  padding-top: var(--s4);
  border-top: var(--hair) solid var(--line);
  flex-wrap: wrap;
}

/* S05 Status */

.statuspanel {
  padding: 0;
}

.statuspanel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  padding: var(--s4) var(--s6);
  border-bottom: var(--hair) solid var(--line);
  background: var(--surface-2);
  flex-wrap: wrap;
}

.statusrow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 200px minmax(0, 1.3fr);
  gap: var(--s4);
  align-items: center;
  padding: var(--s5) var(--s6);
  border-bottom: var(--hair) solid var(--line);
}

.statusrow:last-child {
  border-bottom: 0;
}

.statusrow__name {
  font-weight: 600;
  letter-spacing: -0.01em;
}

.statusrow__state {
  display: flex;
  align-items: center;
  gap: var(--s3);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.statusrow__note {
  font-size: var(--fs-sm);
  color: var(--text-2);
}

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

/* S06 Contact */

.contactform {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s4);
}

.contactform .field--wide {
  grid-column: 1 / -1;
}

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

.contactside {
  display: flex;
  flex-direction: column;
  gap: var(--s5);
}

.contactside__mail {
  display: inline-flex;
  align-items: center;
  gap: var(--s3);
  font-size: var(--fs-lg);
  font-weight: 600;
  letter-spacing: -0.02em;
}

/* Auth shell */

.auth {
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: 112px var(--gutter) var(--s9);
  position: relative;
}

.auth__card {
  width: 100%;
  max-width: 480px;
  padding: clamp(24px, 4vw, 44px);
}

.auth__head {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  margin-bottom: var(--s6);
  padding-bottom: var(--s5);
  border-bottom: var(--hair) solid var(--line);
}

.auth__title {
  font-size: var(--fs-xl);
}

.auth__form {
  display: flex;
  flex-direction: column;
  gap: var(--s4);
}

.auth__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-top: var(--s6);
  padding-top: var(--s5);
  border-top: var(--hair) solid var(--line);
  font-size: var(--fs-sm);
  color: var(--text-2);
  flex-wrap: wrap;
}

/* Errors */

.errorpage {
  min-height: 100svh;
  display: grid;
  place-items: center;
  text-align: center;
  padding: var(--s10) var(--gutter);
}

.errorpage__code {
  font-size: clamp(4rem, 18vw, 11rem);
  font-weight: 800;
  letter-spacing: -0.06em;
  line-height: 1;
}
