/* layout.css — Page layout and structural utilities */

html,
body {
  height: 100%;
  overflow: hidden;
  background: var(--lawn);
  color: var(--ink);
  font-family: var(--font-sans), sans-serif;
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
}

/* -- stage -- */
/* Fixed viewport the camera looks through. Nothing here ever scrolls. */
.stage {
  position: fixed;
  inset: 0;
  overflow: hidden;
  cursor: grab;
  touch-action: none;
  /* Dragging the camera would otherwise sweep a text selection across every
     label it passes over. Nothing in the world is meant to be selected. */
  user-select: none;
  -webkit-user-select: none;
}

/* Images and video shouldn't be draggable either — the browser's native
   image-drag hijacks the pan. */
.stage img,
.stage video {
  -webkit-user-drag: none;
  user-select: none;
  pointer-events: none;
}

.stage.is-dragging {
  cursor: grabbing;
}

/* -- world -- */
/* The plane every node is positioned on. camera.js owns this transform and */
/* writes it once per frame; nothing else may touch it. */
.world {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  transform-origin: 0 0;
  will-change: transform;
}

.world > * {
  position: absolute;
}

/* -- cursors -- */
/* Presence draws here, above the world and below the HUD. */
.cursors {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 2;
}

/* -- hud -- */
.hud {
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  font-size: var(--ui-size);
  font-weight: var(--ui-weight);
  letter-spacing: var(--ui-tracking);
  text-transform: uppercase;
}

.hud > * {
  position: absolute;
  pointer-events: auto;
}

.hud-topleft {
  top: var(--edge);
  left: var(--edge);
}

.hud-topright {
  top: var(--edge);
  right: var(--edge);
  display: flex;
  gap: var(--gutter);
}

.hud-bottomright {
  right: var(--edge);
  bottom: var(--edge);
  display: flex;
  gap: var(--gutter);
  align-items: center;
}

/* -- panel -- */
/* Bottom left. Small type at real size, so it stays crisp at any zoom. */
.panel {
  bottom: var(--edge);
  left: var(--edge);
  width: 320px;
  opacity: 0;
  transform: translateY(4px);
  transition:
    opacity 0.25s ease,
    transform 0.25s ease;
  pointer-events: none;
}

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

/* -- entrance -- */
/* A dimmer over the live view rather than a screen in front of it: the whole */
/* thing is visible underneath from the first frame. */
.entrance {
  position: fixed;
  inset: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--gutter);
  background: rgba(242, 242, 242, 0.88);
  background: color-mix(in srgb, var(--lawn) 88%, transparent);
  cursor: pointer;
  opacity: 1;
  transition: opacity 0.45s ease;
}

/* Lifts rather than blinks out, so the fly-in starts before it has fully */
/* cleared and the two read as one movement. */
.entrance.is-gone {
  opacity: 0;
  pointer-events: none;
}
