/* IBM Plex, served from our own origin: this page makes no third-party request and
   should keep it that way. Basic-latin subsets only, because the copy is English —
   see fonts/SOURCES.md, which also names the matching Thai face for later.
   No unicode-range: there is one subset per family here, so there is nothing to
   choose between, and a hand-copied range is one more thing to get wrong. */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 100 700;          /* a single variable file covers the whole range */
  font-display: swap;
  src: url('fonts/ibm-plex-sans-var.056e4e2459.woff2') format('woff2');
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-400.c36f509c0a.woff2') format('woff2');
}

:root {
  color-scheme: dark;
  --ink: #e8f0fb;
  --dim: #7d8ea6;
  --line: #2a3a55;
  --accent: #5aa9ff;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --pad: max(20px, env(safe-area-inset-left));
}

* { box-sizing: border-box; }

body {
  margin: 0;
  /* A definite height, not just a minimum. With only min-height the grid container is
     content-sized, so the 1fr row asks the canvas how tall it wants to be, the canvas
     answers with its own drawing-buffer size, the row grows, the next resize makes the
     buffer bigger still — and the globe ends up drawn larger than the window. */
  height: 100svh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  background: #04060c;
  color: var(--ink);
  font: 400 15px/1.6 'IBM Plex Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Arial, sans-serif;
  overflow: hidden;
}

/* The starfield sits behind everything and never takes pointer events. */
#sky {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
}

header {
  padding: max(22px, env(safe-area-inset-top)) var(--pad) 0;
  text-align: center;
}

h1 {
  --track: .34em;               /* one source for the tracking, see .orb */
  margin: 0;
  font-size: clamp(19px, 2.6vw, 26px);
  font-weight: 300;
  letter-spacing: var(--track);
  text-indent: var(--track);    /* letter-spacing pads the right edge; recentre */
  text-transform: uppercase;
}

h1 b {
  font-weight: 600;
  color: var(--accent);
}

/* The O of WORLD, drawn rather than typed: the ◉ character this borrows from is
   missing or differently shaped in plenty of system fonts, which is not a risk worth
   taking with a wordmark. Sized in em so it tracks the heading at every breakpoint. */
.orb {
  /* Sized and placed on the font's cap height so the ring reads as the O it replaces.
     inline-block puts its bottom edge on the baseline, which centres it at half the
     cap height — plain `inline` does not, and left the ring sitting 0.26em low.
     --cap is the cap height of the heading's typeface; swapping the font means
     measuring it again. */
  --cap: .698em;                /* cap height of IBM Plex Sans, measured not guessed */
  display: inline-block;
  width: var(--cap);
  height: var(--cap);
  vertical-align: baseline;
  /* Chrome does not add letter-spacing after a replaced element, so the ring would
     sit hard against the R while the W keeps its full tracking. Carrying the same
     tracking as a right margin makes the ring space like the character it stands in
     for — which is what a text glyph gets for free. */
  margin-left: 0;
  margin-right: var(--track);
  color: var(--accent);
}

/* The globe fills whatever is left between the header and the footer. */
#stage {
  position: relative;
  min-height: 0;
  touch-action: none;           /* we handle the drag ourselves */
  cursor: grab;
}

#stage.holding { cursor: grabbing; }

/* Taken out of flow as well, so the canvas can never contribute its intrinsic size
   back to the row that sizes it. Either of these two changes prevents the feedback
   loop; both are here because the failure is invisible until a window is resized
   twice and the globe is suddenly off the bottom of the screen. */
#stage canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

#stage-note {
  position: absolute;
  inset: auto 0 12% 0;
  margin: 0;
  text-align: center;
  color: var(--dim);
  font: 400 12px/1.6 var(--mono);
  letter-spacing: .16em;
  text-transform: uppercase;
}

#readout {
  position: fixed;
  top: max(22px, env(safe-area-inset-top));
  left: var(--pad);
  margin: 0;
  display: grid;
  gap: 14px;
  font-family: var(--mono);
}

#readout div { display: grid; gap: 3px; }

#readout dt {
  color: var(--dim);
  font-size: 9.5px;
  letter-spacing: .22em;
  text-transform: uppercase;
}

#readout dd {
  margin: 0;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
}

#pin dd { color: var(--accent); }

/* Two lines of marked-point detail would push the mobile footer around, so it
   keeps its own line there rather than joining the two-column row. */
@media (max-width: 700px) {
  #pin { grid-column: 1 / -1; }
}

footer {
  padding: 0 var(--pad) max(20px, env(safe-area-inset-bottom));
  text-align: center;
}

footer p { margin: 0; }

#controls {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-bottom: 12px;
}

#controls button {
  min-height: 44px;
  padding: 0 18px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #0a1220cc;
  color: var(--ink);
  font: 400 11px/1 var(--mono);
  letter-spacing: .18em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color .2s ease, background .2s ease;
}

#controls button:hover { border-color: var(--accent); background: #10203acc; }
#controls button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.hint {
  font: 400 11px/1.8 var(--mono);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--dim);
  transition: opacity .6s ease;
}

.hint.gone { opacity: 0; }

.credit {
  margin-top: 6px !important;
  font-size: 11px;
  color: #56637a;
}

/* Under ~700px the readout would sit on top of the globe, so it moves into the
   footer flow instead of floating. */
@media (max-width: 700px) {
  #readout {
    position: static;
    grid-auto-flow: column;
    justify-content: center;
    gap: 26px;
    padding: 10px var(--pad) 0;
    text-align: center;
  }
  #readout div { justify-items: center; }
  h1 { --track: .26em; }
}

@media (prefers-reduced-motion: reduce) {
  .hint { transition: none; }
}
