/* Lobby (start page): the first screen is the solar system, on every screen.
   The system is laid out twice by templates/lobby.mjs (VIEWS in assets/js/system-geometry.mjs): the wide view for
   landscape windows (aspect ratio 1:1 or wider), orbits lying flat across a 1.75 : 1 stage, and the tall view for
   portrait windows, the same system turned on its side on a 0.62 : 1 stage. Both come as custom properties on the
   same elements, each set under its view's prefix (--w-x, --t-x, ...); the two VIEW blocks at the end of this file
   map the live view's set onto the plain names (--x) and size the stage and the type, so every other rule is the
   same for both views. Positions are shares of the stage and sizes are in container units of .lobby-stage.
   With JavaScript and the motion setting on or calm (html[data-motion], base.css), assets/js/lobby-orbits.js then
   moves the planets along their orbits (.lobby-planets.is-orbiting). The motion gates below are wrapped in :where(),
   so each rule keeps the weight it had. */

.lobby {
  --lobby-name: rgb(var(--on-dark-rgb) / 0.9);
  --lobby-hook: var(--on-dark-muted);
  --lobby-hook-hover: #d3d7de;
  --lobby-night: rgb(var(--globe-night-rgb) / 0.8); /* was 0.88: front planets stop reading as dark holes */
  --lobby-text-shadow: 0 0 2px rgb(var(--space-rgb) / 0.9), 0 0 12px rgb(var(--space-rgb) / 0.9);
  /* The chip round each name (the planets, below): its hairline and fill at rest and lit. The leader line meets the
     hairline in its colour: cream at rest, the planet's own colour lit (--chip-line-lit, with the planets). */
  --chip-line: rgb(var(--on-dark-rgb) / 0.3);
  --chip-fill: rgb(var(--on-dark-rgb) / 0.05);
  /* 0.12 lit (the chips had 0.2): over the planet's wash the name stays at 7:1 or more. */
  --chip-fill-lit: rgb(var(--on-dark-rgb) / 0.12);
  /* The sky's tone round the planets, from the colour tokens: near the sun (the innermost orbit), where the nebula's
     lapis glow lies under the system, and out at the edge, space lifted a little by the photo's faint stars. The
     night sides end on it (the lit globe, below), so a planet's dark limb fades into the sky instead of cutting a
     dark edge into it. Measured behind the planets (the photo's stars left out, 390x844 to 1440x900): about 17 24 57
     on the innermost orbit, 12-15 16-21 37-53 on the outer ones, before the dark tones got their floor (base.css),
     which lifts them by about 5 of 255. */
  --lobby-sky-near: color-mix(in srgb, rgb(var(--nebula-1)) 16%, var(--space));
  --lobby-sky-far: color-mix(in srgb, var(--on-dark) 2%, var(--space));
  /* The market constellations' lines (lobby-sky.js): a cool tint, so a figure never reads as an orbit line
     (--orbit-rgb is cream). The stars themselves are a neutral warm white since 2026-10-09 (--star-rgb, base.css);
     the lines keep the blue-white the cool stars had. */
  --lobby-sky-mark: 186 204 255;
  /* The hovered planet's glow on its sun side, in the planet's own colour (--tint): as strong as the drop-shadow it
     replaces (below), so the darker tints still read on the blue. */
  --lobby-glow-a: 0.6;
}

/* The test banner (preview, base.css) stays one line here, so the first screen can take its height off exactly
   (--lobby-banner). Its text only gets smaller on the narrowest phones (3.5vw is 13px at 372px); the line height is
   the 20.8px it always has (1.6 x 13px). */
body:has(> .preview-banner) {
  --lobby-banner: 38.4px;
}

.lobby .preview-banner p {
  overflow: hidden;
  font-size: min(1em, 3.5vw);
  line-height: 1.3rem;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* ------------------------------------------------------------------ hero */
/* The first screen: the header over the top of it, the frame below. Deep blue with three faint glows of the nebula
   (lapis behind the system, warm dust in two corners), and over it the starfield photo (::before). */
.lobby-hero {
  position: relative;
  /* Its own stacking context, so the sky (lobby-sky.js, z-index -1) paints over this background and under
     everything in the frame. */
  isolation: isolate;
  overflow: hidden;
  overflow: clip;
  padding: var(--header-h) 0 0;
  background:
    radial-gradient(55% 50% at 50% 64%, rgb(var(--nebula-1) / 0.2), transparent 72%),
    radial-gradient(40% 36% at 86% 18%, rgb(var(--nebula-2) / 0.12), transparent 70%),
    radial-gradient(36% 40% at 10% 85%, rgb(var(--nebula-2) / 0.08), transparent 70%),
    var(--space);
  background-repeat: no-repeat;
}

/* The photo's stars: tinted by a neutral wash (multiplied over the photo) and screened onto the blue, so the photo's
   black becomes the sky's blue and the stars keep their light. The photo (2048 x 1152) covers the hero, cropped from
   the centre, in both views, so a phone held upright sees a tall slice of it at about the scale the old 1400px tiles
   had, with no seams (lobby-sky.js assumes this placement where it lets the photo's own stars swell).
   Cleaner since 2026-10-09 (the owner: "the stars are too blue ... can be cleaner"): one warm white wash instead of
   base.css's --star-wash (a cream base with an amber and a blue patch), halved by the saturate() with the photo's own
   blue cast; warm enough that a bright star screened onto the lapis comes out near white, where a neutral one came out
   grey-blue (the screen keeps a share of the blue under it). The faint speckle is calmed and the bright stars are
   brighter: contrast() takes the dark parts darker and the bright ones up, and more of the photo shows (0.75 for
   0.55). Measured as drawn at 1440 x 900, the stars one notices (15 L* or more over the sky) went from chroma 12.2 to
   about 11, and the faint specks (5 to 10 L*) from about 2,000 to about 700. The buy pages keep their look's wash. */
.lobby-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  /* Black under the photo: if it is not painted (a failed fetch, a decode dropped under GPU load) the wash multiplies
     to black and the screen leaves the blue as it is, instead of a grey-cream sky. */
  background-color: #000;
  background-image: linear-gradient(#ffe4cc, #ffe4cc), url("../planets/starfield.webp");
  background-size: 100% 100%, cover;
  background-repeat: no-repeat;
  background-position: center;
  background-blend-mode: multiply, normal;
  mix-blend-mode: screen;
  opacity: 0.75;
  filter: saturate(0.5) contrast(1.35);
}

/* The rest of the first screen below the header. An explicit height: Chrome does not resolve cqh inside a
   flex-grown size container. The floor only keeps absurdly short windows from collapsing it: a 740 x 360 phone held
   sideways has a 237.6px frame (with the 38.4px test banner) and a 381 x 218px stage. */
.lobby-hero__frame {
  display: grid;
  place-items: center;
  width: 100%;
  height: max(160px, calc(100svh - var(--lobby-banner, 0px) - var(--header-h)));
  margin: 0 auto;
  container-type: size;
}

/* The stage: sized per view (VIEW blocks). */
.lobby-stage {
  position: relative;
  isolation: isolate;
  container-type: inline-size;
}

/* Stacking on the stage (system-geometry.mjs uses the same numbers): orbit lines 1, planets behind the sun 10-29,
   the sun 30, the orbit lines where they cross the sun 31, planets in front 32-51, leader lines 60, labels 61,
   headline 70. */
.lobby-intro {
  position: absolute;
  top: var(--top);
  left: 50%;
  z-index: 70;
  width: max-content;
  text-align: center;
  transform: translateX(-50%);
}

.lobby-intro__title {
  /* The spacing after the last letter would push the centred title to the left. */
  margin: 0 -0.12em 0 0;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.lobby-intro__sub {
  color: var(--on-dark-muted);
  text-wrap: balance;
}

/* The menu of the solar systems under the headline (systemSwitch in templates/lobby.mjs): a row per system, one link
   each, its name in a pill, its hook beside it and its tag after the hook's last word; the pill of the one shown here
   filled (aria-current), the others links to their lobbies. The pills stand in one column as wide as the widest (the
   rows share the menu's two columns: subgrid), so the hooks start level. In both views and on every stage: where a row
   does not fit the intro on one line (phones held either way, small windows), its hook wraps beside its pill and the
   row grows with it. No subline under it: the rows carry this system's hook (lobby.mjs prints none with a menu). Its
   rows' least height, the gaps, its type and the hooks' line height are SWITCH in system-geometry.mjs per view (the
   VIEW blocks set them), which the build lays the intro out with: keep them equal. */
.lobby-switch {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--sw-hook-gap);
  row-gap: var(--sw-row-gap);
  width: fit-content;
  max-width: 100%;
  margin: var(--sw-gap) auto 0;
  text-align: start;
}

.lobby-switch__link {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: center;
  min-height: var(--sw-h);
  border-radius: 999px;
  color: rgb(var(--on-dark-rgb) / 0.78);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}

.lobby-switch__name {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--sw-h);
  padding: 0 var(--sw-pad);
  border: 1px solid var(--chip-line);
  border-radius: 999px;
  background-color: var(--chip-fill);
  font-family: var(--font-display);
  font-size: var(--sw-font);
  letter-spacing: 0.14em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color 0.25s ease, border-color 0.25s ease, background-color 0.25s ease;
}

/* 1.25: SWITCH's hookLh. Balanced, so a wrapped hook's lines are about as long. */
.lobby-switch__hook {
  color: var(--on-dark-muted);
  font-size: var(--sw-hook-font);
  line-height: 1.25;
  text-wrap: balance;
  transition: color 0.25s ease;
}

/* The hook's last word and the tag never part: the build wraps them as one. */
.lobby-switch__end {
  white-space: nowrap;
}

/* The tag (Eridu's "Deeper data"): a small outlined chip after the hook, never under 11px. Inline, with the hook's
   line height, so a line that carries it is no taller than the others (the build counts lines, not chips). */
.lobby-switch__tag {
  margin-left: var(--sw-tag-gap);
  padding: 1px 7px;
  border: 1px solid rgb(var(--on-dark-rgb) / 0.3);
  border-radius: 999px;
  color: rgb(var(--on-dark-rgb) / 0.82);
  font-size: 11px;
  line-height: 1.25;
}

.lobby-switch__link:hover .lobby-switch__name,
.lobby-switch__link:focus-visible .lobby-switch__name {
  border-color: rgb(var(--on-dark-rgb) / 0.6);
  color: var(--on-dark);
}

.lobby-switch__link:hover .lobby-switch__hook,
.lobby-switch__link:focus-visible .lobby-switch__hook {
  color: var(--on-dark);
}

.lobby-switch__link:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* The systems menu zoomed out (lobby-systems.js; the owner's idea, a first version): the "Systems" control, a round
   pill in the menu's style with two small suns in their orbits (its word for screen readers), in the room left of the
   headline over the menu's pills, left out where there is none (.is-out); the script sets its top (--sys-top). It
   opens a card over the dimmed and scaled stage with every system, each with a tiny sun. No control with motion off,
   on paper or without JavaScript: the menu's links are the way there. */
.lobby-systems {
  position: absolute;
  top: var(--sys-top, 0px);
  left: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--sw-h);
  height: var(--sw-h);
  padding: 0;
  border: 1px solid var(--chip-line);
  border-radius: 999px;
  background-color: var(--chip-fill);
  color: rgb(var(--on-dark-rgb) / 0.82);
  font-family: var(--font-display);
  font-size: calc(var(--sw-font) * 0.9);
  letter-spacing: 0.1em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color 0.25s ease, border-color 0.25s ease, background-color 0.25s ease;
}

.lobby-systems__icon {
  flex: none;
}

.lobby-systems__word {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

.lobby-systems.is-out {
  display: none;
}

.lobby-systems:hover,
.lobby-systems:focus-visible,
.lobby-systems[aria-expanded="true"] {
  border-color: rgb(var(--on-dark-rgb) / 0.6);
  color: var(--on-dark);
}

.lobby-systems[aria-expanded="true"] {
  background-color: rgb(var(--on-dark-rgb) / 0.14);
}

.lobby-systems:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* Over the hero, above the stage: a backdrop that takes the click outside the card, and the card in the middle. */
.lobby-systems-layer {
  position: absolute;
  inset: var(--header-h) 0 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: 16px;
}

.lobby-systems-layer[hidden] {
  display: none;
}

.lobby-systems__backdrop {
  position: absolute;
  inset: calc(var(--header-h) * -1) 0 0;
}

.lobby-systems__card {
  position: relative;
  width: min(440px, 100%);
  padding: 18px 16px 12px;
  border: 1px solid var(--line-dark);
  border-radius: var(--radius);
  background: rgb(var(--space-2-rgb) / 0.94);
  box-shadow: 0 24px 64px rgb(var(--night-rgb) / 0.55);
}

.lobby-systems__title {
  margin: 0 8px 10px;
  color: var(--on-dark-muted);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.lobby-systems__list {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.lobby-systems__item {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  column-gap: 12px;
  align-items: center;
  padding: 10px 12px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--on-dark);
  text-decoration: none;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}

.lobby-systems__item:hover,
.lobby-systems__item:focus-visible {
  background-color: rgb(var(--on-dark-rgb) / 0.06);
}

.lobby-systems__item[aria-current="page"] {
  border-color: rgb(var(--on-dark-rgb) / 0.3);
}

.lobby-systems__item:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* A tiny sun: the lobby's, white-hot at the middle and warm at the edge. */
.lobby-systems__sun {
  grid-row: span 2;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: radial-gradient(circle at 45% 42%, rgb(255 250 240), rgb(var(--sun-glow)) 46%, rgb(var(--sun-glow) / 0.35) 70%, rgb(var(--sun-glow) / 0) 100%);
}

.lobby-systems__name {
  font-family: var(--font-display);
  font-size: 0.875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.lobby-systems__hook {
  color: var(--on-dark-muted);
  font-size: 0.875rem;
  line-height: 1.35;
}

.lobby-systems__tag {
  display: inline-block;
  margin-left: 4px;
  padding: 0 7px;
  border: 1px solid rgb(var(--on-dark-rgb) / 0.3);
  border-radius: 999px;
  color: rgb(var(--on-dark-rgb) / 0.82);
  font-size: 11px;
  line-height: 1.5;
}

html[data-motion="off"] .lobby-systems,
html[data-motion="off"] .lobby-systems-layer {
  display: none;
}

@media print {
  .lobby-systems,
  .lobby-systems-layer {
    display: none;
  }
}

@media (forced-colors: active) {
  .lobby-systems,
  .lobby-systems__card {
    border-color: ButtonText;
  }
}

/* The system shown: its pill filled in cream, as a lit chip, and not a link to itself in looks (it is not one to the
   eye either: it stays where it is). */
.lobby-switch__link[aria-current="page"] {
  color: var(--on-dark);
  cursor: default;
}

.lobby-switch__link[aria-current="page"] .lobby-switch__name {
  border-color: rgb(var(--on-dark-rgb) / 0.75);
  background-color: rgb(var(--on-dark-rgb) / 0.14);
}

.lobby-switch__link[aria-current="page"] .lobby-switch__hook {
  color: var(--on-dark);
}

@media (forced-colors: active) {
  .lobby-switch__name {
    border-color: LinkText;
  }

  .lobby-switch__link[aria-current="page"] .lobby-switch__name {
    border-color: CanvasText;
    border-width: 2px;
  }
}

/* A site of one solar system has no menu: the subline follows the headline at the menu's gap (layout.mjs lays it out
   so, and the lift's --w-intro-rest). */
.lobby-intro__title + .lobby-intro__sub {
  margin-top: var(--sw-gap) !important;
}

.lobby-orbits {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

/* Below every planet: the far halves of the orbits, and the near halves outside the sun's box. */
.lobby-orbits--back {
  z-index: 1;
}

/* The near halves inside the sun's box only (clipped to it in lobby.mjs), so they pass in front of the sun. */
.lobby-orbits--front {
  z-index: 31;
}

.lobby-orbit {
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  transition: stroke 0.3s ease;
}

/* The orbits' gradient (lobby.mjs) in the orbit colour; the attributes there are the fallback. */
.lobby-orbits stop {
  stop-color: rgb(var(--orbit-rgb));
}

/* Hovering or focusing a planet lights up its orbit (and keeps it lit while it departs: .is-lit, lobby.js): one rule
   per orbit of the system, which templates/lobby.mjs writes into the page's <head> (orbitLight), so a system of any
   size has them. */

/* The sun: a small, hot star with a dim, warm glow. */
.lobby-sun {
  position: absolute;
  left: var(--x);
  top: var(--y);
  z-index: 30;
  width: var(--size);
  height: var(--size);
  margin: calc(var(--size) / -2) 0 0 calc(var(--size) / -2);
  pointer-events: none;
}

.lobby-sun__img {
  position: relative;
  width: 100%;
  height: 100%;
  /* Warm white with a golden glow (--sun-filter), a distant star rather than an orange ball. */
  filter: var(--sun-filter);
}

/* A white-hot core and a thin warm limb in the sun's glow, so the photo reads as a burning star and not a ball. */
.lobby-sun__core {
  position: absolute;
  inset: 20.5%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgb(255 252 246), rgb(var(--sun-glow) / 0.8) 50%, rgb(var(--sun-glow) / 0.25) 85%, rgb(var(--sun-glow) / 0) 100%);
  box-shadow: 0 0 7.8px 1.95px rgb(var(--sun-glow) / calc(0.325 * var(--core-p, 1))), 0 0 26px 6.5px rgb(var(--sun-glow) / calc(0.13 * var(--core-p, 1)));
  mix-blend-mode: screen;
}

/* Inner glow (tight, warm) and the faint haze around it. Both at 0.65 of their first strength and reach beyond the
   disc: enough of a corona to read as a star, while the halo no longer washes over the inner planets. */
.lobby-sun::before,
.lobby-sun::after {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 50%;
  pointer-events: none;
}

.lobby-sun::before {
  inset: -90.5%;
  background: radial-gradient(closest-side, rgb(var(--sun-glow) / 0.078), rgb(var(--sun-glow) / 0.029) 45%, rgb(var(--sun-glow) / 0) 100%);
}

.lobby-sun::after {
  inset: 9.6%;
  background: radial-gradient(closest-side, rgb(var(--sun-glow) / 0.26), rgb(var(--sun-glow) / 0.078) 62%, rgb(var(--sun-glow) / 0) 100%);
}

/* The sun's light breathes slowly, with motion on and calm (and without JavaScript, but for the system's reduced
   motion: base.css). Nothing moves that you can click. */
:where(html:not([data-motion="off"])) .lobby-sun::before {
  animation: lobby-breathe 9s ease-in-out infinite alternate;
}

@keyframes lobby-breathe {
  from {
    opacity: 0.7;
    transform: scale(0.96);
  }

  to {
    opacity: 1;
    transform: scale(1.04);
  }
}

/* The sun alive (lobby-life.js; tools/SPEC_LOOK_2026-10-09.md 2): a corona round the disc that breathes, a glow over
   the core that comes and goes on another period, and a flare that brightens one side of the corona now and then.
   Hidden until the script animates them (.is-alive on the stage: motion on or calm, never on a weak device), so
   without it the sun is what it was. The corona and the flare lie behind the disc (the photo or the living sun's
   canvas), the glow over it. Opacity and transform only, on these small layers. While they run, the haze's own
   breathing (::before, above) rests at its middle, so the sun breathes on the two periods of the script. */
.lobby-sun__corona,
.lobby-sun__flare,
.lobby-sun__glow {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
}

.lobby-sun__corona {
  inset: -36%;
  z-index: -1;
  background: radial-gradient(closest-side, rgb(var(--sun-glow) / 0.11), rgb(var(--sun-glow) / 0.04) 52%, rgb(var(--sun-glow) / 0) 100%);
}

/* One side brightens: the light sits right of centre, and the script turns the layer toward the side it picks. */
.lobby-sun__flare {
  inset: -60%;
  z-index: -1;
  background: radial-gradient(30% 24% at 70% 50%, rgb(255 226 186 / 0.5), rgb(var(--sun-glow) / 0.16) 55%, rgb(var(--sun-glow) / 0) 100%);
}

.lobby-sun__glow {
  inset: 18%;
  z-index: 2;
  background: radial-gradient(closest-side, rgb(255 250 240 / 0.55), rgb(var(--sun-glow) / 0.2) 58%, rgb(var(--sun-glow) / 0) 100%);
  mix-blend-mode: screen;
}

.lobby-stage.is-alive .lobby-sun::before {
  opacity: 0.85; /* the haze's own breathing at its middle */
  animation: none;
}

/* The photos' glint (the globes pulse and glint in their own frames, lobby-planets3d.js): when the sun flares toward
   a planet (.is-glint, 1.6 s), the light on its sun side (its ::after, the lit globe below) lifts for a moment. Gone
   at once when the lobby rests. The photos have no slow pulse: the light's ::after is restyled with the planet on the
   main thread, and a pulse running on it raised the photo lobby's style work by a fifth (the frame budget allows a
   tenth), whichever way it was driven. */
.lobby-stage.is-alive:not(.is-resting) .lobby-planets:not(.is-3d, .is-3d-in, .is-3d-out) .lobby-planet.is-glint:not(.is-3d) .lobby-planet__body::after {
  animation: lobby-glint 1.6s ease-in-out;
}

@keyframes lobby-glint {
  50% {
    filter: brightness(1.7);
  }
}

/* The headline's entrance (lobby-life.js): hidden before the first paint where it will play (html.lobby-text-wait,
   from the page's <head>: templates/lobby.mjs), then its words rise and fade in one after another (each in a
   .lobby-word, inline-block so it can rise) and the menu's rows after them. Never on paper. */
.lobby-text-wait .lobby-intro {
  opacity: 0;
}

.lobby-word {
  display: inline-block;
}

@media print {
  .lobby-text-wait .lobby-intro {
    opacity: 1;
  }
}

/* ------------------------------------------------------------------ the planets */
/* No stacking context of its own: each planet's --z (from lobby.mjs, then lobby-orbits.js) puts it behind or in
   front of the sun, so planets pass behind the sun. Every orbit line passes behind every planet: the only lines
   above the sun are the near halves inside its box, which no planet behind the sun reaches (orbitsSvg in
   lobby.mjs). */
.lobby-planets {
  position: absolute;
  inset: 0;
  list-style: none;
  margin: 0;
  padding: 0;
}

.lobby-planet {
  --bare: 0; /* 1 on the smallest stages (the VIEW blocks): no label drawn at rest, below */
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: 0;
  height: 0;
}

/* Each planet's own colours, those of its buy page: its look's palette (.look-*, base.css) turned by its own tone,
   which templates/lobby.mjs writes on the planet (--tint, --tint-hi, --planet-tone: templates/appearance.mjs). --tint
   is its glow and the wash behind it when it is hovered, focused or pressed, and its lighter tone (--tint-hi) its
   chip's hairline and its leader line, so a lit chip stands out more than a resting one on the wash too. Lit, the
   hairline and the line are the same colour, so they meet as one stroke; set here and on the departure's copy, which
   takes the planet's colours (lobby.js), since a custom property takes --tint-hi where it is declared. */
.lobby-planet,
.lobby-fly {
  --chip-line-lit: rgb(var(--tint-hi, var(--on-dark-rgb)) / 0.9);
}

/* How lit the planet is: 0 at rest, 1 hovered or focused, and for the wash also while it departs (.is-lit).
   Registered numbers, so they fade on the link and all under it takes the same value in the same frame: the wash
   behind the planet and the sky tone its night side ends on (--wash-k, at the wash's pace), and the glow on its sun
   side or round Saturn (--glow-k). Only these numbers move, never the filters and shadows they go into, which
   lobby-orbits.js restyles as the planet turns: a transition there would start again on every step, so the photo's
   filter has none (the lit globe, below). Where they are not registered they switch at once. */
@property --wash-k {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

@property --glow-k {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

/* The photo's share of the light round its disc (the hover glow, the haze and the occlusion): 1, but from 1 to 0 while a
   late globe fades in over the photo (lobby-planets3d.js), so the photo's gives way to the globe's glow and halo as
   the globe comes, rather than the two adding up. */
@property --glow-p {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

/* The photo sun's core glow (its box-shadow, round the core): 1, but from 1 to 0 while the living sun fades in over
   the photo (lobby-planets3d.js), with the living sun's corona, which takes its place. */
@property --core-p {
  syntax: "<number>";
  inherits: false;
  initial-value: 1;
}

/* The disc's radius as a share of its wash's (the lit globe, below). */
@property --wr {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

/* The lit globe's colours, worked out on the link from the numbers above (below): registered, so they are resolved
   there once, and the night side, restyled on every step of the orbit, takes plain colours instead of a chain of
   color-mix() to resolve each time. */
@property --sky-w { syntax: "<color>"; inherits: true; initial-value: transparent; }
@property --night-w { syntax: "<color>"; inherits: true; initial-value: transparent; }
@property --lobby-night { syntax: "<color>"; inherits: true; initial-value: transparent; }
@property --skyshine { syntax: "<color>"; inherits: true; initial-value: transparent; }
@property --occl { syntax: "<color>"; inherits: true; initial-value: transparent; }
@property --glow-c { syntax: "<color>"; inherits: true; initial-value: transparent; }
@property --haze-lit { syntax: "<color>"; inherits: true; initial-value: transparent; }

.lobby-planet__link {
  --wash-k: 0;
  --glow-k: 0;
  position: relative;
  display: block;
  color: var(--on-dark);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: --wash-k 0.5s ease, --glow-k 0.4s ease;
}

.lobby-planet__link:is(:hover, :focus-visible, .is-lit) {
  --wash-k: 1;
}

.lobby-planet__link:is(:hover, :focus-visible) {
  --glow-k: 1;
}

.lobby-planet__link:focus-visible {
  outline: none;
}

/* The planet's body, its leader line and its label each sit in a wrapper (templates/lobby.mjs) at the planet's place,
   which carries their stacking on the stage (the body behind or in front of the sun by --z, the lines over every
   planet, the labels over the lines) and which the orbits move (lobby-orbits.js: a translate, and the body's a
   scale): a wrapper's style is that and nothing else, so a frame of the orbits restyles three small boxes per planet,
   never the planet's light or its label. */
.lobby-planet__pos {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}

.lobby-planet__pos--body {
  z-index: var(--z);
}

.lobby-planet__pos--lead {
  z-index: 60;
}

.lobby-planet__pos--label {
  z-index: 61;
}

/* The image box is bigger than the disc (disc = --sd of the box), so it is placed around the planet's centre. A
   stacking context of its own (the sun-side light blends with this planet only). */
.lobby-planet__body {
  position: absolute;
  left: calc(var(--size) / -2);
  top: calc(var(--size) / -2);
  z-index: 0;
  width: var(--size);
  height: var(--size);
  pointer-events: none;
  transition: transform 0.4s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* Each planet's tone (--planet-filter, base.css: warmer, brighter and more colourful than the file, as its globe is),
   the same as on its buy page, then the lobby's lift that matches it to its globe here (--lobby-lift, base.css), and
   then a little crisper and brighter, so the planets read as near, lit bodies, and last the planet's own tone
   (--planet-tone: templates/appearance.mjs), which its globe takes last too (lobby-planets3d.js). lobby.js copies the
   filter into the departure. */
.lobby-planet__img {
  width: 100%;
  height: 100%;
  filter: var(--planet-filter) var(--lobby-lift,) brightness(1.08) contrast(1.07) saturate(1.06) var(--planet-tone,);
  transition: filter 0.4s ease;
}

/* The light on each planet: a crisp rim on the limb that faces the sun and a faint haze just outside it, coloured by
   the planet's air (warm for Jupiter and Mars, blue for Earth and Neptune). Sized in the disc, so it is the same on
   every planet and every stage. */
.lobby-planet {
  --rim: rgba(255, 246, 234, 0.62);
  --haze: rgba(255, 236, 214, 0.2);
}

.lobby-planet--ocean {
  --rim: rgba(226, 238, 255, 0.66);
  --haze: rgba(150, 190, 255, 0.24);
}

.lobby-planet--ice {
  --rim: rgba(214, 228, 255, 0.6);
  --haze: rgba(120, 156, 255, 0.24);
}

/* Lit toward the sun: the angle and the size of the night side come from shade() in system-geometry.mjs, written
   by lobby.mjs at build time and then by lobby-orbits.js while orbiting. The shade is turned so its +x points away
   from the sun: an inset shadow pushed to +x lights the sun-side limb (the rim), an outer one pulled to -x lies
   outside it (the haze), and both turn with the planet as it orbits. lobby.js copies the box-shadow into the
   departure, so the crescent keeps the rim. */
.lobby-planet__shade {
  position: absolute;
  inset: calc((1 - var(--sd)) * 50%);
  border-radius: 50%;
  transform: rotate(var(--sa));
  background: linear-gradient(90deg, rgb(var(--globe-night-rgb) / 0) var(--s0), rgb(var(--globe-night-rgb) / 0.6) calc((var(--s0) + var(--s1)) / 2), var(--lobby-night) var(--s1));
  box-shadow:
    inset calc(var(--disc) * 0.06) 0 calc(var(--disc) * 0.04) calc(var(--disc) * -0.02) var(--rim),
    calc(var(--disc) * -0.02) 0 calc(var(--disc) * 0.1) calc(var(--disc) * -0.01) var(--haze);
  transition: opacity 0.4s ease;
}

/* Saturn: no haze, which would lie over the rings. */
.lobby-planet--ringed .lobby-planet__shade {
  box-shadow: inset calc(var(--disc) * 0.06) 0 calc(var(--disc) * 0.04) calc(var(--disc) * -0.02) var(--rim);
}

/* Saturn's rings: a softer shade over the whole photo, darkest on the side away from the sun. */
.lobby-planet__ringshade {
  position: absolute;
  inset: 0;
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  background: linear-gradient(calc(var(--sa) + 90deg), rgb(var(--globe-night-rgb) / 0) 45%, rgb(var(--globe-night-rgb) / 0.55) 90%);
}

.lobby-planet--ringed .lobby-planet__img {
  filter: var(--planet-filter) var(--lobby-lift,) contrast(1.07) saturate(1.04) var(--planet-tone,);
}

/* The hit area: at least 44 px (TAP in templates/layout.mjs), a little bigger than the planet. Saturn's rings are
   clickable too. While orbiting, the body is scaled by --k (lobby-orbits.js), so the 44px are divided by it. */
.lobby-planet__hit {
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(calc(44px / var(--k, 1)), calc(var(--disc) + 14px));
  aspect-ratio: 1;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  pointer-events: auto;
}

.lobby-planet__hit--ring {
  width: 96%;
  aspect-ratio: auto;
  height: 44%;
  transform: translate(-50%, -50%) rotate(var(--ring));
}

/* Hover or focus: the planet glows in its own colour (--tint), never the accent, and so do its leader line, the sky
   behind it and, above, its orbit. One glow: here a drop shadow on the photo, not the whole body, so the wash below is
   not filtered with it (lobby.js reads it there for the departure); where the lit globe is drawn (below) it is on the
   sun side instead, faded by --glow-k, and only Saturn keeps the drop shadow. */
.lobby-planet__link:is(:hover, :focus-visible) .lobby-planet__body {
  transform: scale(1.08);
}

.lobby-planet__link:is(:hover, :focus-visible) .lobby-planet__img {
  filter: var(--planet-filter) var(--lobby-lift,) brightness(1.08) contrast(1.07) saturate(1.06) var(--planet-tone,) drop-shadow(0 0 calc(var(--disc) * 0.24) rgb(var(--tint, var(--on-dark-rgb)) / 0.6));
}

.lobby-planet--ringed .lobby-planet__link:is(:hover, :focus-visible) .lobby-planet__img {
  filter: var(--planet-filter) var(--lobby-lift,) contrast(1.07) saturate(1.04) var(--planet-tone,) drop-shadow(0 0 calc(var(--disc) * 0.2) rgb(var(--tint, var(--on-dark-rgb)) / 0.6));
}

.lobby-planet__link:is(:hover, :focus-visible) .lobby-planet__shade {
  opacity: 0.82;
}

/* A faint wash of the planet's colour in the sky behind it, only while it is hovered or focused, and while it departs
   (.is-lit, also once the body is hidden). Inside the body, so it follows the planet along its orbit, under the
   photo. Hidden once it has faded out, so at rest it does not make the moving planet's layer as big as itself. */
.lobby-planet__body::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: -1;
  width: 64cqw;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgb(var(--tint, var(--on-dark-rgb)) / 0.34), rgb(var(--tint, var(--on-dark-rgb)) / 0.16) 34%, rgb(var(--tint, var(--on-dark-rgb)) / 0.05) 70%, rgb(var(--tint, var(--on-dark-rgb)) / 0) 100%);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -50%);
  transition: opacity 0.5s ease, visibility 0s linear 0.5s;
  pointer-events: none;
}

.lobby-planet__link:is(:hover, :focus-visible, .is-lit) .lobby-planet__body::before {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

/* ------------------------------------------------------------------ the lit globe */
/* The rules above draw the night side as a straight-edged half disc turned away from the sun, with the rim and haze,
   and stay for browsers without cos() or color-mix(). Where both exist this block lights each planet as a ball:
   the night side is the globe's own outline (an ellipse for Jupiter and Saturn, tools/photos/fit/geom.json), turned
   only by Saturn's ring tilt, and the light's direction comes in through cos/sin of --la (--sa less the tilt). Each
   layer is drawn on a disc-sized square (background-size), so its percentages are the disc's. Layers, top first: a
   veil of the sky over far planets, the sky's tone on the night limb (skyshine), the sun's warmth on the lit limb
   (sunlit), the night side and terminator (circles 3R wide centred 1R beyond the sun-side limb: on the sun axis the
   stops of shade(), off it the terminator bows toward the night side as on a ball), and limb darkening for the photos
   that have none (Earth, Mars). The body's ::after lifts the side that faces the sun (soft-light). The rim stays as
   above, turned by --la; the haze moves to the sun side, and a faint occlusion all round lets orbit lines and stars
   fade into the limb instead of stopping at a cut edge. Nearer planets are a little crisper, farther ones flatter
   (--dz from --s0). */
@supports (width: calc(cos(0deg) * 1px)) and (color: color-mix(in srgb, red 50%, blue)) {
  .lobby-planet {
    /* The sky is brightest round the sun: from --lobby-sky-near on the innermost orbit to --lobby-sky-far on the
       outermost, over the system's own number of orbits (--n on the list). */
    --f: clamp(0, 0.85 - var(--i) * 0.8 / max(1, var(--n, 5) - 1), 1);
    --sky-c: color-mix(in srgb, var(--lobby-sky-near) calc(var(--f) * 100%), var(--lobby-sky-far));
    /* The night side: 0.7 of the sky's tone and the rest the planets' night (--globe-night-rgb), so it still hides
       stars and lines but is never a black hole, and stays blue. */
    --night-c: color-mix(in srgb, var(--sky-c) 70%, rgb(var(--globe-night-rgb)));
    --night-a: 90%;
    --skyshine-a: 62%;
    --q: 1; /* the globe's polar / equatorial axis in the sphere file */
    --tilt: 0deg;
    --haze: rgb(255 236 214 / 0.24);
    --haze-w: 0.12;
    --sunlit: rgb(var(--sun-glow) / 0.22);
    --ld: 0;
    --light-c: 255 244 226;
    --light: 0.5;
  }

  /* Jupiter: oblate; a bright photo, so a denser night (at 0.9 it showed through as a grey disc); the photo's own limb
     is 0.03 of its centre, so it gets the most light. */
  .lobby-planet--gas {
    --q: 0.9595;
    --night-a: 95%;
    --haze: rgb(255 226 190 / 0.22);
    --light: 0.62;
  }

  /* Neptune: a blue atmosphere, cool light. */
  .lobby-planet--ice {
    --haze: rgb(120 156 255 / 0.34);
    --haze-w: 0.14;
    --sunlit: rgb(170 196 255 / 0.16);
    --light-c: 226 236 255;
    --light: 0.55;
  }

  /* Earth: a thin bright blue atmosphere; the photo has no limb darkening (its limb is 2.85x its centre). */
  .lobby-planet--ocean {
    --haze: rgb(150 190 255 / 0.38);
    --haze-w: 0.1;
    --sunlit: rgb(var(--sun-glow) / 0.05);
    --ld: 0.25;
    --light: 0.4;
  }

  /* Mars: a faint dusty haze; a flat photo (limb 0.78x centre). */
  .lobby-planet--rocky {
    --haze: rgb(255 206 176 / 0.16);
    --haze-w: 0.08;
    --sunlit: rgb(var(--sun-glow) / 0.06);
    --ld: 0.22;
    --light: 0.6;
  }

  /* Saturn: globe q 0.92, rings tilted 7deg in the file (geom.json ringSphere: theta + ring.dtheta); no haze (it would
     lie over the rings); its night limb borders its own dark ring gap, so little skyshine. */
  .lobby-planet--ringed {
    --q: 0.92;
    --tilt: 7deg;
    --night-a: 94%;
    --haze: transparent;
    --skyshine-a: 20%;
    --sunlit: rgb(var(--sun-glow) / 0.15);
  }

  /* The night side, the skyshine and the occlusion end on the sky's tone, and while the planet is lit its wash
     (above) lies in the sky behind it: they take the wash's colour as it fades in (--wash-k), as much as the wash
     has at the limb, so the night side still fades into the sky there instead of standing as a dark-blue cut-out on
     the coloured sky. The wash's alpha at the limb follows its stops (0.34, 0.16 at 34%, 0.05 at 70%, 0 at the edge
     of its 64cqw), the disc's radius as a share of the wash's (--wr): less on bigger planets and in the tall view.
     --wr is registered, so it is a plain number here (Chrome resolved its cqw as 0 in the gradients). Declared on the
     link, where --wash-k moves, so the orbit's steps on the body leave them be; the departure copies the result. */
  .lobby-planet__link {
    --wr: tan(atan2(var(--disc), 64cqw));
    --ws: calc(var(--wash-k) * max(34% - 52.94% * var(--wr), 26.39% - 30.56% * var(--wr), 16.67% - 16.67% * var(--wr), 0%));
    --sky-w: color-mix(in srgb, rgb(var(--tint, var(--on-dark-rgb))) var(--ws), var(--sky-c));
    --night-w: color-mix(in srgb, rgb(var(--tint, var(--on-dark-rgb))) var(--ws), var(--night-c));
    --lobby-night: color-mix(in srgb, var(--night-w) var(--night-a), transparent);
    --skyshine: color-mix(in srgb, var(--sky-w) var(--skyshine-a), transparent);
    --occl: color-mix(in srgb, var(--sky-w) calc(42% * var(--glow-p, 1)), transparent); /* the sky's own tone: no dark ring on the blue */
    /* The hover glow (the shade, below; Saturn's drop shadow) and the haze, which gives way to it. */
    --glow-c: rgb(var(--tint, var(--on-dark-rgb)) / calc(var(--lobby-glow-a) * var(--glow-k) * var(--glow-p, 1)));
    --haze-lit: color-mix(in srgb, var(--haze) calc((100% - var(--glow-k) * 100%) * var(--glow-p, 1)), transparent);
  }

  /* Depth: --s0 is 45% - 22% * depth (shade()), from the build and then lobby-orbits.js: --dz is +22% in front, -22%
     at the very back. */
  .lobby-planet__body {
    --dz: calc(45% - var(--s0));
  }

  /* The planets' tone (--planet-filter) first, then nearer planets a little crisper, farther ones flatter: 111%/111%
     in front, 98%/100% at the back. No transition: --s0 changes while orbiting, and a filter transition would then
     run on every planet all the time. The same hovered or focused: the glow is on the sun side (the shade, below),
     not the photo's drop shadow round the whole silhouette, which outlines the night limb: the cut-out look. Saturn
     keeps the drop shadow (its night side is masked to the globe), at rest too, where --glow-k makes it nothing: it
     grows and fades with --glow-k as the filter's transition did. lobby.js takes it for the departure only while
     the planet is lit. */
  .lobby-planet .lobby-planet__img,
  .lobby-planet > .lobby-planet__link:is(:hover, :focus-visible) .lobby-planet__img {
    filter: var(--planet-filter) var(--lobby-lift,) saturate(1.06) contrast(calc(105% + var(--dz) * 0.3)) brightness(calc(106% + var(--dz) * 0.25)) var(--planet-tone,);
    transition: none;
  }

  .lobby-planet--ringed .lobby-planet__img,
  .lobby-planet--ringed > .lobby-planet__link:is(:hover, :focus-visible) .lobby-planet__img {
    filter: var(--planet-filter) var(--lobby-lift,) saturate(1.06) contrast(calc(105% + var(--dz) * 0.3)) brightness(calc(106% + var(--dz) * 0.25)) var(--planet-tone,) drop-shadow(0 0 calc(var(--disc) * 0.2 * var(--glow-k)) var(--glow-c));
  }

  /* Neptune's photo carries its own light, from 28deg (lower right); turned by --sa + 152deg it comes from the sun.
     One slow turn per orbit; the disc is nearly featureless. Goes when a neutrally lit Neptune file exists. */
  .lobby-planet--ice .lobby-planet__img {
    rotate: calc(var(--sa) + 152deg);
  }

  /* The sphere files' limb is a one-pixel alpha step premultiplied against black: a dark keyline, sharper than any
     star. Pulled in 0.5px (inside the keyline) and feathered over 0.9px in front, up to about 2px at the back.
     Saturn's own file is fixed instead (tools/photos/fix-ringed.mjs). */
  .lobby-planet:not(.lobby-planet--ringed) .lobby-planet__img {
    --fw: calc(0.9px + clamp(0%, var(--dz) * -0.22, 5%));
    -webkit-mask-image: radial-gradient(calc(var(--sd) * 50%) calc(var(--sd) * 50% * var(--q)) at 50% 50%, #000 calc(100% - 0.5px - var(--fw)), transparent calc(100% - 0.5px));
    mask-image: radial-gradient(calc(var(--sd) * 50%) calc(var(--sd) * 50% * var(--q)) at 50% 50%, #000 calc(100% - 0.5px - var(--fw)), transparent calc(100% - 0.5px));
  }

  .lobby-planet__shade,
  .lobby-planet__body::after {
    --la: calc(var(--sa) - var(--tilt)); /* the night direction in the element's own (tilted) frame */
    inset: calc((1 - var(--sd) * var(--q)) * 50%) calc((1 - var(--sd)) * 50%);
    border-radius: 50%;
    transform: rotate(var(--tilt));
    background-size: 100% calc(100% / var(--q));
    background-position: center;
    background-repeat: no-repeat;
  }

  .lobby-planet__shade {
    background-image:
      linear-gradient(rgb(var(--space-rgb) / clamp(0%, (var(--s0) - 45%) * 0.5, 11%)) 0 0),
      radial-gradient(50% 50% at calc(50% - cos(var(--la)) * 10%) calc(50% - sin(var(--la)) * 10%), transparent 86%, var(--skyshine) 108%),
      radial-gradient(50% 50% at calc(50% + cos(var(--la)) * 10%) calc(50% + sin(var(--la)) * 10%), transparent 78%, var(--sunlit) 120%),
      radial-gradient(150% 150% at calc(50% + cos(var(--la)) * (var(--s0) - 200%)) calc(50% + sin(var(--la)) * (var(--s0) - 200%)),
        transparent 72%,
        color-mix(in srgb, var(--night-w) 14%, transparent) 100%,
        color-mix(in srgb, var(--night-w) 62%, transparent) 110%,
        var(--lobby-night) 120%),
      radial-gradient(50% 50% at calc(50% - cos(var(--la)) * 15%) calc(50% - sin(var(--la)) * 15%), transparent 62%, rgb(var(--globe-night-rgb) / calc(var(--ld) * 0.45)) 90%, rgb(var(--globe-night-rgb) / var(--ld)) 112%);
    /* First, the hover glow on the sun side, in the planet's --tint (--glow-k: none at rest); it takes the haze's
       place, which fades out as it comes. lobby.js splits it off for the departure. */
    box-shadow:
      calc(cos(var(--la)) * var(--disc) * -0.3) calc(sin(var(--la)) * var(--disc) * -0.3) calc(var(--disc) * 0.3) calc(var(--disc) * -0.15) var(--glow-c),
      inset calc(cos(var(--la)) * var(--disc) * 0.06) calc(sin(var(--la)) * var(--disc) * 0.06) calc(var(--disc) * 0.04) calc(var(--disc) * -0.02) var(--rim),
      calc(cos(var(--la)) * var(--disc) * -0.07) calc(sin(var(--la)) * var(--disc) * -0.07) calc(var(--disc) * var(--haze-w)) calc(var(--disc) * -0.05) var(--haze-lit),
      0 0 calc(var(--disc) * 0.14) calc(var(--disc) * 0.01) var(--occl);
  }

  /* The sun-side light: soft-light over the photo, centred 0.6R toward the sun. The body is a stacking context
     (z-index), so it blends with this planet only. */
  .lobby-planet__body::after {
    content: "";
    position: absolute;
    background-image: radial-gradient(50% 50% at calc(50% - cos(var(--la)) * 30%) calc(50% - sin(var(--la)) * 30%),
      rgb(var(--light-c) / var(--light)) 0%, rgb(var(--light-c) / calc(var(--light) * 0.55)) 45%, transparent 100%);
    mix-blend-mode: soft-light;
    pointer-events: none;
  }

  .lobby-planet--ringed .lobby-planet__shade {
    box-shadow: inset calc(cos(var(--la)) * var(--disc) * 0.06) calc(sin(var(--la)) * var(--disc) * 0.06) calc(var(--disc) * 0.04) calc(var(--disc) * -0.02) var(--rim);
  }

  /* Saturn: the night side and the light skip the rings where they pass in front of the globe: the upper half in the
     ring frame, outside the B ring's inner edge (1.527R by 0.676R, here as shares of the 1 x 0.92 disc box). The thin
     C ring inside it lets the globe through, so it keeps the shade. */
  .lobby-planet--ringed .lobby-planet__shade,
  .lobby-planet--ringed .lobby-planet__body::after {
    -webkit-mask-image:
      linear-gradient(#000 0 0),
      radial-gradient(76.35% 36.76% at 50% 50%, transparent calc(100% - 0.6px), #000 calc(100% + 0.6px)),
      linear-gradient(to top, transparent calc(50% - 0.5px), #000 calc(50% + 0.5px));
    mask-image:
      linear-gradient(#000 0 0),
      radial-gradient(76.35% 36.76% at 50% 50%, transparent calc(100% - 0.6px), #000 calc(100% + 0.6px)),
      linear-gradient(to top, transparent calc(50% - 0.5px), #000 calc(50% + 0.5px));
    -webkit-mask-composite: source-out, source-in;
    mask-composite: subtract, intersect;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
  }

  /* Hovered or focused, the night side keeps its full strength (the glow is on its sun side). With 3D on the globe
     draws its own light, so this does not apply there. */
  .lobby-planets:not(.is-3d, .is-3d-out) > .lobby-planet:not(.lobby-planet--ringed, .is-3d) > .lobby-planet__link:is(:hover, :focus-visible) .lobby-planet__shade {
    opacity: 1;
  }
}

/* 3D globes on: the contract with the lobby's globes (lobby-planets3d.js; their canvases' own rules are under "the
   lobby in 3D" below). Its script puts .is-3d on the list once every globe has drawn its first frame (a planet may
   take it on its own, where its canvas is live), or, for globes that came late, once they have faded in over the
   photos and the photos have gone out under them (.is-3d-in, .is-3d-out below), and takes it off when the globes are
   dropped, so the photo comes back in the same frame, as it was. The globe draws its own light, terminator and atmosphere, so under .is-3d the photo
   and everything the CSS draws on it are off, at once and with no transition: the night side with its rim, haze,
   occlusion and sun-side hover glow (the shade), Saturn's ring shade, and the light on the sun side (the body's
   ::after); no hover rule can bring them back over a globe. The glow is then a drop shadow in --tint on the canvas,
   never on the body, whose ::before is the wash behind the planet, which stays, as do the chip, the leader line and
   the orbit's light. lobby-orbits.js still writes --sa, --s0 and --s1 there, which only these hidden layers read;
   lobby.js's departure copies the photo and these layers as they are drawn, and a live globe's last frame instead;
   and where the canvas is not drawn (forced colours, print) the photo comes back with both its opacity and its
   visibility. */
:is(.lobby-planets.is-3d, .lobby-planet.is-3d) :is(.lobby-planet__img, .lobby-planet__shade, .lobby-planet__ringshade) {
  opacity: 0;
  visibility: hidden;
  transition: none;
}

:is(.lobby-planets.is-3d, .lobby-planet.is-3d) .lobby-planet__body::after {
  content: none;
}

/* Leader line from the planet to its label: fainter at the planet, as bright as the chip's hairline where it ends, at
   the chip's rounded end (beside the planet). Below its planet (--stub 1) it runs on over the chip's padding to its
   top: the build's line ends labelGap (--chip-x) above the label, the chip begins --chip-y (0.3024 of the label's
   size) above it. Drawn as one line, so it stays straight where a separate stub was a fraction of a px off. One
   stroke from the planet into the control. The fade is a mask, so the colour can still change. */
.lobby-planet__lead {
  position: absolute;
  left: 0;
  top: -0.5px;
  z-index: 60;
  width: calc(var(--l1) - var(--l0) + var(--stub, 0) * max(0px, var(--chip-x) - 0.3024 * var(--label-size)));
  height: 1px;
  background: var(--chip-line);
  -webkit-mask-image: linear-gradient(90deg, rgba(0, 0, 0, 0.35), #000 85%);
  mask-image: linear-gradient(90deg, rgba(0, 0, 0, 0.35), #000 85%);
  transform-origin: 0 50%;
  transform: rotate(var(--la)) translateX(var(--l0));
  pointer-events: none;
  transition: background-color 0.25s ease;
}

.lobby-planet__link:is(:hover, :focus-visible, :active, .is-lit) .lobby-planet__lead {
  background: var(--chip-line-lit);
}

/* A departure lights the line in its first frame, as the name's copy has its lit chip from the start
   (.lobby-fly__name): faded in from cream, the line was still cream beside the coloured pill for most of the time
   it takes to go out. */
.lobby-planet__link.is-launching .lobby-planet__lead,
.lobby-planet__link.is-launching .lobby-planet__label::after {
  transition: none;
}

/* The label's font size is per view (VIEW blocks); everything in it is in em of that (LABEL in lobby.mjs). */
.lobby-planet__label {
  position: absolute;
  left: var(--lx);
  /* Side labels: the name sits on the line (half the name's line: 0.756em * 1.3 / 2). Top/bottom labels sit
     above/below its end. */
  top: calc(var(--ly) - var(--ny) * 0.4914em);
  z-index: 61;
  display: block;
  width: var(--lw);
  /* The name's line is the name's own (an inline-block, below); the hook sets its own line height. */
  line-height: 0;
  text-align: var(--ta);
  text-shadow: var(--lobby-text-shadow);
  /* A soft cloud of the sky's blue behind the text, so orbit lines never run through the words: light and wide, so it
     never shows as a box on the blue. */
  background: rgb(var(--space-rgb) / 0.32);
  border-radius: 0.6em;
  box-shadow: 0 0 1.4em 1em rgb(var(--space-rgb) / 0.32);
  transform: translate(calc(var(--ax) * -100%), calc(var(--ay) * -100%));
}

/* An inline-block, so the label's alignment (lobby.css, or lobby-orbits.js while orbiting) puts its chip left, right
   or in the middle, and exactly as tall as the block it was: no glyph moves. */
.lobby-planet__name {
  --chip-y: 0.4em; /* the chip's padding above and below the name; --chip-x beside it is per view (VIEW blocks) */
  position: relative;
  display: inline-block;
  vertical-align: top;
  color: var(--lobby-name);
  font-family: var(--font-display);
  font-size: 0.756em;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: 0.1em;
  white-space: nowrap;
  text-transform: uppercase;
  transition: color 0.25s ease;
}

.lobby-planet__hook {
  display: block;
  margin-top: 0.3em;
  color: var(--lobby-hook);
  line-height: 1.4;
  text-wrap: pretty;
  transition: color 0.25s ease;
}

/* The chip: a thin pill round the name and its arrow that says "link" at rest and fills when lit. Drawn outside the
   label's layout box, so the size the build and lobby-orbits.js lay out with does not change (they count it in with
   withChip, system-geometry.mjs): --chip-x beside the name, which is the build's labelGap, so on the line's side it
   begins exactly where the leader line ends, and --chip-y above and below. Behind the text and above the label's dark
   cloud (the label is the stacking context). A little more light along its top edge: a lit object, not a box. The
   whole pill is part of the link (a hit on it is the name's), so all of what looks like a button lights and opens;
   the build and lobby-orbits.js keep it clear of the other labels, planets and tap targets. */
.lobby-planet__name::before {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--chip-y)) calc(-1 * var(--chip-x));
  z-index: -1;
  border: 1px solid var(--chip-line);
  border-radius: 999px;
  background-color: var(--chip-fill);
  background-image: linear-gradient(rgb(var(--on-dark-rgb) / 0.06), rgb(var(--on-dark-rgb) / 0) 70%);
  box-shadow: inset 0 1px 0 rgb(var(--on-dark-rgb) / 0.07);
  pointer-events: auto;
  transition: background-color 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}

/* The stub: above its planet where the label is its name only (the steps in the VIEW blocks), the line ends
   labelGap below the label, and this closes the rest of the way to the chip's bottom (0.3024em: the chip's padding,
   0.4 of the name's em). --stub-t is 1 there (lobby.mjs per view, lobby-orbits.js while orbiting). With its hook the
   label ends in the hook, as before. */
.lobby-planet__label::after {
  content: "";
  position: absolute;
  left: 50%;
  top: calc(100% + 0.3024em);
  width: 1px;
  height: max(0px, calc(var(--chip-x) - 0.3024em));
  background: var(--chip-line);
  opacity: 0;
  transform: translateX(-50%);
  pointer-events: none;
  transition: background-color 0.25s ease;
}

/* The arrow's box is a little more than the name's cap height (0.75em), centred on the capitals. Part of the chip, a
   shade brighter than the hook. */
.lobby-planet__arrow {
  display: inline-block;
  width: 0.89em;
  height: 0.89em;
  margin-left: 0.36em;
  vertical-align: -0.07em;
  color: rgb(var(--on-dark-rgb) / 0.72);
  transition: transform 0.25s ease, color 0.25s ease;
}

.lobby-planet__link:is(:hover, :focus-visible, :active) .lobby-planet__name {
  color: var(--on-dark);
}

.lobby-planet__link:is(:hover, :focus-visible, :active, .is-lit) .lobby-planet__hook {
  color: var(--lobby-hook-hover);
}

.lobby-planet__link:is(:hover, :focus-visible) .lobby-planet__arrow {
  color: var(--on-dark);
}

.lobby-planet__link:hover .lobby-planet__arrow {
  transform: translateX(min(3px, calc(var(--chip-x) - 1px))); /* inside the chip on small stages too */
}

/* Lit: hover, keyboard focus, a press (at once: lobby.js gives iOS the touch listener :active needs), and while
   departing (.is-lit, lobby.js). Only colour: nothing moves or changes size. */
.lobby-planet__link:is(:hover, :focus-visible, :active, .is-lit) .lobby-planet__name::before {
  border-color: var(--chip-line-lit);
  background-color: var(--chip-fill-lit);
  box-shadow: inset 0 1px 0 rgb(var(--on-dark-rgb) / 0.14), 0 0 1.2em rgb(var(--tint, var(--on-dark-rgb)) / 0.14);
}

.lobby-planet__link:is(:hover, :focus-visible, :active, .is-lit) .lobby-planet__label::after {
  background: var(--chip-line-lit);
}

.lobby-planet__link:active .lobby-planet__name::before {
  transition-duration: 0.06s;
}

/* Keyboard focus rings the chip itself: over its hairline, so it reaches only 1px beyond the pill and stays clear of
   the hook below at 11px labels too (outside the hairline it touched the hook's accents there). While the orbit has
   hidden the label (data-hidden, lobby-orbits.js) the ring goes round the planet's tap target instead, on Saturn
   round its rings. */
.lobby-planet__link:focus-visible .lobby-planet__name::before {
  outline: 2px solid var(--focus);
  outline-offset: -1px;
}

.lobby-planet[data-hidden] > .lobby-planet__link:focus-visible .lobby-planet__hit {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

.lobby-planet--ringed[data-hidden] > .lobby-planet__link:focus-visible .lobby-planet__hit:not(.lobby-planet__hit--ring) {
  outline: none;
}

.lobby-planet--ringed[data-hidden] > .lobby-planet__link:focus-visible .lobby-planet__hit--ring {
  outline-offset: 5px;
}

@media (forced-colors: active) {
  /* Lit too, and on the departure's copy: a colour that is not a system colour (the planet's --tint) would be forced
     to the link's. On Canvas, as a native button is, so it reads on whatever is behind it: the hero is Canvas there,
     with the photo's stars screened onto it in dark themes. */
  .lobby-planet__name::before,
  .lobby-planet__link:is(:hover, :focus-visible, :active, .is-lit) .lobby-planet__name::before,
  .lobby-planet__name.lobby-fly__name::before {
    border-color: CanvasText;
    background-color: Canvas;
  }

  /* The leader line and its stub are fills, which forced colours turn into Canvas, so they vanished (as the buttons'
     edges would, base.css): drawn in CanvasText, the pill's outline, at rest and lit, so the line still runs into
     the pill. */
  .lobby-planet__lead,
  .lobby-planet__label::after,
  .lobby-planet__link:is(:hover, :focus-visible, :active, .is-lit) .lobby-planet__lead,
  .lobby-planet__link:is(:hover, :focus-visible, :active, .is-lit) .lobby-planet__label::after {
    forced-color-adjust: none;
    background-color: CanvasText;
  }

  .lobby-planet__link:focus-visible .lobby-planet__name::before,
  .lobby-planet[data-hidden] > .lobby-planet__link:focus-visible .lobby-planet__hit {
    outline-color: Highlight;
  }
}

/* Orbiting (lobby-orbits.js): the script moves each planet's body, label and leader line by a translate from the
   place above every frame, gives the leader line its transform (angle and length change with the label's
   placement), and sets the night side, the stacking and the label's alignment. Slides, fades and the way round a
   planet are Web Animations from the script on the label's and the line's transform and opacity, so nothing here
   has a transition: one would start again every frame. */

/* Labels and leader lines get a layer of their own (their wrappers, which the orbits move), a thousandth of a degree
   off the pixel grid, so the compositor moves them by fractions of a pixel. Drawn in place, text snaps to whole
   pixels and ticks along behind its planet instead of gliding with it. The price: the layer alone can move label
   text by up to a pixel against the still picture, which happens while the entrance fades the labels in. */
.lobby-planets.is-orbiting :is(.lobby-planet__pos--label, .lobby-planet__pos--lead) {
  will-change: transform;
  rotate: 0.001deg;
}

/* The planets' bodies get a layer of their own while orbiting: the lit globe (night side, light, rim, haze) is too
   heavy to repaint every frame on the bigger planets. */
.lobby-planets.is-orbiting .lobby-planet__pos--body {
  will-change: transform;
}

/* Once the entrance is over its finished animations are let go, so the frames of the motion stay cheap. */
.lobby-planets.is-orbiting.is-entered :is(.lobby-planet__body, .lobby-planet__label, .lobby-planet__lead) {
  animation: none;
}

/* ------------------------------------------------------------------ the lobby in 3D (lobby-planets3d.js) */
/* Each planet's globe over its photo: centred on the photo's box and a share of it (--gw, --gh: the disc and its
   halo, Saturn with its rings), so the orbit's translate and scale and the hover scale carry it as they carry the
   photo. Its buffer is the disc at its biggest. It shows once the globes have taken over (.is-3d on the list, or on a
   planet), in the same frame as the photo and its CSS light go (the contract above), and so does the departure's copy
   of it. Hidden with visibility, as the photo is, so the two always trade places in one style change. */
.lobby-planet__gl {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--gw) * 100%);
  height: calc(var(--gh) * 100%);
  max-width: none;
  translate: -50% -50%;
  pointer-events: none;
  visibility: hidden;
  transition: filter 0.4s ease;
}

/* Shown as its body is: inherit, so a departing planet's hidden body (.is-launching, .is-flying) hides it too. */
:is(.lobby-planets.is-3d, .lobby-planet.is-3d) .lobby-planet__gl,
.lobby-fly .lobby-planet__gl {
  visibility: inherit;
}

/* Hover and focus on a globe, and a lit (departing) planet: the photo's glow, a drop shadow in the planet's --tint
   round the canvas (the disc and its halo; Saturn with its rings and the photo's 0.2), never on the body, whose wash
   stays as it is. .is-lit as the wash has it, so a fly-over's glow holds while the overlay is under the pointer and
   Escape gives it back as it was. A filter transition (above), as nothing in it changes while the planet orbits; none
   at rest, so a resting globe is drawn without a filter pass. lobby.js reads it here for the departure. */
.lobby-planet__link:is(:hover, :focus-visible, .is-lit) .lobby-planet__gl {
  filter: drop-shadow(0 0 calc(var(--disc) * 0.24) rgb(var(--tint, var(--on-dark-rgb)) / var(--lobby-glow-a)));
}

.lobby-planet--ringed .lobby-planet__link:is(:hover, :focus-visible, .is-lit) .lobby-planet__gl {
  filter: drop-shadow(0 0 calc(var(--disc) * 0.2) rgb(var(--tint, var(--on-dark-rgb)) / var(--lobby-glow-a)));
}

/* Back to the photos: their shade comes back with them, not after its 0.4 s transition (an unshaded photo would show
   meanwhile), and so does a photo that was fading out under a late globe; after the watchdog gave up the globes also
   fade out over them (seen until they are gone). */
.lobby-planets.is-snap :is(.lobby-planet__img, .lobby-planet__shade, .lobby-planet__ringshade),
.lobby-planets.is-snap .lobby-planet__body::after {
  transition: none;
}

.lobby-planets.is-3d-fade .lobby-planet__gl,
.lobby-sun.is-3d-fade .lobby-sun__gl {
  visibility: inherit;
  opacity: 0;
  transition: opacity 0.3s ease;
}

/* Globes that came after the entrance fade in over the photos in view (lobby-planets3d.js, fadeIn: the script fades
   each canvas from nothing): shown here meanwhile, while the photos and their CSS light stay as they are underneath.
   Above all of the photo's layers (the body is a stacking context, so this orders within the planet only; the wash,
   its ::before, stays at the back): the sun-side light, its ::after, would otherwise lie over the fading globe and
   brighten it, until it went. Once the globes are in at full the photos go out under them (.is-3d-out), the photo
   first and then its light, so what shows through a globe's translucent night side and halo is never an unshaded
   photo and never goes at once; then .is-3d, as above. The living sun is drawn over its photo for all of it (its
   glow and its prominence go while it comes: SUN_OUT and PHOTO_OUT in lobby-planets3d.js), rather than under it as
   when it takes over unseen. */
.lobby-planets.is-3d-in .lobby-planet__gl {
  visibility: inherit;
  z-index: 1;
}

.lobby-planets.is-3d-out .lobby-planet__img,
.lobby-planets.is-3d-out .lobby-planet__body::after {
  opacity: 0;
  transition: opacity 0.3s ease;
}

.lobby-planets.is-3d-out :is(.lobby-planet__shade, .lobby-planet__ringshade) {
  opacity: 0;
  transition: opacity 0.3s ease 0.3s;
}

.lobby-sun.is-3d-in .lobby-sun__gl {
  z-index: 1;
  opacity: 1;
}

/* The living sun in place of the photo, its core and inner glow (the wide haze, ::before, stays). It takes over while
   the entrance waits for the globes, so it comes in softly. */
.lobby-sun__gl {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  opacity: 0;
}

.lobby-sun.is-3d .lobby-sun__gl {
  opacity: 1;
  transition: opacity 0.6s ease;
}

.lobby-sun.is-3d > :is(.lobby-sun__img, .lobby-sun__core),
.lobby-sun.is-3d::after {
  opacity: 0;
  transition: opacity 0.6s ease;
}

/* Back to the photos (lobby-planets3d.js, snapBack): the photo sun at once, as the planets' photos. */
.lobby-sun.is-snap > :is(.lobby-sun__img, .lobby-sun__core),
.lobby-sun.is-snap::after {
  transition: none;
}

/* No canvas is drawn in forced colours or on paper: the photos, their CSS light and the photo sun come back, with
   their visibility as well as their opacity, as if no globe had been there. */
@media (forced-colors: active), print {
  .lobby-planet__gl,
  .lobby-sun__gl,
  .lobby-fly__frame {
    display: none;
  }

  :is(.lobby-planets.is-3d, .lobby-planet.is-3d) :is(.lobby-planet__img, .lobby-planet__shade, .lobby-planet__ringshade),
  .lobby-planets:is(.is-3d-in, .is-3d-out) :is(.lobby-planet__img, .lobby-planet__shade, .lobby-planet__ringshade),
  .lobby-planets:is(.is-3d-in, .is-3d-out) .lobby-planet__body::after,
  .lobby-sun:is(.is-3d, .is-3d-in) > :is(.lobby-sun__img, .lobby-sun__core),
  .lobby-sun:is(.is-3d, .is-3d-in)::after {
    opacity: 1 !important; /* over the late fade's fill-forwards animations too (fadeIn), which outrank a plain value */
    visibility: visible;
    transition: none; /* also all through a late fade (.is-3d-in, .is-3d-out) */
  }

  :is(.lobby-planets.is-3d, .lobby-planet.is-3d) .lobby-planet__body::after {
    content: "";
  }

  /* The light round each photo and the photo sun's core glow, which the late fade holds out too (fadeIn). */
  .lobby-planet__link {
    --glow-p: 1 !important;
  }

  .lobby-sun__core {
    --core-p: 1 !important;
  }
}

/* ------------------------------------------------------------------ the sky (lobby-sky.js) */
/* Nearer stars, twinkles, a rare comet and glint, built by lobby-sky.js. Behind the whole frame: the blue and the
   photo paint first, then the sky, then the stage. All motion is Web Animations from the script (no keyframes
   here), so the motion setting is handled in one place. On phones the sky is a band over the first screen (--sky-h). */
.lobby-sky {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  z-index: -1;
  height: var(--sky-h, 100%);
  pointer-events: none;
  contain: strict;
}

.lobby-sky__veil,
.lobby-sky__faint,
.lobby-sky__bright {
  position: absolute;
  inset: 0;
}

/* Pushes the photo back a shade (SKY_VEIL in lobby-sky.js), so the planets stay the brightest things. A neutral
   grey as light as the space tone (it was the space tone itself, which pushed the photo's stars toward blue): over the
   sky it changes almost nothing, over a star it takes a tenth toward grey. */
.lobby-sky__veil {
  background: rgb(27 27 27 / 0.1);
  background: oklch(from var(--space) l 0 0 / 0.1);
}

/* A star: a crisp dot close to a Gaussian (FWHM about a quarter of --d), centred on left/top, with no halo. --c is a
   space-separated RGB triplet (--star-rgb, lobby-sky.js), --a the rest brightness. It had a wider skirt (FWHM about a
   third of --d) until 2026-10-09, which read as fuzz. */
.lobby-sky__star,
.lobby-sky__swell {
  position: absolute;
  width: var(--d);
  height: var(--d);
  margin: calc(var(--d) / -2) 0 0 calc(var(--d) / -2);
  background: radial-gradient(closest-side, rgb(var(--c)), rgb(var(--c) / 0.6) 25%, rgb(var(--c) / 0.16) 50%, rgb(var(--c) / 0.02) 72%, rgb(var(--c) / 0) 86%);
  opacity: var(--a);
}

/* The brightest stars (HALO in lobby-sky.js: those of the chart's forty brightest on the screen, at most 15 % of the
   stars placed, and the bright four; 8 of 67 at 1440 x 900): a core one device pixel across (--px) at full strength,
   in a soft halo. */
.lobby-sky__star--halo {
  background: radial-gradient(closest-side, rgb(var(--c) / 0.9), rgb(var(--c) / 0.42) 14%, rgb(var(--c) / 0.14) 34%, rgb(var(--c) / 0.05) 58%, rgb(var(--c) / 0) 100%);
}

.lobby-sky__star--halo::after {
  content: "";
  position: absolute;
  left: calc(50% - var(--px) / 2);
  top: calc(50% - var(--px) / 2);
  width: var(--px);
  height: var(--px);
  background: rgb(var(--c));
}

/* A photo star brightening: placed on it when it swells. */
.lobby-sky__swell {
  opacity: 0;
}

/* Market constellations: faint chart figures between stars in the wide view's corners (lobby-sky.js, MARKS). */
.lobby-sky__marks {
  position: absolute;
  inset: 0;
}

.lobby-sky__lines {
  position: absolute;
  left: 0;
  top: 0;
  max-width: none;
  overflow: visible;
  fill: none;
  stroke: rgb(var(--lobby-sky-mark));
  stroke-linecap: round;
}

.lobby-sky__glint {
  position: absolute;
  opacity: 0;
}

.lobby-sky__glint svg,
.lobby-sky__dust {
  max-width: none;
}

/* The comet: everything is placed on its head, at the origin of .lobby-sky__comet, which the script moves. */
.lobby-sky__comet,
.lobby-sky__comet > * {
  position: absolute;
  left: 0;
  top: 0;
}

.lobby-sky__coma {
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px;
  background: radial-gradient(closest-side, rgb(var(--comet-coma) / 0.7) 12%, rgb(var(--comet-coma) / 0.24) 24%, rgb(var(--comet-coma) / 0.07) 55%, rgb(var(--comet-coma) / 0));
}

/* The ion tail: 1.2 px at the head, tapering to 0.4 px. */
.lobby-sky__ion {
  height: 1.2px;
  margin-top: -0.6px;
  transform-origin: 0 50%;
  background: linear-gradient(90deg, rgb(var(--comet-ion) / 0.3), rgb(var(--comet-ion) / 0));
  clip-path: polygon(0 0, 100% 33%, 100% 67%, 0 100%);
}

.lobby-sky__dust {
  height: 64px;
  margin-top: -32px;
  transform-origin: 0 32px;
}

@media (forced-colors: active), print {
  .lobby-sky {
    display: none;
  }
}


/* ------------------------------------------------------------------ the departure: eclipse (lobby.js) */
/* A plain click on a planet: copies of the planet and its name take the originals' place, the house lights go down
   around them, the planet's night side slides across it until only the logo's crescent is left, the logo's star
   stands beside it for a beat, and then it goes out. The lights go down into the strategy page's own space tone
   (.lobby-fly--<look>, base.css), and the page opens on the dark that is left. Every layer is fixed over the page,
   so it stays put whatever is scrolled; lobby.js animates transform and opacity only (and the orbit lines'
   stroke-opacity). The pointer is over the copies from the first frame, so a hovered planet would lose its hover
   look there: .is-lit keeps it (see the hover rules for the hook, the leader line and the orbit). */
.lobby-planet__link.is-launching .lobby-planet__body,
.lobby-planet__link.is-launching .lobby-planet__name {
  visibility: hidden;
}

/* As tall as the viewport with the mobile toolbars gone, so the last dark frame covers what they leave. */
.lobby-fly {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 1000;
  width: 100%;
  height: 100vh;
  height: 100lvh;
  contain: strict;
  touch-action: none;
  overscroll-behavior: none;
  cursor: pointer;
}

.lobby-fly__veil {
  position: absolute;
  inset: 0;
  background: var(--space);
  opacity: 0;
}

/* The planet copy, placed by lobby.js on the original (orbit, hover scale and all). --sd is the disc's share of the box.
   .lobby-fly__inner carries the original's fraction of a pixel (lobby.js, snap). */
.lobby-fly__planet,
.lobby-fly__inner,
.lobby-fly__body,
.lobby-fly__rings,
.lobby-fly__ringshade {
  position: absolute;
}

.lobby-fly__inner {
  width: 100%;
  height: 100%;
}

.lobby-fly__body,
.lobby-fly__rings,
.lobby-fly__ringshade {
  inset: 0;
}

.lobby-fly__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
}

/* Saturn: the globe on its own, so the rings can go first and the crescent sits on the globe. */
.lobby-fly__globe {
  clip-path: circle(calc(var(--sd) * 50%));
}

.lobby-fly__shade {
  position: absolute;
  border-radius: 50%;
}

/* The copy blends its sun-side light (soft-light) with its own photo only. */
.lobby-fly__body {
  isolation: isolate;
}

.lobby-fly__light {
  position: absolute;
  pointer-events: none;
}

/* The eclipse. Clipped to the disc with clip-path (not a radius and overflow, which leaks at the corners in Safari),
   a pixel wider than the disc so no sliver of the photo's own edge shows round the dark side. */
.lobby-fly__night {
  position: absolute;
  inset: calc((1 - var(--sd)) * 50%);
  clip-path: circle(calc(50% + 1px));
}

.lobby-fly__umbra {
  position: absolute;
  inset: -3%;
  background: radial-gradient(closest-side, var(--space) 92%, rgb(var(--space-rgb) / 0) 100%);
}

/* The logo's needle star, cream, with a glow that never moves. */
.lobby-fly__star {
  position: absolute;
  max-width: none;
  overflow: visible;
  color: var(--on-dark);
  filter: drop-shadow(0 0 3px rgb(var(--on-dark-rgb) / 0.45));
  opacity: 0;
}

.lobby-fly__name {
  position: absolute;
  margin: 0;
  white-space: nowrap;
}

/* The name's copy keeps its chip, lit, and leaves with it. lobby.js gives it the chip's padding in px (outside the
   stage cqw has no container) and the fraction of a px its box was moved by (snap), so the pill is where it was. */
.lobby-fly__name::before {
  top: calc(var(--fly-dy, 0px) - var(--chip-y));
  left: calc(var(--fly-dx, 0px) - var(--chip-x));
  border-color: var(--chip-line-lit);
  background-color: var(--chip-fill-lit);
}

/* The departure as a fly-over (lobby-flight.js, where the planets are globes): the planet itself goes, its globe flies
   on in one canvas, seen through a frame over the part of the window it covers (both placed and sized by the script:
   the canvas keeps one buffer, of which the frame shows the part drawn), and the buy page's reading shade comes over
   it in the dive, so the last frame is the buy page's first. Its name fades with the other labels. */
.lobby-planet__link.is-flying .lobby-planet__body {
  visibility: hidden;
}

.lobby-fly__frame {
  position: absolute;
  left: 0;
  top: 0;
  overflow: hidden;
  pointer-events: none;
}

.lobby-fly__gl {
  position: absolute;
  left: 0;
  top: 0;
  max-width: none;
  pointer-events: none;
}

.lobby-fly__dusk {
  position: absolute;
  inset: 0;
  opacity: 0;
}

/* Only on a slow network: the strategy's name, small, while the dark waits for the page. */
.lobby-fly__slate {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 0 var(--gutter);
  color: var(--on-dark-muted);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.24em;
  text-align: center;
  text-transform: uppercase;
  opacity: 0;
}

/* ------------------------------------------------------------------ "The six strategies" (templates/lobby.mjs) */
/* The list that sells, after the stage: one card per planet, three a row from 900 px, two from 600 px, one under that.
   Gold only on what the gold marks everywhere: the best true numbers (here the net result), the price and the buttons. */
.lobby-list {
  padding: clamp(56px, 9vw, 112px) 0;
  background: var(--space-2);
  border-top: 1px solid var(--line-dark);
}

.lobby-list__heading {
  margin: 0 0 0.3em;
  color: var(--on-dark);
}

.lobby-list__note {
  margin: 0 0 clamp(28px, 4vw, 44px);
  color: var(--on-dark-muted);
}

.lobby-list__note a {
  color: rgb(var(--on-dark-rgb) / 0.86);
  text-underline-offset: 3px;
  white-space: nowrap;
}

.lobby-list__cards {
  display: grid;
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 600px) {
  .lobby-list__cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 900px) {
  .lobby-list__cards {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 20px;
  }
}

/* A card: the planet and the name, the net result, the line, then the price and Subscribe on one row at the bottom. Its
   edge takes the planet's own light tone while it is hovered or focused within, as a planet's chip does on the stage. */
.lobby-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 20px 20px 18px;
  border: 1px solid var(--line-dark);
  border-radius: var(--radius);
  background: rgb(var(--space-rgb) / 0.72);
  transition: border-color 0.15s ease;
}

.lobby-card:hover,
.lobby-card:focus-within {
  border-color: rgb(var(--tint-hi, var(--on-dark-rgb)) / 0.55);
}

.lobby-card__title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  margin: 0 0 14px;
  font-size: 1.26rem;
}

/* A system's tag after the name (Eridu's "Deeper data", data/systems.json): small, in the planet's light tone. */
.lobby-card__tag {
  padding: 3px 9px;
  border: 1px solid rgb(var(--tint-hi, var(--on-dark-rgb)) / 0.4);
  border-radius: 999px;
  color: rgb(var(--tint-hi, var(--on-dark-rgb)));
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  line-height: 1.4;
  text-transform: uppercase;
  white-space: nowrap;
}

.lobby-card__link {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 44px;
  color: var(--on-dark);
  text-decoration: none;
}

.lobby-card__link:hover span {
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* The sphere photo in its own tone (--planet-filter for its look, base.css; --planet-tone, appearance.mjs), Saturn's
   scaled up as on the strategy page (--k), so its disc is as big as the others'. */
/* The disc is 0.6 of the photo's width: a 68 px photo draws a 41 px planet, pulled in to the card's edge and the name.
   Saturn's photo, scaled up by --k, reaches 34 px * (k - 1) further out: its margins give that back, so its rings stay
   inside the card and short of the name. */
.lobby-card__planet {
  flex: none;
  width: 68px;
  height: 68px;
  margin: -12px calc(34px * (var(--k, 1) - 1) - 6px) -12px calc(34px * (var(--k, 1) - 1) - 14px);
  filter: brightness(0.95) var(--planet-filter) var(--planet-tone,);
  transform: scale(var(--k, 1));
}

.lobby-card__net {
  margin: 0 0 6px;
  color: var(--on-dark);
  font-size: 0.9375rem;
}

.lobby-card__value {
  display: block;
  color: var(--accent);
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.3rem + 0.6vw, 1.75rem);
  line-height: 1.25;
  white-space: nowrap;
}

.lobby-card__line {
  margin: 0 0 18px;
  color: var(--on-dark-muted);
  font-size: 0.875rem;
  line-height: 1.5;
}

.lobby-card__buy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 16px;
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--line-dark);
}

.lobby-card__price {
  margin: 0;
  color: var(--on-dark-muted);
  font-size: 0.9375rem;
}

.lobby-card__amount {
  color: var(--accent);
  font-family: var(--font-display);
  font-size: 1.26rem;
}

.lobby-card__btn {
  min-height: 44px;
  padding: 0 1.4em;
  font-size: 1rem;
}

/* The way down to the list on phones held upright: a small pill fixed at the bottom of the screen, gold text on the
   dark, outside the stage, in portrait windows up to 860 px wide (the strategy pages' small screen media, SMALL_MEDIA in
   assets/js/hero-geometry.mjs, held upright: the lobby's tall view) and in windows taller than 5:4. Without JavaScript
   (no html[data-motion]) it is a plain link that stays, and the page keeps room for it at the end; with it,
   lobby-pill.js shows it after a second and takes it away once the list has been in view. Never on wider or landscape
   screens, nor in print; in forced colours a plain link. Not in a small landscape window either, which the strategy
   pages count as small up to 3:2: the lobby draws its wide view there, with a planet at the bottom left under the pill. */
.lobby-pill {
  display: none;
}

@media (max-width: 860px) and (max-aspect-ratio: 1/1), (max-aspect-ratio: 4/5) {
  .lobby-pill {
    position: fixed;
    left: max(var(--gutter), env(safe-area-inset-left, 0px));
    bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    z-index: 40;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 40px;
    padding: 0 14px;
    border: 1px solid rgb(var(--accent-rgb) / 0.5);
    border-radius: 999px;
    background: rgb(var(--space-2-rgb) / 0.9);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: 0 8px 26px rgb(var(--night-rgb) / 0.6);
    color: var(--accent);
    font-size: 0.8125rem;
    font-weight: 500;
    white-space: nowrap;
    text-decoration: none;
  }

  .lobby-pill:focus-visible {
    outline: 3px solid var(--accent-ring);
    outline-offset: 3px;
  }

  html[data-motion] .lobby-pill {
    visibility: hidden;
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 0.3s ease, transform 0.3s ease, visibility 0s linear 0.3s;
  }

  html[data-motion] .lobby-pill.is-shown {
    visibility: visible;
    opacity: 1;
    transform: none;
    transition: opacity 0.3s ease, transform 0.3s ease;
  }

  html:not([data-motion]) body.lobby {
    padding-bottom: 76px;
  }
}

/* Narrow phones: smaller and lower, so it stays clear of the planet the still layout puts at the bottom (on a 320 px
   phone the pill ends 151 px from the left and Haya's disc starts at 167 px; on Eridu's it ends at 165 px and Sargon's
   disc starts at 169 px). */
@media (max-width: 380px) and (max-aspect-ratio: 1/1) {
  .lobby-pill {
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    gap: 5px;
    min-height: 36px;
    padding: 0 11px;
    font-size: 0.75rem;
  }
}

@media (forced-colors: active) and (max-width: 860px) and (max-aspect-ratio: 1/1), (forced-colors: active) and (max-aspect-ratio: 4/5) {
  .lobby-pill,
  html[data-motion] .lobby-pill {
    position: static;
    display: block;
    width: fit-content;
    margin: 16px auto;
    visibility: visible;
    opacity: 1;
    transform: none;
    border: 0;
    box-shadow: none;
    color: LinkText;
    text-decoration: underline;
  }
}

@media print {
  .lobby-pill,
  html[data-motion] .lobby-pill {
    display: none;
  }
}

/* ------------------------------------------------------------------ "How it works" */
.lobby-how {
  padding: clamp(56px, 9vw, 112px) 0;
  background: var(--space);
  border-top: 1px solid var(--line-dark);
}

.lobby-how__heading {
  margin-bottom: clamp(28px, 4vw, 48px);
  color: var(--on-dark);
  font-size: 0.735rem;
  font-weight: 400;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.lobby-how__steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 32px;
}

.lobby-how__step {
  padding-top: 18px;
  border-top: 1px solid var(--line-dark);
}

.lobby-how__num {
  display: block;
  margin-bottom: 14px;
  color: var(--on-dark-muted);
  font-family: var(--font-display);
  font-size: 0.6825rem;
  font-weight: 400;
  letter-spacing: 0.1em;
}

.lobby-how__title {
  margin: 0 0 6px;
  font-size: 1.05rem;
  font-weight: 400;
}

.lobby-how__text {
  margin: 0;
  max-width: 28em;
  color: var(--on-dark-muted);
}

.lobby-how__cta {
  margin: clamp(36px, 5vw, 56px) 0 0;
}

@media (min-width: 720px) {
  .lobby-how__steps {
    grid-template-columns: repeat(3, 1fr);
    gap: 40px;
  }
}

/* ================================================================== VIEW: wide (landscape windows) */
/* Every window 1:1 or wider, however short: the stage is 1.75 : 1 and as big as the frame allows. The build lays
   the labels and the headline out for an 820px stage (13px labels, 16px headline, 12px subline on one line) and the
   type scales with the stage, but no label goes under 11px, so on stages under 694px (1.585cqw = 11px) the labels
   are bigger than the build laid them out and only the room it left around them keeps them apart. Below that the
   steps take things away, never the type size. The widths are STEPS in templates/layout.mjs (keep equal): the build
   lays every system out to keep clear at each step's smallest stage (where its labels take the largest share of the
   stage), then draws the layout at every stage width from 2400 down to 380px with these sizes and steps (stageClash(),
   every label with its chip), and stops if anything comes closer than 4px:
     hooks              below a 640px stage a label is its name and arrow
     subline            below a 614px stage it would take two lines and goes
     labels             below a 470px stage (every phone held sideways) no label is drawn at rest: the planet pointed
                        at, focused or pressed shows its name, over everything (--bare, below)
     arrows             below a 400px stage, and the headline down to 13px
   The menu of the systems stays whole at every size: under about a 610px stage its hooks wrap beside the pills (the
   build lays the system out clear of it there too). Window -> stage (with the 38px test banner; without it every stage is
   larger): 1100 x 500: 626px, names; 1024 x 600: 801px, all; 932 x 430: 503px, names; 844 x 390: 433px, 740 x 360:
   381px and 667 x 375: 407px, the planets alone. Where the width limits the stage its margin grows, so a label never
   reaches off the screen (.lobby-stage below). Nothing on the stage is ever under 11px, but the names (Michroma at
   0.756em, as always). */
@media (min-aspect-ratio: 1/1) {
  .lobby-intro {
    --top: var(--w-top);
    /* SWITCH.wide in system-geometry.mjs. */
    --sw-h: 26px;
    --sw-gap: 10px;
    --sw-font: 10.5px;
    --sw-pad: 13px;
    --sw-row-gap: 6px;
    --sw-hook-gap: 10px;
    --sw-tag-gap: 8px;
    /* The hooks in the subline's type (below). */
    --sw-hook-font: clamp(11px, 1.463cqw, 13.714px);
  }

  /* The lift (liftAt in system-geometry.mjs): from a 620px stage on, the system is drawn taller by as much as the
     intro takes less of the stage, positions only. The build fitted the orbits below the intro on a 620px stage,
     where its type (px floors, below) takes the largest share; on a bigger stage the top of the outer orbit keeps
     the same distance (--w-lift-margin) below the intro and its bottom stays. As lengths: y' = --lift-a + y *
     --lift-b, y in stage units (--w-y); --lift-t is where the top of the outer orbit goes. The intro's height here is
     the type below, one line each (the build warns if not). lobby-orbits.js works out the same. */
  .lobby-stage > * {
    --stage-h: calc(100cqw / 1.75);
    --lift-a: 0px;
    --lift-b: var(--stage-h);
  }

  @container (min-width: 620px) {
    .lobby-stage > * {
      --lift-t: min(var(--w-lift-top) * var(--stage-h), var(--w-lift-margin) * var(--stage-h) + 0.03 * var(--stage-h) + clamp(16px, 1.951cqw, 22.667px) * 1.2 + var(--w-intro-rest, 10px + clamp(11px, 1.463cqw, 13.714px) * 1.6));
      --lift-b: calc((var(--w-lift-bottom) * var(--stage-h) - var(--lift-t)) / (var(--w-lift-bottom) - var(--w-lift-top)));
      --lift-a: calc(var(--w-lift-bottom) * (var(--stage-h) - var(--lift-b)));
    }
  }

  .lobby-sun {
    --x: var(--w-x);
    --y: calc(var(--lift-a) + var(--w-y) * var(--lift-b));
    --size: var(--w-size);
  }

  .lobby-planet {
    --x: var(--w-x);
    --y: calc(var(--lift-a) + var(--w-y) * var(--lift-b));
    --size: var(--w-size);
    --disc: var(--w-disc);
    --sa: var(--w-sa);
    --s0: var(--w-s0);
    --s1: var(--w-s1);
    --l0: var(--w-l0);
    --l1: var(--w-l1);
    --la: var(--w-la);
    --lx: var(--w-lx);
    --ly: var(--w-ly);
    --ax: var(--w-ax);
    --ay: var(--w-ay);
    --ny: var(--w-ny);
    --ta: var(--w-ta);
    --lw: var(--w-lw);
    --stub: var(--w-stub);
    --stub-t: var(--w-stub-t);
    --z: var(--w-z);
  }

  /* The chip's padding beside the name: the view's labelGap (7px at the 820px reference stage), as a share of the
     stage, so the chip begins exactly where the leader line ends at every stage size. The label's size (below) is
     here too, for the line below a planet (the leader line, above). */
  .lobby-planet {
    --chip-x: 0.8537cqw;
    --label-size: clamp(11px, 1.585cqw, 15px);
  }

  .lobby-orbits--tall {
    display: none;
  }

  /* The orbits' viewBox is the stage, stretched to the lift. */
  .lobby-orbits--wide {
    top: var(--lift-a);
    bottom: auto;
    height: var(--lift-b);
  }

  /* Fixed aspect stage (1.75 : 1, VIEWS.wide in system-geometry.mjs), as big as the space allows (up to 2400px:
     the label and intro type stop growing long before, so a bigger stage only gives the system more room). Where
     the width limits it, the side margin covers the labels' reach (above, about 76px less 0.117 of the stage): from
     windows under about 520px wide it grows past the gutter, so the labels stay on the screen. */
  .lobby-stage {
    width: min(calc(100cqw - 2 * max(var(--gutter), 102px - 15.3cqw)), calc((100cqh - 20px) * 1.75), 2400px);
    aspect-ratio: 1.75;
  }

  .lobby-intro {
    max-width: 86cqw;
  }

  /* 16px and 12px at the 820px reference stage (TEXT.wide in lobby.mjs): small, so the system leads, and the
     subline on one line. */
  .lobby-intro__title {
    font-size: clamp(16px, 1.951cqw, 22.667px);
  }

  .lobby-intro__sub {
    max-width: 50em;
    margin: 0 auto;
    /* Down to 11px, like the labels. */
    font-size: clamp(11px, 1.463cqw, 13.714px);
    line-height: 1.6;
  }

  /* 13px at the 820px reference stage; down to 11px (see the steps above), up to 15px. */
  .lobby-planet__label {
    font-size: var(--label-size);
  }

  /* The steps (above). .98 so no fractional width falls between. The menu stays: its hooks wrap instead (above). */
  @container (max-width: 613.98px) {
    .lobby-intro__sub {
      display: none;
    }
  }

  @container (max-width: 639.98px) {
    .lobby-planet__label {
      width: max-content;
    }

    .lobby-planet__label::after {
      opacity: var(--stub-t, 0);
    }

    /* Out of sight, but still part of the link's name for screen readers. Absolute, so the label stays as wide as
       its name (the size the build and lobby-orbits.js lay out with). */
    .lobby-planet__hook {
      position: absolute;
      width: 1px;
      height: 1px;
      margin: -1px;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
    }
  }

  @container (max-width: 399.98px) {
    .lobby-planet__arrow {
      display: none;
    }

    .lobby-intro__title {
      font-size: max(13px, 1.951cqw);
    }
  }

  /* The smallest stages (a phone held sideways): the labels are not drawn at rest; the planet pointed at, focused or
     pressed shows its name, over everything (STEPS.wide.label, and .lobby-planet__pos--label below). */
  @container (max-width: 469.98px) {
    .lobby-planet {
      --bare: 1;
    }
  }
}

/* ================================================================== VIEW: tall (portrait windows) */
/* The stage is laid out at 0.62 : 1 (VIEWS.tall). A phone held upright, in its browser: a 390 x 844 iPhone shows a
   viewport about 390 x 664 in Safari, which leaves 390 x 596 under the 68px header (0.65), or 390 x 558 with the
   38px test banner (0.70); a 412 x 915 Android phone in Chrome leaves about 412 x 720 (0.57). 0.62 sits in the middle,
   so on real phones the stage nearly fills the frame either way. Windows taller than that (a full-height 390 x 844
   window has a 390 x 738 frame, 0.53) get the stage drawn up to 0.62 / 0.52 = 1.19 times taller: the positions
   stretch with it, the sizes do not, and the build checks its layout at both ends (VIEWS.tall.stretch). Wider frames
   (tablets, short phones) get the whole height and side margins.
   Type at the 330px reference stage (the smallest phone of today, 360 or 375 px wide, and a little less): labels 11px,
   headline 15px (4.545cqw), subline 12.7px (3.846cqw), growing with the stage up to 28px and 15px. Labels grow less
   (3.35cqw, 13px on a 390px stage): while the planets move, bigger labels on a narrow stage find no clear place more
   often and are hidden for a while.
   Portrait windows show the names only, in their chips, on every stage (STEPS.tall in templates/layout.mjs): with
   ten or eleven planets the hooks would crowd the moving planets everywhere. The build lays the still picture out
   with names only at the reference size, every planet a tap target of 44px or more, spaced as WCAG 2.5.8 asks, and
   checks it down to a 270px stage at both ends of the stretch. Under a 330px stage (a 320px phone of 2016) no label
   is drawn at rest: the planet focused or pressed shows its name (--bare, below). */
@media not all and (min-aspect-ratio: 1/1) {
  .lobby-intro {
    --top: var(--t-top);
    /* SWITCH.tall in system-geometry.mjs: a finger's height, nearly. The hooks in the labels' type (below), wrapping
       beside the pills on a phone. */
    --sw-h: 32px;
    --sw-gap: 8px;
    --sw-font: 11px;
    --sw-pad: 14px;
    --sw-row-gap: 4px;
    --sw-hook-gap: 10px;
    --sw-tag-gap: 6px;
    --sw-hook-font: clamp(11px, 3.35cqw, 15px);
  }

  .lobby-sun {
    --x: var(--t-x);
    --y: var(--t-y);
    --size: var(--t-size);
  }

  .lobby-planet {
    --x: var(--t-x);
    --y: var(--t-y);
    --size: var(--t-size);
    --disc: var(--t-disc);
    --sa: var(--t-sa);
    --s0: var(--t-s0);
    --s1: var(--t-s1);
    --l0: var(--t-l0);
    --l1: var(--t-l1);
    --la: var(--t-la);
    --lx: var(--t-lx);
    --ly: var(--t-ly);
    --ax: var(--t-ax);
    --ay: var(--t-ay);
    --ny: var(--t-ny);
    --ta: var(--t-ta);
    --lw: var(--t-lw);
    --stub: var(--t-stub);
    --stub-t: var(--t-stub-t);
    --z: var(--t-z);
  }

  /* 7px at the 330px reference stage (above), and the label's size (below). */
  .lobby-planet {
    --chip-x: 2.1212cqw;
    --label-size: clamp(11px, 3.35cqw, 15px);
  }

  .lobby-orbits--wide {
    display: none;
  }

  /* As wide as the frame (labels keep their own margin from the edge, VIEWS.tall.edge) and 0.62 : 1, or the full
     height when the frame is wider than that; up to 1.19 times taller on tall frames. */
  .lobby-stage {
    width: min(100cqw, calc(100cqh * 0.62));
    height: min(100cqh, calc(100cqw / 0.52));
  }

  .lobby-intro {
    max-width: 92cqw;
  }

  .lobby-intro__title {
    font-size: clamp(13px, 4.545cqw, 28px);
  }

  .lobby-intro__sub {
    max-width: 23em;
    margin: 0 auto;
    font-size: clamp(11px, 3.846cqw, 15px);
    line-height: 1.5;
  }

  .lobby-planet__label {
    font-size: var(--label-size);
  }

  /* The steps (the comment above, STEPS in templates/layout.mjs): names only, on every portrait stage. */
  .lobby-planet__label {
    width: max-content;
  }

  .lobby-planet__label::after {
    opacity: var(--stub-t, 0);
  }

  /* Out of sight, but still part of the link's name for screen readers. Absolute, so the label stays as wide as its
     name (the size the build and lobby-orbits.js lay out with). */
  .lobby-planet__hook {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* Under the smallest phone held upright (a 330px stage: STEPS.tall.label) the labels are not drawn at rest; the
     planet focused or pressed shows its name, over everything (below). The menu's tags go there too, to screen readers
     only: a hook beside its pill keeps to three lines there (switchBox in layout.mjs). */
  @container (max-width: 329.98px) {
    .lobby-planet {
      --bare: 1;
    }

    .lobby-switch__tag {
      position: absolute;
      width: 1px;
      height: 1px;
      margin: -1px;
      padding: 0;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
    }
  }
}

/* Stages too small for every label at once (--bare from the VIEW blocks: a phone held sideways, a phone narrower than
   any of today's held upright): the labels and their lines are not drawn at rest, and the planet pointed at, focused
   or pressed shows its name, over everything. On the wrappers, whose opacity nothing else sets; lobby-orbits.js reads
   --bare and stops placing the labels while it is set. */
.lobby-planet__pos--label,
.lobby-planet__pos--lead {
  opacity: calc(1 - var(--bare));
  transition: opacity 0.2s ease;
}

.lobby-planet__link:is(:hover, :focus-visible, :active, .is-lit) :is(.lobby-planet__pos--label, .lobby-planet__pos--lead) {
  opacity: 1;
}

.lobby-planet__link:is(:hover, :focus-visible, :active, .is-lit) .lobby-planet__pos--label {
  z-index: calc(61 + 8 * var(--bare));
}

/* The planets appear one by one: with motion on (html[data-motion], base.css; and without JavaScript, where the
   system's reduced motion cuts it short), never calm or off, and never back from a strategy page (templates/lobby.mjs:
   html.lobby-return), where there is no entrance again. The gates are in :where() and the classes outside it, so
   every rule here weighs what it did inside the media query it replaces. */
/* One after another 110 ms apart, inner first, but never more than 880 ms from the first to the last (five planets
   took 440 ms; a system of eleven 880 ms, so its entrance ends under half a second later). */
.lobby-planet {
  --entry-step: min(110ms, 880ms / max(1, var(--n, 5) - 1));
}

:where(html:not(.lobby-return, [data-motion="calm"], [data-motion="off"])) .lobby-planet__body {
  animation: lobby-pop 1s cubic-bezier(0.2, 0.7, 0.2, 1) backwards;
  animation-delay: calc(200ms + var(--i) * var(--entry-step));
}

:where(html:not(.lobby-return, [data-motion="calm"], [data-motion="off"])) :is(.lobby-planet__label, .lobby-planet__lead) {
  animation: lobby-fade 0.9s ease backwards;
  animation-delay: calc(500ms + var(--i) * var(--entry-step));
}

:where(html:not(.lobby-return, [data-motion="calm"], [data-motion="off"])) .lobby-orbits {
  animation: lobby-fade 1.6s ease backwards;
}

/* While the globes may still come in time (html.lobby-3d-wait, templates/lobby.mjs) the entrance waits where it
   starts, the planets not yet shown, so the globes take over before anyone sees a photo. Where there is no entrance
   (back from a strategy page, and with motion calm) the planets wait hidden and then fade in. With motion off the
   page's <head> never waits (no globes then). */
.lobby-3d-wait :is(.lobby-planet__body, .lobby-planet__label, .lobby-planet__lead, .lobby-orbits) {
  animation-play-state: paused;
}

:where(html:not([data-motion="calm"], [data-motion="off"])).lobby-return .lobby-planet__body {
  transition: transform 0.4s cubic-bezier(0.2, 0.7, 0.2, 1), filter 0.4s ease, opacity 0.3s ease;
}

.lobby-3d-wait:is(.lobby-return, [data-motion="calm"]) .lobby-planet__body {
  opacity: 0;
}

/* The photo sun waits hidden too, so it never shows before the living sun takes its place (which then comes in
   with the planets, lobby.css above). When the globes will not come it fades in as the planets start to appear. */
:where(html:not([data-motion="off"])).lobby-3d-wait .lobby-sun > :is(.lobby-sun__img, .lobby-sun__core),
:where(html:not([data-motion="off"])).lobby-3d-wait .lobby-sun::after {
  opacity: 0;
  transition: none; /* a style computed before this sheet arrived must not fade the sun out in view */
}

:where(html:not([data-motion="off"])) .lobby-sun > :is(.lobby-sun__img, .lobby-sun__core),
:where(html:not([data-motion="off"])) .lobby-sun::after {
  transition: opacity 0.6s ease;
}

/* The first visit in a session (lobby.js, .is-cueing): when the planets have come in, the chips light once, inner
   planet first, and settle. Colour only, on the pseudo-element, so nothing moves and nothing lobby-orbits.js writes
   is touched (its animation: none for orbiting labels is on the elements). With motion on only. */
:where(html:not([data-motion="calm"], [data-motion="off"])) .lobby-planets.is-cueing .lobby-planet__name::before {
  animation: lobby-chip-cue 1.2s ease-in-out calc(var(--i) * min(150ms, 900ms / max(1, var(--n, 5) - 1)));
}

/* Motion calm (base.css): on hover and focus the planet's lift, its glow and wash, its orbit's light and the arrow's
   nudge change at once, with nothing gliding; the quick colour changes (the chip, the name, the hook, the leader line,
   a quarter of a second) stay. A planet that waited hidden for its globe still fades in (above). */
:where(html[data-motion="calm"]) :is(.lobby-orbit, .lobby-planet__link, .lobby-planet__img, .lobby-planet__shade, .lobby-planet__gl),
:where(html[data-motion="calm"]) .lobby-planet__body::before {
  transition: none;
}

:where(html[data-motion="calm"]) .lobby-planet__body {
  transition: opacity 0.3s ease;
}

:where(html[data-motion="calm"]) .lobby-planet__arrow {
  transition: color 0.25s ease;
}

/* In the lit chip's own colours (--chip-line-lit, the planet's lighter tone), so the cue shows what a hover, a focus
   or a press will. */
@keyframes lobby-chip-cue {
  35% {
    border-color: var(--chip-line-lit);
    background-color: var(--chip-fill-lit);
    box-shadow: inset 0 1px 0 rgb(var(--on-dark-rgb) / 0.14), 0 0 1.4em rgb(var(--tint, var(--on-dark-rgb)) / 0.16);
  }
}

@keyframes lobby-pop {
  from {
    opacity: 0;
    transform: scale(0.85);
  }
}

@keyframes lobby-fade {
  from {
    opacity: 0;
  }
}
