/* Orbi's website: one pinned stage that scroll plays like a film (site.ts).
   WebGL draws space and the laptop, the app's engine draws Orbi and the
   planets, and the real island runs in the laptop's screen (screen.html).
   Without scripts the page reads top to bottom as plain text. */

:root {
  color-scheme: dark;
  --ink: #ece9e2;
  --muted: #aaa7a1;
  --focus: #c6b4f0;
  --line: #2c2a31;
  --box: #0a090c;
  --box-line: #343137;
  --font: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, sans-serif;
  --mono: "Cascadia Mono", Consolas, ui-monospace, monospace;
  /* The app's eases, by the same names. */
  --ease-land: cubic-bezier(0.25, 0.92, 0.66, 0.95);
}

* { box-sizing: border-box; }
body { margin: 0; background: #000; color: var(--ink); font: 15px/1.6 var(--font); }
button { font: inherit; cursor: pointer; touch-action: manipulation; }
a { color: inherit; text-underline-offset: 0.25em; text-decoration-thickness: 1px; }
a:hover { color: #fff; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 5px; }
h1, h2, p { margin: 0; }
.skip { position: fixed; z-index: 20; top: 8px; left: 16px; padding: 10px 14px; background: var(--ink); color: #141312; border-radius: 7px; transform: translateY(-200%); }
.skip:focus { transform: none; }

.site-header { position: fixed; z-index: 8; top: 0; left: 0; right: 0; display: flex; align-items: center; justify-content: space-between; padding: 12px 24px 12px 36px; pointer-events: none; }
.site-header > * { pointer-events: auto; }
.wordmark { font-size: 24px; font-weight: 600; letter-spacing: -1px; text-decoration: none; }

h1 { font-size: clamp(32px, 3.6vw, 46px); font-weight: 550; line-height: 1.15; letter-spacing: -1.4px; text-wrap: balance; }
h2 { font-size: clamp(26px, 2.8vw, 34px); font-weight: 550; line-height: 1.2; letter-spacing: -1px; text-wrap: balance; }
.beat-hello h1 { width: min(26em, calc(100vw - 40px)); margin-left: 50%; translate: -50% 0; font-size: clamp(28px, 4vw, 56px); letter-spacing: -0.03em; }
.beat-hello h1 .line { display: block; }
.beat-hello h1 .line:first-child { font-size: 1.4em; letter-spacing: -0.035em; }

/* The install prompt, set as the input line of the agent it is pasted into:
   code type after a lavender prompt, and Copy at the end of the line. It shows
   the guide's address; the sentence before it is visually hidden, so Copy and
   screen readers still get the whole prompt. Above it, the agents it works
   with, in one colour. */
.prompt { margin-top: 28px; text-align: left; }
.prompt-label { padding: 0 16px 8px; font-size: 12px; color: var(--muted); }
.paste-into { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 6px 12px; padding-bottom: 12px; font-size: 12px; color: var(--muted); }
.agents { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 12px; margin: 0; padding: 0; list-style: none; }
.agents li, .platforms li { display: inline-flex; align-items: center; gap: 6px; }
/* The platforms Orbi runs on, quietly above the greeting. */
.platforms { display: flex; justify-content: center; gap: 18px; margin: 0 0 20px; padding: 0; list-style: none; font-size: 13px; color: var(--muted); }
/* Other makers' logos (media/logos/), drawn in the text's colour. */
.logo { width: 14px; height: 14px; background: currentColor; mask: var(--logo) center / contain no-repeat; }
@media (forced-colors: active) { .logo { forced-color-adjust: none; background: CanvasText; } }
.prompt-box { display: flex; align-items: center; gap: 14px; padding: 10px 10px 10px 16px; border: 1px solid var(--box-line); border-radius: 10px; background: var(--box); }
.prompt-text { position: relative; flex: 1; min-width: 0; padding-left: 2ch; font: 13.5px/1.6 var(--mono); overflow-wrap: anywhere; }
.prompt-text::before { content: ">" / ""; position: absolute; left: 0; color: var(--focus); }
.primary { flex: 0 0 auto; min-height: 44px; min-width: 76px; padding: 10px 18px; border: 1px solid var(--ink); border-radius: 6px; background: var(--ink); color: #141312; font-weight: 500; transition: background 140ms; }
.primary:hover { background: #fff; }
.copy-status { position: fixed; z-index: 7; left: 50%; bottom: 64px; translate: -50% 0; min-height: 1.6em; font-size: 12px; color: var(--focus); text-align: center; pointer-events: none; }
.links { display: flex; flex-wrap: wrap; justify-content: center; gap: 0 18px; margin-top: 18px; font-size: 12px; color: var(--muted); }
.links a { padding-block: 12px; }

/* ── Without scripts: the words, top to bottom ────────────────────────────── */
.film { position: relative; }
.stage { position: relative; }
.layer, .screen, .hit, .tag, .stage-foot, .quip { display: none; }
.orbi-still { display: block; width: min(60vw, 320px); margin: 120px auto 0; }
.beat, .described section { width: min(520px, calc(100% - 48px)); margin: 72px auto; text-align: center; }
.described p { margin-top: 12px; color: var(--muted); line-height: 1.7; }

/* ── With scripts: the pinned stage ───────────────────────────────────────── */
.live .stage { height: 100vh; height: 100dvh; overflow: clip; isolation: isolate; background: #000; }
.live .layer { display: block; position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.live #world { z-index: 0; }
.live #cast { z-index: 2; }
.live .orbi-still { display: none; }
.live .screen {
  display: block; position: absolute; z-index: 1; left: 0; top: 0;
  border: 0; background: transparent; color-scheme: dark;
  transform-origin: 0 0; pointer-events: none; visibility: hidden;
}
.live .hit { display: block; position: absolute; z-index: 3; left: 0; top: 0; padding: 0; border: 0; border-radius: 50%; background: none; }
.live .hit[hidden] { display: none; }
.live .tag { display: block; position: absolute; z-index: 3; left: 0; top: 0; opacity: 0; font-size: 14px; font-weight: 600; color: var(--ink); white-space: nowrap; pointer-events: none; }

.live .beat { position: absolute; z-index: 4; left: 50%; margin: 0; translate: -50% 0; text-align: center; }
.live .beat-hello { top: 50%; translate: -50% -50%; width: min(480px, calc(100% - 40px)); }
/* Orbi's aside and its lines through the middle of the film, in the sky above it (site.ts). */
.live .quip, .live .say {
  display: block; position: absolute; z-index: 4; left: 50%; top: 18%; translate: -50% -50%; width: min(24em, calc(100vw - 40px)); margin: 0;
  font-size: clamp(26px, 3.2vw, 44px); font-weight: 550; line-height: 1.15; letter-spacing: -0.03em; text-align: center; text-wrap: balance; pointer-events: none;
}
/* A line that follows on under the one before it, which stays. */
.live .say.under { top: calc(18% + 1.4em); }
@media (max-width: 719px) { .live .say.under { top: calc(18% + 2.6em); } }
/* The laptop story's lines, in the room above the laptop (site.ts sets --above). */
.live .say.above { top: var(--above, 9%); width: min(30em, calc(100vw - 40px)); font-size: clamp(20px, 2.2vw, 32px); }

/* The greeting assembling from dots (dots.ts): letters over a canvas of dots,
   and the whole text, visually hidden, for screen readers. */
.dot-type { position: relative; isolation: isolate; }
.dot-word { white-space: nowrap; }
.dot-letter { display: inline-block; }
/* Room for the dots' whole flight, with soft edges in case one strays further. */
.dot-canvas {
  position: absolute; z-index: -1; left: -3.5em; top: -5em; width: calc(100% + 7em); height: calc(100% + 9.4em); pointer-events: none;
  mask-image: linear-gradient(transparent, #000 1em, #000 calc(100% - 1em), transparent), linear-gradient(90deg, transparent, #000 1em, #000 calc(100% - 1em), transparent);
  mask-composite: intersect;
}
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.live .described { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* The scrubber: a dotted line across the screen like the app's timeline, one
   stop per scene. What has played turns lavender, dot for dot, and so do the
   stops passed; the current one is lit. A soft shadow keeps it readable over
   Orbi's bright horizon. */
.live .stage-foot { display: flex; position: absolute; z-index: 6; left: 20px; right: 20px; bottom: 10px; justify-content: center; align-items: center; pointer-events: none; }
/* Across the whole screen, the end stops 20px in from its edges. */
.scrubber { position: relative; width: 100%; height: 44px; pointer-events: auto; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.9)); }
.scrubber::before, .playhead { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 2px; translate: 0 -50%; background: radial-gradient(circle, var(--dot) 0.9px, transparent 1.2px) 0 50% / 6px 2px repeat-x; }
.scrubber::before { --dot: rgba(235, 228, 214, 0.35); }
.playhead { --dot: var(--focus); right: auto; width: calc(var(--at, 0) * 100%); }
.scrubber button { position: absolute; top: 0; left: calc(var(--at, 0) * 100%); width: 28px; height: 44px; translate: -50% 0; padding: 0; border: 0; background: none; display: grid; place-items: center; }
.scrubber button::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: rgba(235, 228, 214, 0.45); transition: background 200ms, transform 200ms var(--ease-land), box-shadow 200ms; }
.scrubber button[data-passed]::before { background: var(--focus); }
.scrubber button:hover::before { background: var(--ink); transform: scale(1.4); }
.scrubber button[aria-current="true"]::before { background: var(--ink); transform: scale(1.6); box-shadow: 0 0 0 3px rgba(198, 180, 240, 0.3); }

@media (max-width: 719px) {
  .site-header { padding: 10px 12px 10px 20px; }
  .prompt-box { flex-direction: column; align-items: stretch; }
  .primary { width: 100%; }
  .copy-status { bottom: 58px; width: calc(100% - 40px); }
}
