:root {
  --ink: #e8eeff;
  --dim: rgba(232, 238, 255, 0.45);
  --accent: #4de2ff;
  --panel: rgba(10, 16, 34, 0.55);
  --edge: rgba(120, 165, 255, 0.14);
  --ui: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --mono: 'SF Mono', ui-monospace, 'JetBrains Mono', Menlo, monospace;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: #060915;
  color: var(--ink);
  font-family: var(--ui);
  -webkit-font-smoothing: antialiased;
}

#stage,
#stage3d {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

#stage {
  cursor: crosshair;
}

/* The character layer sits over the painted city. Input still belongs to the
   2D canvas underneath, so this one never takes a pointer event. */
#stage3d {
  z-index: 1;
  pointer-events: none;
}

.title,
.hud,
.hints {
  position: fixed;
  pointer-events: none;
  z-index: 2;
}

.title {
  top: 26px;
  left: 28px;
}

.title h1 {
  margin: 0;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.title p {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--dim);
  letter-spacing: 0.04em;
}

.hud {
  top: 26px;
  right: 28px;
  /* Thirty rows of five by seven type is taller than a short window, so the
     wrapper scrolls even though the panel it holds is one canvas. */
  max-height: calc(100vh - 120px);
  overflow-y: auto;
  scrollbar-width: none;
  /* The panel is painted on the canvas now, frame and all, so the wrapper is
     only here to position it and to catch the click. */
  pointer-events: auto;
  line-height: 0;
}

.hudCanvas {
  display: block;
  image-rendering: pixelated;
}

/* An invisible button over the painted title bar. The header is drawn, but a
   canvas cannot be tabbed to or announced, and this can. */
.hudHit {
  all: unset;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  cursor: pointer;
}

/* The lab. Sits opposite the readouts, because one panel tells you what the
   simulation is doing and the other decides it. */
.lab {
  position: fixed;
  top: 96px;
  left: 28px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  width: 268px;
  max-height: calc(100vh - 190px);
  overflow-y: auto;
  padding: 12px 14px 14px;
  /* Square corners and a two pixel border, because a rounded rectangle is the
     one shape a pixel grid cannot make. */
  border: 2px solid var(--edge);
  background: var(--panel);
  backdrop-filter: blur(14px);
  pointer-events: auto;
}

.lab.hidden {
  display: none;
}

.labHeader {
  margin-bottom: 10px;
}

.labHeader h1,
.labHeader p {
  margin: 0;
  line-height: 0;
}

.labHeader p {
  margin-top: 6px;
}

.presets {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 4px;
}

.preset {
  all: unset;
  cursor: pointer;
  padding: 4px 7px;
  border: 2px solid var(--edge);
  background: rgba(36, 49, 84, 0.6);
  line-height: 0;
  transition: border-color 0.12s, background 0.12s;
}

.preset:hover {
  border-color: var(--accent);
  background: rgba(77, 226, 255, 0.16);
}

.preset.wide {
  margin-top: 10px;
  text-align: center;
  justify-content: center;
  padding: 5px 8px;
}

/* Label and number on one line, slider on the next. At this width a slider
   sharing a row with its label is too short to aim at. */
.control {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 4px 8px;
  padding: 3px 0;
}

.control input[type='range'],
.control select {
  grid-column: 1 / -1;
}

/* A setting nothing currently reads, like stiffness on a rigid web. Dimmed
   rather than hidden, so the panel does not jump about as you switch. */
.control.inactive {
  opacity: 0.3;
}

.control input[type='range'] {
  width: 100%;
  height: 4px;
  margin: 4px 0 1px;
  appearance: none;
  background: rgba(120, 165, 255, 0.22);
  cursor: pointer;
}

/* A square thumb. A circle is the giveaway that this is a browser control. */
.control input[type='range']::-webkit-slider-thumb {
  appearance: none;
  width: 10px;
  height: 10px;
  background: var(--accent);
}

.control input[type='range']::-moz-range-thumb {
  width: 10px;
  height: 10px;
  border: 0;
  border-radius: 0;
  background: var(--accent);
}

.control select {
  margin-top: 3px;
  padding: 2px 4px;
  border: 2px solid var(--edge);
  background: rgba(10, 16, 34, 0.7);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 11px;
}

.control input[type='checkbox'] {
  grid-column: 2;
  margin: 0;
  accent-color: var(--accent);
}

.control .value {
  font-size: 12px;
}

.derived {
  margin-top: 12px;
  padding-top: 4px;
  border-top: 1px solid var(--edge);
}

/* One row of the "that means" block: name, number, unit.
 *
 * It needs a layout of its own because the spans inside it are set to a line
 * height of nothing. That is right for a label whose text is a canvas, since a
 * canvas brings its own height and the leading around it is only a gap that
 * cannot be controlled, but it means a row of them collapses to nothing at all
 * and the next row is drawn straight through it. Which is what was happening:
 * the weight was printed over the top of the terminal speed.
 *
 * A grid, so the numbers line up down the column instead of sitting wherever
 * the label before them happened to end, and a gap, so consecutive rows are
 * plainly separate readings rather than a paragraph. */
.stat {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: 6px;
  row-gap: 5px;
  padding: 7px 0;
}

/* The name on its own line, the number and its unit right aligned under it.
 *
 * Measured rather than guessed at: "Terminal speed" is a hundred and sixty six
 * pixels of bitmap type in a row two hundred and thirty six wide, so the three
 * of them never did fit across, and forcing them to clipped the unit to "m/"
 * and jammed the number against it. Two lines fits any label this panel will
 * ever be given, and the row gap is the vertical air the readings were missing. */
.stat .label {
  grid-column: 1 / -1;
}

.stat .value {
  justify-self: end;
}

/* The time of day button. Bottom right, the one corner nothing else uses:
   readouts are top right, the lab is top left, the hints are bottom left. */
.corner {
  position: fixed;
  right: 28px;
  bottom: 24px;
  z-index: 2;
  pointer-events: auto;
}

.timeToggle {
  all: unset;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 12px 7px 9px;
  background: var(--panel);
  backdrop-filter: blur(14px);
  /* A hard stepped border rather than a hairline, so the button is built out
     of blocks like everything else on the screen. */
  box-shadow:
    0 0 0 2px rgba(10, 16, 34, 0.55),
    0 0 0 4px var(--edge);
  transition: box-shadow 0.12s;
}

.timeToggle:hover {
  box-shadow:
    0 0 0 2px rgba(10, 16, 34, 0.55),
    0 0 0 4px var(--accent);
}

.timeToggle:active {
  /* Sinks by one whole pixel. Half a pixel would be a smooth control. */
  transform: translateY(1px);
}

.timeToggle canvas {
  display: block;
  image-rendering: pixelated;
}

.timeLabel {
  font-family: var(--ui);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
  min-width: 52px;
}

.timeToggle:hover .timeLabel {
  color: var(--ink);
}

.hints {
  bottom: 24px;
  left: 28px;
  right: 190px;
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 0.05em;
}

kbd {
  display: inline-block;
  padding: 2px 6px;
  margin-right: 3px;
  border: 1px solid var(--edge);
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.04);
  font-family: var(--mono);
  font-size: 10px;
  color: var(--ink);
}

@media (max-width: 720px) {
  .title p,
  .hints {
    display: none;
  }

  .title {
    top: 18px;
    left: 16px;
  }

  .title h1 {
    font-size: 13px;
    letter-spacing: 0.12em;
  }

  .hud {
    top: 14px;
    right: 14px;
    min-width: 138px;
    padding: 9px 11px;
  }

  .stat {
    column-gap: 5px;
    row-gap: 4px;
    padding: 5px 0;
  }

  .label {
    font-size: 9px;
  }

  .value {
    font-size: 12px;
  }

}

/* Every label in the interface is a little canvas of bitmap type now, so they
   need to sit like text rather than like images. */
.lab canvas,
.timeLabel canvas {
  display: block;
  image-rendering: pixelated;
}

.control .label,
.control .value,
.stat .label,
.stat .value,
.stat .unit,
.preset {
  line-height: 0;
}

.control {
  align-items: center;
}

.derived {
  border-top: 2px solid var(--edge);
}

/* No native scrollbars anywhere. A rounded grey thumb is the last smooth shape
   that would be left on the screen. */
.hud::-webkit-scrollbar,
.lab::-webkit-scrollbar {
  display: none;
}

.lab {
  scrollbar-width: none;
}

/* ---------------------------------------------------------------- embedded

   The version that sits in a card on another page.

   Everything that is there to be read or pressed goes, because at the size a
   card gives it none of it is legible and none of it is usable: a dashboard of
   twenty five readouts at three hundred and fifty pixels wide is texture, not
   information. What is left is the simulation itself, flying, and a link. */

.embedLink,
.embedTag {
  display: none;
}

body.embed .embedTag {
  position: fixed;
  top: 6px;
  right: 8px;
  z-index: 4;
  display: block;
  padding: 2px 6px;
  background: rgba(6, 10, 24, 0.55);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: rgba(232, 238, 255, 0.5);
  pointer-events: none;
}

body.embed .title,
body.embed .hud,
body.embed .lab,
body.embed .corner,
body.embed .hints {
  display: none;
}

body.embed .embedLink {
  position: fixed;
  inset: 0;
  z-index: 3;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  padding: 10px 12px;
  text-decoration: none;
  /* No hit testing to steal, no cursor change until it is hovered: the card
     should read as a picture that happens to be alive, and only then as a door. */
  background: transparent;
}

body.embed .embedLink span {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(232, 238, 255, 0.55);
  background: rgba(6, 10, 24, 0.55);
  padding: 4px 7px;
  opacity: 0;
  transition: opacity 140ms ease;
}

body.embed .embedLink:hover span,
body.embed .embedLink:focus-visible span {
  opacity: 1;
}
