/* Self-hosted so the page keeps making zero external requests. */
@font-face {
  font-family: "Space Mono";
  src: url("/assets/space-mono-700-latin-6NnW1qxO.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --sq-green: #33ff33;
  --sq-black: #000;
  --cube-size: 100vmax;
  --perspective: 145vmax;
}

body {
  background-color: var(--sq-black);
  color: var(--sq-green);
  font-family: "Courier New", monospace;
  padding: 2rem;
  margin: 0;
}

ul {
  list-style: none;
  padding-left: 0;
}

/* Nested groups (e.g. the Manifold projects) indent under their heading. */
li > ul {
  padding-left: 1.6rem;
  margin-top: 0.15rem;
}

li:has(> ul) {
  margin-top: 0.6rem;
}

a {
  color: var(--sq-green);
}

a:hover {
  text-decoration: underline;
}

/* The centered text column shared by every face (and by 404.html). */
.page {
  max-width: 40rem;
  margin: 0 auto;
  padding: 0 1rem;
  font-size: 0.9rem;
  line-height: 1.5;
}

.page h1,
.page h2 {
  font-family: "Space Mono", "Courier New", monospace;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  /* the trailing letter's tracking would otherwise push the text off-centre */
  text-indent: 0.18em;
  text-shadow: 0 0 16px rgba(51, 255, 51, 0.4);
  margin: 0 0 0.7rem;
}

.page h1 {
  font-size: clamp(1.5rem, 5.5vw, 2.4rem);
  line-height: 1.2;
}

.page h2 {
  font-size: clamp(1.1rem, 3.6vw, 1.5rem);
}

.page > p:first-of-type {
  margin-top: 0;
}

.page code {
  color: #aaffaa;
}

/* Links face: an icon, the site, then the handle in dimmer text. */
.links li {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.35rem 0;
}

.links a {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  text-decoration: none;
}

.links a:hover .link-name,
.links a:focus-visible .link-name {
  text-decoration: underline;
}

.links .icon {
  /* centred against the label rather than sitting on its baseline */
  align-self: center;
  width: 1.05em;
  height: 1.05em;
  flex: none;
  fill: currentColor;
  opacity: 0.8;
  transition: opacity 160ms ease, filter 160ms ease;
}

.links a:hover .icon,
.links a:focus-visible .icon {
  opacity: 1;
  filter: drop-shadow(0 0 6px rgba(51, 255, 51, 0.55));
}

.links .handle {
  opacity: 0.5;
}

.hint {
  margin-top: 2rem;
  opacity: 0.4;
  font-size: 0.85rem;
  letter-spacing: 0.2em;
}

/* Starfield sits behind everything; the script fades it in while you drag. */
#starfield {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  opacity: 0;
  pointer-events: none;
}

/*
 * Without JS (or without 3D support) the markup is just a stack of sections:
 * show the landing face and hide the rest, so the page degrades to a link list.
 */
.face:not(.face-front) {
  display: none;
}

.face-front .hint {
  display: none;
}

@supports (transform-style: preserve-3d) {
  html.cube-ready,
  html.cube-ready body {
    height: 100%;
    overflow: hidden;
  }

  /*
   * Deep space behind the box. The faces stay pure black, so the lifted
   * background is what makes the cube read as a solid silhouette — and at rest
   * the front face covers all of it, leaving the page plain black.
   */
  html.cube-ready body {
    padding: 0;
    background: radial-gradient(125% 95% at 50% 42%, #0d1a16 0%, #071009 42%, #010301 78%, #000 100%);
  }

  html.cube-ready .scene {
    position: fixed;
    inset: 0;
    z-index: 1;
    perspective: var(--perspective);
    transform-style: preserve-3d;
    touch-action: none;
    cursor: grab;
    overflow: hidden;
  }

  html.cube-ready .scene.is-dragging {
    cursor: grabbing;
    user-select: none;
  }

  html.cube-ready .cube {
    position: absolute;
    top: 50%;
    left: 50%;
    width: var(--cube-size);
    height: var(--cube-size);
    margin-top: calc(var(--cube-size) / -2);
    margin-left: calc(var(--cube-size) / -2);
    transform-style: preserve-3d;
    transform: translateZ(calc(var(--cube-size) / -2));
  }

  html.cube-ready .face {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--sq-black);
    backface-visibility: hidden;
    box-shadow: inset 0 0 0 1px rgba(51, 255, 51, 0.55), inset 0 0 60px rgba(51, 255, 51, 0.07),
      0 0 50px rgba(51, 255, 51, 0.14);
  }

  html.cube-ready .face-front {
    transform: translateZ(calc(var(--cube-size) / 2));
  }

  html.cube-ready .face-back {
    transform: rotateY(180deg) translateZ(calc(var(--cube-size) / 2));
  }

  html.cube-ready .face-right {
    transform: rotateY(90deg) translateZ(calc(var(--cube-size) / 2));
  }

  html.cube-ready .face-left {
    transform: rotateY(-90deg) translateZ(calc(var(--cube-size) / 2));
  }

  html.cube-ready .face-top {
    transform: rotateX(90deg) translateZ(calc(var(--cube-size) / 2));
  }

  html.cube-ready .face-bottom {
    transform: rotateX(-90deg) translateZ(calc(var(--cube-size) / 2));
  }

  html.cube-ready .face:not(.face-front) {
    display: flex;
  }

  html.cube-ready .face-front .hint {
    display: block;
  }

  /* Keep the text column inside the viewport even though the face overflows it. */
  html.cube-ready .page {
    width: 100vw;
    max-width: 40rem;
    max-height: 100vh;
    padding: 0 2rem;
  }

  /* Faces you aren't looking at shouldn't be selectable or hoverable. */
  html.cube-ready .face[inert] {
    user-select: none;
  }
}

/* Edge affordances: which way the cube can turn from here. */
.edges {
  display: none;
}

@supports (transform-style: preserve-3d) {
  html.cube-ready .edges {
    display: block;
  }
}

.edge-arrow {
  position: fixed;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.7rem;
  border: 0;
  background: none;
  color: var(--sq-green);
  font: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  opacity: 0.45;
  transition: opacity 180ms ease;
}

/* A turn that isn't available offers no arrow. This has to outrank the
   `display: flex` above, which would otherwise defeat the hidden attribute. */
.edge-arrow[hidden] {
  display: none;
}

.edge-arrow:hover,
.edge-arrow:focus-visible {
  opacity: 1;
  text-shadow: 0 0 12px rgba(51, 255, 51, 0.6);
}

.edge-glyph {
  font-size: 0.85rem;
  line-height: 1;
  animation: edge-nudge 2.8s ease-in-out infinite;
}

.edge-label {
  white-space: nowrap;
}

.edge-up,
.edge-down {
  left: 50%;
  transform: translateX(-50%);
  flex-direction: column;
  gap: 0.3rem;
}

.edge-up {
  top: 0.6rem;
}

.edge-down {
  bottom: 0.6rem;
}

.edge-left {
  left: 0.6rem;
  top: 50%;
  transform: translateY(-50%);
}

.edge-right {
  right: 0.6rem;
  top: 50%;
  transform: translateY(-50%);
}

/* Out of the way while you're actually turning the cube. */
html.is-dragging .edge-arrow {
  opacity: 0;
  pointer-events: none;
}

@keyframes edge-nudge {
  0%,
  82%,
  100% {
    transform: translate(0, 0);
  }
  90% {
    transform: translate(var(--nudge-x, 0), var(--nudge-y, 0));
  }
}

.edge-up .edge-glyph {
  --nudge-y: -3px;
}
.edge-down .edge-glyph {
  --nudge-y: 3px;
}
.edge-left .edge-glyph {
  --nudge-x: -3px;
}
.edge-right .edge-glyph {
  --nudge-x: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .edge-glyph {
    animation: none;
  }

  .page h1,
  .page h2 {
    text-shadow: none;
  }
}
