/* Canonn Orrery — chrome for the system model.
 *
 * Loaded on demand by js/orrery.js, so a session that never opens a system
 * never pays for it. Inherits the console's tokens: same amber, same ion, same
 * three Plex faces, same hairlines. It is another room in the same building,
 * not a different building.
 */

.orrery{
  position:fixed;inset:0;z-index:60;display:none;
  grid-template-rows:auto auto 1fr auto;
  background:var(--void,#05070A);color:var(--text,#CAD4DC);
  font-family:var(--sans,'IBM Plex Sans',system-ui,sans-serif)
}
.orrery.open{display:grid}

/* Signal kinds get their own five colours, because they are the one thing on
   this page a reader scans for rather than reads. They are deliberately not
   the interface's amber or ion: those already mean "selected" and "station",
   and a fifth meaning on the same two hues would be no meaning at all. */
.orrery{--bio:#6FBF73;--geo:#D08B3C;--gua:#A98BE0;--thg:#B9D94A;--hum:#93A3B1}
/* Rows named, not counted. The spine hides itself below 960px, and with rows
   assigned by source order that shifted everything up one — the stage took
   the "auto" track and collapsed to its content while the time bar inherited
   the 1fr and grew to half the screen. */
.orr-top{grid-row:1}
.orr-spine{grid-row:2}
.orr-mid{grid-row:3;min-width:0}
.orr-foot{grid-row:4}
/* The galaxy map stays mounted underneath, camera and all — it is only
   switched off. Hiding it here stops it painting behind a transparent edge. */
body.orrery-open .app{visibility:hidden}

/* On its own page the search is the header, and the back button has nowhere
   to go; in a map it is the reverse. One markup, two rooms. */
/* The identity and the search belong to the page; the back button belongs to
   the map. Everything else — the tools, the source, the donate link, the ways
   out to this system elsewhere — belongs to both, because a reader who
   arrived from the map should not lose them by arriving. */
.orr-home,.orr-find{display:none}
.orr-page .orr-home{display:flex}
.orr-page .orr-find{display:block}
/* Signals and Copy link are about the system on screen, so they wait for one. */
.orr-tb.sys{display:none}
.orrery.has-system .orr-tb.sys{display:block}
/* A link the script has switched off stays off. Four classes beat the plain
   [hidden] rule the browser ships, so "On the map" showed on every system
   whether or not there was a map to go back to. */
.orr-tb[hidden]{display:none!important}
.orr-rail{display:flex;align-items:center;gap:6px;flex:none}
.orr-page .orr-back{display:none}
.orr-page .orr-x{display:none}
.orr-page.has-system .orr-x{display:block}
/* Nothing chosen yet: the search is the whole page, so the rest stands down. */
.orrery:not(.has-system) .orr-spine,
.orrery:not(.has-system) .orr-mid,
.orrery:not(.has-system) .orr-foot,
.orrery:not(.has-system) .orr-title{display:none}
.orr-empty{display:none}
.orr-page:not(.has-system) .orr-empty{display:flex}

/* top */
/* 44px, which is the height of the console's own header — see .app's
   grid-template-rows in console.css. The orrery covers the whole page
   when it opens over a map, so its header replaces that one visually;
   at 46px the chrome jumped two pixels on open, which is exactly the
   sort of thing that makes one product read as two. */
.orr-top{display:flex;align-items:center;gap:12px;min-height:44px;
  padding:env(safe-area-inset-top) max(12px,env(safe-area-inset-right)) 0
          max(12px,env(safe-area-inset-left));
  border-bottom:1px solid var(--rule,#1B242E);background:var(--panel,#0C1116);
  position:relative;z-index:5}
.orr-home{align-items:center;gap:9px;color:var(--amber,#FF9D00);text-decoration:none;
  flex:none;min-height:24px}
.orr-home svg{width:19px;height:19px}
.orr-home span{font-family:var(--cond,sans-serif);font-size:14px;font-weight:600;
  letter-spacing:.02em;color:var(--text,#CAD4DC)}
.orr-home:hover span{color:var(--amber,#FF9D00)}

/* The one control this page exists for. */
.orr-find{position:relative;flex:1;max-width:340px}
.orr-find input{width:100%;background:var(--void,#05070A);border:1px solid var(--rule,#1B242E);
  color:var(--text,#CAD4DC);font-family:var(--mono,monospace);font-size:12px;
  padding:6px 11px}
.orr-find input::placeholder{color:var(--dimmer,#6E7F8D)}
.orr-find input:focus{outline:none;border-color:var(--amber,#FF9D00)}
.orr-res{position:absolute;top:calc(100% + 5px);left:0;right:0;display:none;
  background:var(--panel,#0C1116);border:1px solid var(--rule,#1B242E);
  box-shadow:0 12px 30px rgba(0,0,0,.65);max-height:52vh;overflow-y:auto;z-index:8}
.orr-res.open{display:block}
.orr-r{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  padding:6px 11px;cursor:pointer}
.orr-r .nm{font-family:var(--mono,monospace);font-size:11.5px;color:var(--dim,#93A3B1)}
.orr-r.was .ly{color:#2E6E6D}
.orr-r .ly{font-family:var(--mono,monospace);font-size:9.5px;color:var(--dimmer,#6E7F8D);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.orr-r:hover,.orr-r.on{background:var(--panel-2,#111820)}
.orr-r:hover .nm,.orr-r.on .nm{color:var(--amber,#FF9D00)}
.orr-none{padding:9px 11px;font-family:var(--mono,monospace);font-size:10.5px;
  color:var(--dimmer,#6E7F8D)}

/* New, and saying so. Noticeable, not shouting. */
.orr-wip{flex:none;margin-left:-4px;padding:2px 8px;border:1px solid #6A4A12;color:var(--amber,#FF9D00);
  background:rgba(255,157,0,.07);font-family:var(--cond,sans-serif);font-size:10px;
  font-weight:600;letter-spacing:.14em;text-transform:uppercase;cursor:help}

.orr-tb{display:flex;align-items:center;gap:5px;padding:5px 10px;
  border:1px solid var(--rule,#1B242E);background:none;text-decoration:none;
  font-family:var(--cond,sans-serif);font-size:11.5px;font-weight:600;
  color:var(--dim,#93A3B1);cursor:pointer;white-space:nowrap;flex:none}
.orr-tb:hover{border-color:var(--dim,#93A3B1);color:var(--text,#CAD4DC)}
/* Signals is where this system goes on being investigated after the orrery
   has shown you its shape, so it gets the ion the rest of the interface uses
   for a way out to another tool — and the arrow that says it leaves. */
#orr-signals{border-color:#2E6E6D;color:var(--ion,#4DE3E1)}
#orr-signals:hover{background:var(--ion,#4DE3E1);border-color:var(--ion,#4DE3E1);
  color:#04100F}
#orr-signals span{font-size:9px;opacity:.8}
/* Canonn runs on donations and the link to them was the same grey as
   everything else. It is the one thing on this bar that is asking for
   something, so it is the one thing that looks like it. */
.orr-tb.donate{background:var(--amber,#FF9D00);border-color:var(--amber,#FF9D00);
  color:#0B0700}
.orr-tb.donate:hover{background:#FFB233;border-color:#FFB233;color:#0B0700}
.orr-back{display:flex;align-items:center;gap:7px;border:1px solid var(--rule,#1B242E);
  padding:5px 11px;font-family:var(--cond,'IBM Plex Sans Condensed',sans-serif);
  font-size:12px;font-weight:600;color:var(--dim,#93A3B1);
  background:none;cursor:pointer}
.orr-back:hover{border-color:var(--amber,#FF9D00);color:var(--amber,#FF9D00)}
/* The name of the system is what this page is about, so it is the last thing
   in the header allowed to give way. It was flex:1 among five flex:none
   buttons, which made it the only thing that could give: on a phone "Sol"
   came out three pixels wide. */
.orr-title{flex:1 1 auto;min-width:5.5em;display:flex;align-items:baseline;gap:10px}
.orr-title b{font-family:var(--cond,sans-serif);font-size:16px;font-weight:600;
  color:#E4EBF1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.orr-title span{font-family:var(--mono,monospace);font-size:10.5px;
  color:var(--dimmer,#6E7F8D);white-space:nowrap}
/* 24px square minimum, matching the console's card close — it was 19x19,
   under the smallest target a pointer should have to hit. No display here:
   .orr-page toggles this button between none and block, and a display in the
   base rule would win over the none and show it on a page with no system. */
.orr-x{color:var(--dimmer,#6E7F8D);font-size:19px;line-height:1;background:none;
  border:0;cursor:pointer;padding:0 4px;min-width:24px;min-height:24px;
  text-align:center}
.orr-x:hover{color:var(--text,#CAD4DC)}

/* ── the spine ──────────────────────────────────────────────────────────────
   Every body on a log axis of its distance from where you drop in. The orbit
   view draws each body against its own parent, so a moon of Neptune and a
   moon of Earth look alike; here they do not, and "how far is the fly-out" —
   the question every commander actually asks — is answered at a glance. */
.orr-spine{display:flex;flex-direction:column;gap:4px;padding:6px 14px 8px;
  overflow:hidden;border-bottom:1px solid var(--rule,#1B242E);
  background:var(--panel,#0C1116)}
.orr-spine.empty{display:none}
.orr-sp-top{flex:none;display:flex;align-items:baseline;justify-content:space-between;gap:12px}
/* The label is the control: dragging the handle is how a reader who has found
   the handle resizes this, and everybody else needs a thing that says the
   detail is there. */
.orr-sp-lb{display:flex;align-items:baseline;gap:5px;padding:0;background:none;border:0;
  cursor:pointer;font-family:var(--cond,sans-serif);font-size:9px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--dimmer,#6E7F8D)}
.orr-sp-lb:hover{color:var(--amber,#FF9D00)}
.orr-sp-lb i{font-style:normal;font-size:9.5px;letter-spacing:0}
.orr-sp-max{flex:none;font-family:var(--mono,monospace);font-size:9.5px;
  color:var(--dimmer,#6E7F8D);font-variant-numeric:tabular-nums}
.orr-sp-ax{position:relative;flex:none;height:15px;
  background:linear-gradient(to right,var(--star,#6E7F8D),var(--rule,#1B242E));
  background-size:100% 1px;background-position:0 7px;background-repeat:no-repeat}

/* Taller used to mean a taller version of the same thing, which is not more
   detail, it is more empty band. Past the height a row of names fits in, the
   axis names what is on it — packed into as many lanes as it takes for none
   of them to overlap. */
.orr-sp-de{position:relative;flex:1;min-height:0;margin-top:9px;overflow:hidden}
/* What it is still holding back, and how to ask for it. */
.orr-sp-de .more{position:absolute;right:0;bottom:0;padding:1px 5px;
  background:var(--panel,#0C1116);font-family:var(--cond,sans-serif);font-size:9.5px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--dimmer,#6E7F8D)}
/* A stem from the axis down to each name, so a hundred names read as an
   annotated ruler rather than as text scattered over a band. Without them
   every label was floating at an arbitrary height with nothing tying it to
   the distance it was supposed to be marking. */
.orr-sp-de .stem{position:absolute;top:0;width:1px;background:var(--c,#2A3540);
  opacity:.32;pointer-events:none}
.orr-sp-de .tie{position:absolute;height:1px;background:var(--rule,#1B242E);
  pointer-events:none}
.orr-sp-de .lb{position:absolute;display:block;max-width:200px;
  padding:4px 4px 4px 6px;margin:-4px 0 0;background:none;border:0;text-align:left;
  font-family:var(--cond,sans-serif);font-size:10.5px;font-weight:500;
  letter-spacing:.01em;line-height:12px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;color:var(--dim,#93A3B1);cursor:pointer}
.orr-sp-de .lb.port{color:var(--dimmer,#6E7F8D);font-family:var(--mono,monospace);
  font-size:9.5px}
.orr-sp-de .lb:hover{color:var(--amber,#FF9D00)}
.orr-sp-de .lb.on{color:var(--amber,#FF9D00)}
.orr-sp-de .lb.on,.orr-sp-de .lb:hover{background:var(--panel,#0C1116)}
.orr-sp-ax .tk{position:absolute;top:9px;font-family:var(--mono,monospace);font-size:9.5px;
  color:var(--dimmer,#6E7F8D);transform:translateX(-50%);pointer-events:none}
/* A moon's pip is five pixels across, which is a target nobody can hit with a
   thumb and most people miss with a mouse. The dot stays the size it is —
   forty of them at 24px would be a solid bar — and gets an invisible target
   around it instead. */
.orr-sp-ax .pip{position:absolute;top:3px;width:8px;height:8px;margin-left:-4px;
  border-radius:50%;background:var(--c,#8B8579);border:0;padding:0;cursor:pointer}
.orr-sp-ax .pip.moon{top:5px;width:5px;height:5px;margin-left:-2.5px;opacity:.8}
.orr-sp-ax .pip::after{content:"";position:absolute;left:50%;top:50%;
  width:24px;height:24px;transform:translate(-50%,-50%)}
.orr-sp-ax .pip:hover{box-shadow:0 0 0 3px rgba(255,157,0,.25)}
.orr-sp-ax .pip.on{box-shadow:0 0 0 2px var(--void,#05070A),0 0 0 4px var(--amber,#FF9D00)}
/* Stations sit under the axis rather than on it: they have a real distance,
   which is the fact worth showing, but no orbit of their own. */
.orr-sp-ax .port{position:absolute;top:10px;width:3px;height:6px;margin-left:-1.5px;
  background:var(--ion,#4DE3E1);opacity:.65;pointer-events:none}

/* A station in the list is a different kind of thing from a body, and reads
   as one: a square rather than a disc, in the ion the interface already uses
   for anywhere you can dock, and hollow when it is standing on the ground
   rather than in orbit. */
.orr-row.stn .dot{border-radius:0;width:6px;height:6px;background:var(--ion,#4DE3E1);
  margin:0 1.5px}
.orr-row.stn.ground .dot{background:none;box-shadow:inset 0 0 0 1.5px var(--ion,#4DE3E1)}
.orr-row.stn .nm{font-size:10.5px;color:var(--dimmer,#6E7F8D)}
.orr-row.stn:hover .nm{color:var(--ion,#4DE3E1)}
.orr-row .pad{flex:none;font-style:normal;font-family:var(--mono,monospace);font-size:9.5px;
  color:var(--dimmer,#6E7F8D);border:1px solid var(--rule,#1B242E);padding:0 3px}
/* What is on the body, marked on the row. Finding the one Guardian site in a
   system of twenty-two was twenty-two clicks; now it is a glance. */
.orr-row .sg{flex:none;width:5px;height:5px;font-style:normal;border-radius:1px}
.orr-row .sg.bio{background:var(--bio)}
.orr-row .sg.geo{background:var(--geo)}
.orr-row .sg.gua{background:var(--gua)}
.orr-row .sg.thg{background:var(--thg)}
.orr-row .sg.hum{background:var(--hum);opacity:.6}

/* body */
.orr-mid{display:flex;min-height:0}
.orr-stage{position:relative;flex:1;min-width:0}
.orr-stage canvas{display:block;width:100%;height:100%}
.orr-msg{position:absolute;inset:0;display:grid;place-items:center;padding:0 40px;
  text-align:center;font-family:var(--mono,monospace);font-size:12px;
  color:var(--dimmer,#6E7F8D);background:var(--void,#05070A);z-index:4}

/* The same boot screen every map page shows, because this is the same
   building — the R&D banner assembling itself, an amber sweep, and a line
   saying what is being waited on. It was a sentence in grey monospace. */
.orr-boot{display:flex;flex-direction:column;align-items:center;gap:34px}
/* The banner is 1600x400 with the atom centred in a lot of empty canvas, so
   the SVG is scaled up rather than the box widened: that keeps the limpets'
   fly-in on screen. Nothing is shown until the animation has actually
   arrived, so the fallback wordmark never flashes underneath it. */
.orr-boot-logo{display:none;width:min(460px,52vw);aspect-ratio:4/1;
  clip-path:inset(-100% 0 -100% 0)}
.orr-boot-logo.ready{display:block}
.orr-boot-logo svg{display:block;width:100%;height:100%;transform:scale(1.5)}
.orr-boot-word{font-family:var(--cond,sans-serif);font-size:20px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;color:var(--amber,#FF9D00)}
.orr-boot-logo.ready + .orr-boot-word{display:none}
.orr-boot-bar{width:min(240px,40vw);height:2px;background:var(--rule,#1B242E);
  overflow:hidden}
.orr-boot-bar i{display:block;height:100%;width:35%;background:var(--amber,#FF9D00);
  animation:orrsweep 1.15s cubic-bezier(.6,0,.35,1) infinite}
@keyframes orrsweep{0%{transform:translateX(-100%)}100%{transform:translateX(386%)}}
.orr-boot-msg{margin:0;font-family:var(--mono,monospace);font-size:11px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--dim,#93A3B1)}
@media (prefers-reduced-motion:reduce){
  .orr-boot-bar i{animation:none;width:100%}
}
.orr-msg.gone{display:none}
.orr-msg.bad{color:var(--dim,#93A3B1)}
/* A system Canonn has never been sent. Telling a reader that and stopping is
   a dead end; the two things they might want next are another system and the
   tool that knows about every one of them. */
.orr-lost{max-width:44ch;text-align:center}
.orr-lost b{display:block;font-family:var(--cond,sans-serif);font-size:20px;font-weight:600;
  color:#E4EBF1}
.orr-lost p{margin:9px 0 0;font-family:var(--sans,sans-serif);font-size:13.5px;line-height:1.6;
  color:var(--dim,#93A3B1)}
.orr-lost-do{display:flex;flex-wrap:wrap;justify-content:center;gap:7px;margin-top:16px}
.orr-lost-do button,.orr-lost-do a{padding:7px 13px;border:1px solid var(--rule,#1B242E);
  background:none;text-decoration:none;font-family:var(--cond,sans-serif);font-size:11.5px;
  font-weight:600;color:var(--dim,#93A3B1);cursor:pointer}
.orr-lost-do button:hover{border-color:var(--amber,#FF9D00);color:var(--amber,#FF9D00)}
.orr-lost-do a{border-color:#2E6E6D;color:var(--ion,#4DE3E1)}
.orr-lost-do a:hover{background:var(--ion,#4DE3E1);color:#04100F}
/* Names over the view: the star, what orbits it directly, and the selection.
   Positioned by projecting the body each frame, so they never scale or blur
   the way an in-scene sprite would. */
.orr-labels{position:absolute;inset:0;pointer-events:none;overflow:hidden}
.orr-label{position:absolute;top:0;left:0;margin:9px 0 0 11px;white-space:nowrap;
  font-family:var(--mono,monospace);font-size:9.5px;letter-spacing:.04em;
  color:var(--dim,#93A3B1);text-shadow:0 0 5px #05070A,0 0 5px #05070A}
.orr-label.star{color:var(--amber,#FF9D00);font-size:10.5px}
.orr-label.on{color:var(--ion,#4DE3E1)}
.orr-label.off{display:none}
/* The real stars behind the system: dimmer and smaller than the bodies in
   it, because they are the room rather than the thing being looked at. */
.orr-label.far{color:#7C8A99;font-size:9px;letter-spacing:.06em;
  margin:6px 0 0 7px;opacity:.8}

/* ── resizing ───────────────────────────────────────────────────────────────
   The list, the detail and the distance axis all take a drag, because how much
   of each you want depends on what you are doing. The handles sit on the
   inside edge so they never collide with the window's own. */
.orr-grip{position:absolute;z-index:6;background:transparent}
.orr-grip:hover,.orr-grip:focus-visible{background:var(--amber,#FF9D00);opacity:.55}
.orr-grip-l,.orr-grip-r{top:0;bottom:0;width:5px;cursor:col-resize}
.orr-grip-l{right:-3px}
.orr-grip-r{left:-3px}
/* The spine's own handle, and it has to be told which row it belongs to.
   The grid names four rows; this was a fifth grid child with no grid-row, so
   auto-placement dropped it into an implicit row 5 — measured at x 0→1600,
   y 895→900: the full width of the window along the bottom, lying over the
   last 3px of the time bar, showing a row-resize cursor there and lighting up
   amber on hover, while dragging it resized an axis at the top of the screen.

   In the spine's row, aligned to its bottom edge, with the same 3px straddle
   the negative margin was always for. */
.orr-grip-h{grid-row:2;align-self:end;position:relative;height:5px;
  margin-bottom:-3px;cursor:row-resize}
/* No spine, no handle for it. */
.orrery:not(.has-system) .orr-grip-h,
.orr-spine.empty + .orr-grip-h{display:none}
body.orr-dragging{user-select:none}
.orr-left,.orr-right{position:relative}
/* Below the height an axis can be read at, it is simply put away. */
.orr-spine.shut{padding:0;overflow:hidden;border-bottom:0}

/* ── the view bar ───────────────────────────────────────────────────────────
   An orrery answers three questions, and its controls belong where the answers
   do: which system (the header), when (the time bar), and how it is drawn.

   That third group used to live behind a View button, in a panel that floated
   over the corner of the model it was changing. Nesting eight controls behind
   a ninth means a reader has to remember they exist, open the thing, change
   one, and close it again — and while it is open it is covering the answer.
   They are eight controls; eight controls fit on a bar, and a bar is read
   without being opened. */
/* Over the render, because that is the thing it changes. A band across the
   top of the window would have put "3D or 2D" as far from the model as the
   window is tall; here every control has its own effect happening directly
   underneath it. Translucent and hairlined so the model reads through it. */
/* One row, deliberately. A wrapping flex container shrink-to-fits to its
   widest single item rather than to the sum of them, so `wrap` collapsed this
   to the width of one button and stacked the rest four deep over the model
   however much room there was. It is one line that scrolls if the window is
   too narrow to hold it — which is the honest failure for a toolbar. */
.orr-hud{position:absolute;left:12px;top:12px;z-index:3;
  max-width:calc(100% - 24px);overflow-x:auto;scrollbar-width:none;
  display:flex;flex-wrap:nowrap;align-items:center;gap:7px;padding:4px 6px;
  background:rgba(9,13,18,.82);border:1px solid var(--rule,#1B242E);
  backdrop-filter:blur(3px)}
.orr-hud::-webkit-scrollbar{height:0}
/* Every control on the bar is the width of what it says. The default is to
   grow, and a row of controls that grow is a row where "3D" is two hundred
   pixels wide and nothing lines up with anything. */
.orr-hud > *{flex:none}
.orr-hud button,.orr-hud .orr-opt span,.orr-hud .orr-opt b{white-space:nowrap}
/* A hairline between groups: projection and scale are what you are looking
   through, the four rows are what is drawn, the sliders are the light. */
.orr-hud-r{flex:none;width:1px;align-self:stretch;margin:3px 2px;
  background:var(--rule,#1B242E)}

/* Two-state pairs stay segmented, because they are a choice between modes. */
.orr-seg{display:flex;border:1px solid var(--rule,#1B242E)}
.orr-seg button{flex:1;padding:4px 10px;background:none;border:0;
  font-family:var(--cond,sans-serif);font-size:11px;font-weight:600;
  color:var(--dimmer,#6E7F8D);cursor:pointer}
.orr-seg button + button{border-left:1px solid var(--rule,#1B242E)}
.orr-seg button.on{background:var(--amber,#FF9D00);color:#0B0700}

/* Everything else states its own value, so it reads without relying on colour
   to carry the state — and so a three-state control can be one button that
   steps rather than three that have to be told apart.

   Built as a name and a readout welded together, which is what they are, and
   given the same border and the same height as the segmented pairs beside
   them: as loose text with a border only on hover they read as labels rather
   than as things you could press. */
.orr-opt{display:flex;align-items:stretch;padding:0;background:none;
  border:1px solid var(--rule,#1B242E);cursor:pointer;text-align:left;overflow:hidden}
.orr-opt span{display:flex;align-items:center;padding:4px 8px;
  font-family:var(--cond,sans-serif);font-size:11px;font-weight:600;
  letter-spacing:.02em;color:var(--dim,#93A3B1)}
.orr-opt b{display:flex;align-items:center;padding:4px 8px;
  border-left:1px solid var(--rule,#1B242E);background:rgba(255,255,255,.045);
  font-family:var(--mono,monospace);font-size:10px;font-weight:500;
  color:var(--dimmer,#6E7F8D)}
.orr-opt:hover{border-color:var(--dim,#93A3B1)}
.orr-opt:hover b{border-left-color:var(--dim,#93A3B1)}
.orr-opt:hover span{color:var(--text,#CAD4DC)}
.orr-opt.on span{color:var(--text,#CAD4DC)}
.orr-opt.on b{color:var(--ion,#4DE3E1)}
/* Settings, not controls: set once to taste and then left alone, so they
   keep a box of their own rather than crowding the six things a reader
   changes while reading. */
/* Fixed, not absolute, and placed by script.

   The strip scrolls sideways when a window is too narrow to hold it, and
   overflow-x:auto computes overflow-y to auto as well — so a box positioned
   below the strip was clipped out of existence by its own parent. It opened
   every time; there was simply nothing to see. */
.orr-pop{position:fixed;z-index:65;width:212px;
  display:none;padding:8px 10px;background:var(--panel,#0C1116);
  border:1px solid var(--rule,#1B242E);box-shadow:0 14px 40px rgba(0,0,0,.7)}
.light-open #orr-light-p{display:block}
.key-open #orr-key-p{display:block}
/* What the marks mean. All of them are invented here, and until now the only
   way to learn one was to rest on it and wait for a tooltip. */
.orr-key{}
.orr-s-key{flex:none;width:22px;height:22px;padding:0;background:none;
  border:1px solid var(--rule,#1B242E);color:var(--dimmer,#6E7F8D);
  font-family:var(--cond,sans-serif);font-size:11px;font-weight:700;cursor:pointer}
.orr-s-key:hover,.key-open .orr-s-key{border-color:var(--amber,#FF9D00);
  color:var(--amber,#FF9D00)}
.orr-key-p{width:226px}
.orr-key-p h4{margin:8px 0 4px;font-family:var(--cond,sans-serif);font-size:9px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--dimmer,#6E7F8D);font-weight:600}
.orr-key-p h4:first-child{margin-top:0}
.orr-key-r{display:flex;align-items:center;gap:9px;padding:2px 0}
.orr-key-r span{font-family:var(--mono,monospace);font-size:10px;color:var(--dim,#93A3B1)}
.orr-key-r i{flex:none;width:12px;display:flex;justify-content:center;font-style:normal}
.orr-key-r i.sg{height:5px;border-radius:1px}
.orr-key-r i.sg.bio{background:var(--bio)}
.orr-key-r i.sg.geo{background:var(--geo)}
.orr-key-r i.sg.gua{background:var(--gua)}
.orr-key-r i.sg.thg{background:var(--thg)}
.orr-key-r i.sg.hum{background:var(--hum);opacity:.6}
.orr-key-r i.stn{width:6px;height:6px;background:var(--ion,#4DE3E1);margin:0 3px}
.orr-key-r i.stn.hollow{background:none;box-shadow:inset 0 0 0 1.5px var(--ion,#4DE3E1)}
.orr-key-r i.pad{font-family:var(--mono,monospace);font-size:9.5px;
  color:var(--dimmer,#6E7F8D);border:1px solid var(--rule,#1B242E);padding:0 3px;width:auto}
.light-open #orr-light{border-color:var(--amber,#FF9D00);color:var(--amber,#FF9D00)}
.orr-sl{display:flex;align-items:center;gap:10px;padding:3px 0;cursor:pointer}
.orr-sl span{flex:none;width:64px;font-family:var(--cond,sans-serif);font-size:11px;
  color:var(--dim,#93A3B1)}
.orr-sl input{flex:1;min-width:0;accent-color:var(--amber,#FF9D00);cursor:pointer}

/* ── the tools menu ─────────────────────────────────────────────────────────
   Canonn is a dozen tools; the orrery linked to none of them, so arriving
   here was a way of leaving the rest of Canonn behind. */
.orr-menu{position:absolute;right:12px;top:calc(100% - 4px);z-index:9;
  min-width:250px;display:none;background:var(--panel,#0C1116);
  border:1px solid var(--rule,#1B242E);box-shadow:0 14px 40px rgba(0,0,0,.7);
  max-height:70vh;overflow-y:auto}
.menu-open .orr-menu{display:block}
.orr-menu a,.orr-menu button{display:flex;width:100%;align-items:baseline;
  justify-content:space-between;gap:14px;padding:8px 11px;text-decoration:none;
  background:none;border:0;text-align:left;cursor:pointer}
.orr-menu a span,.orr-menu button span{font-family:var(--cond,sans-serif);font-size:12px;
  font-weight:600;color:var(--dim,#93A3B1)}
.orr-menu a em,.orr-menu button em{font-style:normal;font-family:var(--mono,monospace);
  font-size:9px;color:var(--dimmer,#6E7F8D);white-space:nowrap}
.orr-menu a:hover,.orr-menu button:hover{background:var(--panel-2,#111820)}
.orr-menu a:hover span,.orr-menu button:hover span{color:var(--amber,#FF9D00)}
.orr-menu-r{height:1px;margin:4px 0;background:var(--rule,#1B242E)}
/* GitHub and Donate sit in the header while it has room for them, and in
   here when it does not — a narrow window must not be one with no way out. */
.orr-menu .only-narrow{display:none}

.orr-labels.hide{display:none}

.orr-legend{position:absolute;left:14px;bottom:12px;font-family:var(--mono,monospace);
  font-size:10px;line-height:1.7;color:var(--dimmer,#6E7F8D);pointer-events:none}
.orr-legend b{color:var(--amber,#FF9D00);font-weight:500}
.orr-legend .dim{opacity:.7}

/* What is in the system on the left, what you have picked on the right, and
   the model itself between them — so choosing a body and reading it are on
   opposite sides of the thing they are about, not stacked in one column. */
/* Dragged widths arrive as custom properties, not as inline styles, so the
   media queries below can still say what a stacked layout does. */
.orr-side{width:var(--left-w,290px);flex:none;display:flex;flex-direction:column;
  min-height:0;background:var(--panel,#0C1116)}
.orr-left{border-right:1px solid var(--rule,#1B242E)}
.orr-right{width:var(--right-w,276px);border-left:1px solid var(--rule,#1B242E)}
/* Headings the eye does not need and the outline does. */
.orr-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.orr-s-t{margin:0;font-weight:400;font-family:var(--cond,sans-serif);font-size:9.5px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--dimmer,#6E7F8D)}
.orr-s-h{display:flex;align-items:center;gap:8px;padding:10px 13px 8px}
/* Labelled. It was a teal diamond, which tells a reader nothing about what
   pressing it will do — and the list it hides is sixty-seven rows long. */
.orr-s-tog{flex:none;display:flex;align-items:center;gap:5px;padding:3px 7px;
  background:none;border:1px solid var(--rule,#1B242E);color:var(--dimmer,#6E7F8D);
  font-family:var(--cond,sans-serif);font-size:10.5px;font-weight:600;cursor:pointer}
.orr-s-tog::before{content:"";width:5px;height:5px;background:currentColor}
.orr-s-tog.on{border-color:#2E6E6D;color:var(--ion,#4DE3E1)}
.orr-s-tog:not(.on)::before{background:none;box-shadow:inset 0 0 0 1px currentColor}
.orr-s-tog:hover{border-color:var(--dim,#93A3B1)}
.orr-filter{flex:1;min-width:0;background:var(--void,#05070A);
  border:1px solid var(--rule,#1B242E);color:var(--text,#CAD4DC);
  font-family:var(--mono,monospace);font-size:10.5px;padding:3px 7px}
.orr-filter::placeholder{color:var(--dimmer,#6E7F8D)}
.orr-filter:focus{outline:none;border-color:var(--amber,#FF9D00)}
.orr-list{flex:1;min-height:0;overflow-y:auto;padding:0 7px 10px}
.orr-row{display:flex;align-items:center;gap:8px;padding:4px 6px;cursor:pointer;
  padding-left:calc(6px + var(--depth,0) * 15px);border-left:2px solid transparent}
.orr-row:hover{background:var(--panel-2,#111820)}
.orr-row:focus-visible{outline:2px solid var(--amber,#FF9D00);outline-offset:-2px}
.orr-row.on{background:var(--panel-2,#111820);border-left-color:var(--amber,#FF9D00)}
.orr-row .dot{width:9px;height:9px;border-radius:50%;flex:none}
/* A hairline down the indent, so a moon reads as belonging to its planet
   rather than merely being further right. */
.orr-row[style*="--depth:1"],.orr-row[style*="--depth:2"],.orr-row[style*="--depth:3"]{
  background-image:linear-gradient(var(--rule,#1B242E),var(--rule,#1B242E));
  background-size:1px 100%;background-repeat:no-repeat;
  background-position:calc(10px + (var(--depth,0) - 1) * 15px) 0}
.orr-row .nm{flex:1;min-width:0;font-family:var(--mono,monospace);font-size:11px;
  color:var(--dim,#93A3B1);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.orr-row.on .nm{color:var(--text,#CAD4DC)}
.orr-row .ct{font-family:var(--mono,monospace);font-size:9.5px;color:var(--dimmer,#6E7F8D);
  font-variant-numeric:tabular-nums}

.orr-facts{flex:1;min-height:0;overflow-y:auto;padding:2px 13px 16px}

/* The body wears its own face: the disc is the very canvas the sphere in the
   view is textured with, lit from one side so it reads as a globe rather than
   a swatch. */
.orr-f-h{display:flex;align-items:center;gap:11px}
.orr-f-n{display:flex;flex-direction:column;gap:2px;min-width:0}
.orr-f-h b{font-family:var(--cond,sans-serif);font-size:14px;font-weight:600;color:#E4EBF1;
  overflow-wrap:anywhere}
.orr-f-h span{font-family:var(--mono,monospace);font-size:10px;color:var(--amber,#FF9D00)}
.orr-face{flex:none;width:40px;height:40px;border-radius:50%;background-size:170% 100%;
  background-position:38% 50%;box-shadow:inset -9px -4px 14px -4px rgba(0,0,0,.85),
  inset 3px 2px 8px -4px rgba(255,255,255,.28)}
.orr-face.star{box-shadow:0 0 16px -2px currentColor}
/* The disc for a black hole is the one that is not a picture of anything:
   a void, and the ring of sky bent around it. Same geometry as the shader
   draws — the bright edge sits outside the black, not on it. */
.orr-face.hole{background:#000;box-shadow:none;position:relative;overflow:hidden}
.orr-face.hole::after{content:"";position:absolute;inset:0;border-radius:50%;
  background:radial-gradient(circle,#000 0 46%,var(--star,#8FA6C8) 50%,
    rgba(143,166,200,.28) 58%,transparent 76%)}

/* The numbers you decide on, set the way the galaxy map's system card sets
   them: label above, figure large and tabular, unit small beside it. */
/* The measurement tile, and the one place in this file where the comment used
   to describe something the browser was not doing.

   It said these were set "the way the galaxy map's system card sets them:
   label above, figure large and tabular". They were not. `.orr-facts dt` and
   `.orr-facts dd` further down carry the same specificity (0,1,1) and come
   later in the file, and .orr-meas lives inside .orr-facts — so the label came
   out 10px and the figure 11px, a label the same size as its own number, in
   the component both surfaces use for every reading a commander takes off the
   screen. The card renders the same figure at 14.5px.

   Fixed by selecting through the structure — `.orr-meas > div > dt` is (0,1,2)
   and cannot be beaten by a bare descendant rule — and by taking the card's
   values verbatim rather than near-misses of them. */
.orr-meas{display:grid;grid-template-columns:1fr 1fr;gap:1px;margin:11px 0 0;
  background:var(--rule);border:1px solid var(--rule)}
.orr-meas > div{background:var(--panel);padding:7px 9px 8px;min-width:0}
.orr-meas > div > dt{font-family:var(--cond);font-size:9px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--dimmer);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.orr-meas > div > dd{margin:3px 0 0;display:flex;align-items:baseline;gap:5px;
  font-family:var(--mono);font-size:14.5px;line-height:17px;height:20px;
  color:var(--text);font-variant-numeric:tabular-nums}
.orr-meas > div > dd em{font-style:normal;font-size:9.5px;letter-spacing:.02em;
  color:var(--dimmer);white-space:nowrap}

/* The stations on the selected body, as an index rather than as cards: the
   detail is a modal now, and repeating half of it here made the panel long
   without making it more useful. */
.orr-ports{display:flex;flex-direction:column;gap:2px}
.orr-ports button{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  padding:4px 8px;background:none;border:1px solid var(--rule,#1B242E);cursor:pointer;
  text-align:left}
.orr-ports button span{font-family:var(--cond,sans-serif);font-size:11.5px;font-weight:600;
  color:var(--dim,#93A3B1)}
.orr-ports button em{font-style:normal;font-family:var(--mono,monospace);font-size:9px;
  color:var(--dimmer,#6E7F8D);white-space:nowrap}
.orr-ports button:hover{border-color:var(--ion,#4DE3E1)}
.orr-ports button:hover span{color:var(--ion,#4DE3E1)}
.orr-links{display:flex;gap:4px;margin-top:7px}
.orr-links a{flex:1;text-align:center;padding:3px 6px;border:1px solid #2E6E6D;
  font-family:var(--cond,sans-serif);font-size:10px;font-weight:600;
  color:var(--ion,#4DE3E1);text-decoration:none}
.orr-links a:hover{background:var(--ion,#4DE3E1);color:#04100F}
.orr-links a span{opacity:.7;margin-left:3px}

/* What is true about this body at a glance, before any of the numbers. */
.orr-chips{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
.orr-chip{padding:2px 7px;border:1px solid var(--rule,#1B242E);
  font-family:var(--cond,sans-serif);font-size:10px;font-weight:600;
  color:var(--dimmer,#6E7F8D)}
.orr-chip.good{border-color:#2E6E6D;color:var(--ion,#4DE3E1)}

.orr-sec{margin-top:13px}
.orr-sec h3{margin:0 0 5px;font-family:var(--cond,sans-serif);font-size:9.5px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--dimmer,#6E7F8D);font-weight:600}

/* The panel and the station page are the same kind of reading, so they set
   a label-and-figure row the same way. Scoping this to .orr-facts alone left
   the modal's tables stacking label above value. */
.orr-facts dl,.orr-m-b dl{margin:0;display:grid;gap:1px;background:var(--rule,#1B242E);
  border:1px solid var(--rule,#1B242E)}
.orr-facts dl > div,.orr-m-b dl > div{display:flex;justify-content:space-between;
  align-items:baseline;gap:10px;background:var(--panel,#0C1116);padding:5px 8px}
.orr-facts dt,.orr-m-b dt{font-family:var(--cond,sans-serif);font-size:10px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--dimmer,#6E7F8D);white-space:nowrap}
.orr-facts dd,.orr-m-b dd{margin:0;font-family:var(--mono,monospace);font-size:11px;
  color:var(--text,#CAD4DC);font-variant-numeric:tabular-nums;text-align:right}

/* Proportions as bars: "Iron 23.5" beside "Nickel 17.8" is a comparison, and
   a column of numerals leaves the reader to do it. */
.orr-bars{display:flex;flex-direction:column;gap:3px}
.orr-bar{display:grid;grid-template-columns:1fr 54px 40px;align-items:center;gap:7px}
.orr-bar .k{font-family:var(--mono,monospace);font-size:10px;color:var(--dim,#93A3B1);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.orr-bar .t{height:5px;background:var(--panel-2,#111820);display:block}
.orr-bar .t i{display:block;height:100%;background:var(--ion,#4DE3E1)}
.orr-bar .v{font-family:var(--mono,monospace);font-size:9.5px;color:var(--dimmer,#6E7F8D);
  text-align:right;font-variant-numeric:tabular-nums}

/* Named finds, under the counts they belong to. A count says something is
   there; the name is the reason to go. An unidentified genus is dimmed and
   says so, because for a lot of readers that is the most interesting row on
   the page. */
.orr-sigs{margin-top:7px}
.orr-sigs h4{margin:0 0 3px;font-family:var(--cond,sans-serif);font-size:9px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--dimmer,#6E7F8D);font-weight:600}
.orr-sig{display:flex;align-items:baseline;gap:7px;padding:2px 0}
.orr-sig i{flex:none;width:5px;height:5px;border-radius:1px;transform:translateY(-1px)}
.orr-sig i.bio{background:var(--bio)}
.orr-sig i.geo{background:var(--geo)}
.orr-sig i.gua{background:var(--gua)}
.orr-sig span{flex:1;min-width:0;font-family:var(--mono,monospace);font-size:10.5px;
  color:var(--text,#CAD4DC);overflow-wrap:anywhere}
.orr-sig em{flex:none;font-style:normal;font-family:var(--cond,sans-serif);font-size:9.5px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--dimmer,#6E7F8D)}
.orr-sig.dim span{color:var(--dimmer,#6E7F8D)}
.orr-note-i{margin-top:7px;font-family:var(--mono,monospace);font-size:9.5px;
  line-height:1.6;color:var(--dimmer,#6E7F8D)}

/* Reinforcement against undermining, as the tug of war it is. Two numbers in
   a table are a comparison the reader has to do; this is one they can see. */
.orr-tug{display:flex;height:20px;margin-top:6px;background:var(--panel-2,#111820);
  border:1px solid var(--rule,#1B242E)}
.orr-tug i,.orr-tug u{display:flex;align-items:center;min-width:0;padding:0 6px;
  font-style:normal;text-decoration:none;overflow:hidden}
.orr-tug i{background:rgba(111,191,115,.18);justify-content:flex-start}
.orr-tug u{background:rgba(229,72,77,.18);justify-content:flex-end}
.orr-tug b{font-family:var(--mono,monospace);font-size:9.5px;font-weight:500;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.orr-tug i b{color:var(--bio)}
.orr-tug u b{color:#E5484D}

.orr-item{padding:5px 8px;border:1px solid var(--rule,#1B242E);margin-bottom:3px}
.orr-item b{display:block;font-family:var(--cond,sans-serif);font-size:11.5px;
  font-weight:600;color:var(--text,#CAD4DC)}
.orr-item span{display:block;margin-top:1px;font-family:var(--mono,monospace);
  font-size:9.5px;color:var(--dimmer,#6E7F8D)}

/* ── a station, in full ─────────────────────────────────────────────────────
   Who owns it and how that is going, what the economy is made of, how many
   pads of each size, where on the surface it stands, every service, the ships
   and modules it sells, and its market both ways round. That is a page's
   worth, so it gets a page rather than a card in a column. */
.orr-modal{position:fixed;inset:0;z-index:70;display:grid;place-items:center;
  padding:5vh 16px;background:rgba(3,5,8,.72);backdrop-filter:blur(2px)}
.orr-modal[hidden]{display:none}
.orr-m-box{display:flex;flex-direction:column;width:min(560px,100%);max-height:90vh;
  background:var(--panel,#0C1116);border:1px solid var(--rule,#1B242E);
  box-shadow:0 24px 70px rgba(0,0,0,.8)}
.orr-m-h{flex:none;display:flex;align-items:flex-start;gap:12px;padding:12px 14px 11px;
  border-bottom:1px solid var(--rule,#1B242E)}
.orr-m-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
.orr-m-t b{font-family:var(--cond,sans-serif);font-size:17px;font-weight:600;color:#E4EBF1;
  overflow-wrap:anywhere}
.orr-m-t span{font-family:var(--mono,monospace);font-size:10px;color:var(--ion,#4DE3E1)}
.orr-m-b{flex:1;min-height:0;overflow-y:auto;padding:2px 14px 16px;
  scrollbar-width:thin;scrollbar-color:var(--rule,#1B242E) transparent}
.orr-m-b .orr-meas{margin-top:12px}
.orr-m-b::-webkit-scrollbar{width:9px}
.orr-m-b::-webkit-scrollbar-thumb{background:var(--rule,#1B242E);
  border:2px solid var(--panel,#0C1116)}

/* A market is hundreds of rows and nobody reads hundreds of rows. What
   decides a trip is the few things it sells cheapest and the few it pays
   most for, so those are the ones named. */
.orr-mkt-h{margin:9px 0 4px;font-family:var(--cond,sans-serif);font-size:9px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--dimmer,#6E7F8D);font-weight:600}
.orr-mkt > div{display:grid;grid-template-columns:1fr auto 62px;align-items:baseline;
  gap:10px;padding:3px 0}
.orr-mkt .k{font-family:var(--mono,monospace);font-size:10.5px;color:var(--text,#CAD4DC);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.orr-mkt .p{font-family:var(--mono,monospace);font-size:10.5px;color:var(--amber,#FF9D00);
  font-variant-numeric:tabular-nums}
.orr-mkt .q{font-family:var(--mono,monospace);font-size:9.5px;color:var(--dimmer,#6E7F8D);
  text-align:right;font-variant-numeric:tabular-nums}

/* Nothing chosen yet. The page's job is to show a system, so the search does
   not get a hero — it gets the middle of the screen and some real places to
   start, which is more use than a sentence about what an orrery is. */
.orr-empty{grid-row:2/5;flex-direction:column;align-items:center;justify-content:center;
  gap:14px;padding:0 24px 8vh;text-align:center}
.orr-empty h1{margin:0;font-family:var(--cond,sans-serif);font-size:30px;font-weight:600;
  letter-spacing:.01em;color:#E4EBF1}
.orr-empty p{margin:0;max-width:44ch;font-size:13.5px;line-height:1.65;
  color:var(--dim,#93A3B1)}
.orr-seed-h{margin:10px 0 0;font-family:var(--cond,sans-serif);font-size:9.5px;
  font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--dimmer,#6E7F8D)}
.orr-seeds{display:flex;flex-wrap:wrap;justify-content:center;gap:6px;margin-top:4px}
.orr-seeds button{padding:6px 13px;border:1px solid var(--rule,#1B242E);background:none;
  font-family:var(--mono,monospace);font-size:11.5px;color:var(--dim,#93A3B1);cursor:pointer}
.orr-seeds button:hover{border-color:var(--amber,#FF9D00);color:var(--amber,#FF9D00)}

/* the clock */
/* Notched phones keep a strip at the bottom for the home indicator and a
   corner or two at the top. Without this the time bar sits under the
   indicator and the close button under the camera. */
.orr-foot{display:flex;align-items:center;gap:18px;min-height:42px;
  padding:0 max(12px,env(safe-area-inset-right)) env(safe-area-inset-bottom)
          max(12px,env(safe-area-inset-left));
  border-top:1px solid var(--rule,#1B242E);background:var(--panel,#0C1116)}
.orr-time{display:flex;align-items:center;gap:6px}
.orr-time button{width:30px;height:24px;display:grid;place-items:center;
  border:1px solid var(--rule,#1B242E);color:var(--dim,#93A3B1);font-size:9px;
  background:none;cursor:pointer}
/* .orr-time holds one button, the play/pause toggle. The :disabled rules that
   used to sit here anticipated step controls that were never built.

   Border only: .orr-play below sets its own colour with !important — amber
   playing, ion paused — so a colour here would be inert, and the glyph
   already carries the state. */
.orr-time button:hover{border-color:var(--amber)}

.orr-play{color:var(--amber,#FF9D00)!important;font-size:11px!important}
.orr-play.paused{color:var(--ion,#4DE3E1)!important}
/* The speed slider. Wider than a pair of nudge buttons because that width is
   the point — it is what turns "faster" into "how much faster", and the whole
   signed ladder, backwards through real time to forwards, lives on it. */
/* The speed slider reads continuously between the named rates now, with a dead
   zone at real time. That needs the track to show where real time is — a detent
   you can feel but cannot find is half a control — and to stop lying about
   where zero is.

   Both come from replacing the native track. `accent-color` fills the rail from
   the LEFT end to the thumb, and the left end of this ladder is ten years a
   second *backwards*: a bar that grows as you speed up in reverse and shrinks
   as you approach real time is exactly backwards. It also paints over the
   element's own background, so a mark drawn there is never seen — measured, not
   assumed. So the track is drawn here instead, and the fill runs from the
   detent to the thumb: its length is how far from real time, its side is which
   way the clock is going.

   --sp-pos and --sp-det are the thumb's and the detent's positions along the
   track as fractions, set from JS. The thumb's centre travels between
   thumb/2 and width - thumb/2, never 0 and 100%, so every position here is
   calc(thumb/2 + f * (100% - thumb)) — at the ends the difference is half a
   thumb, which is the whole mark. And they are colour stops inside full-width
   gradients rather than background-positions, because a percentage in
   background-position resolves against the area *less the image*, which is a
   different number and silently so. */
.orr-speed{
  --sp-thumb:14px;
  --sp-pos:.5;
  --sp-det:.5;
  --sp-p:calc(var(--sp-thumb) / 2 + var(--sp-pos) * (100% - var(--sp-thumb)));
  --sp-d:calc(var(--sp-thumb) / 2 + var(--sp-det) * (100% - var(--sp-thumb)));
  --sp-track:
    /* the detent, standing proud of the rail so it reads from across the room */
    linear-gradient(90deg,
      transparent calc(var(--sp-d) - 1px), var(--ion,#4DE3E1) calc(var(--sp-d) - 1px),
      var(--ion,#4DE3E1) calc(var(--sp-d) + 1px), transparent calc(var(--sp-d) + 1px))
      no-repeat 0 50% / 100% 13px,
    /* the rail, filled between real time and here */
    linear-gradient(90deg,
      var(--rule-strong,#4A637D) 0 min(var(--sp-p),var(--sp-d)),
      var(--amber,#FF9D00) min(var(--sp-p),var(--sp-d)) max(var(--sp-p),var(--sp-d)),
      var(--rule-strong,#4A637D) max(var(--sp-p),var(--sp-d)) 100%)
      no-repeat 0 50% / 100% 4px;
  width:132px;height:24px;margin:0 2px;cursor:pointer;
  -webkit-appearance:none;appearance:none;background:none}

/* One value, two vendor pseudo-elements that cannot share a selector: a
   rule listing both is dropped whole by each engine, because neither
   recognises the other's. --sp-track is the shared half. */
.orr-speed::-webkit-slider-runnable-track{height:24px;background:var(--sp-track)}
.orr-speed::-moz-range-track{height:24px;background:var(--sp-track)}

.orr-speed::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;
  width:var(--sp-thumb);height:var(--sp-thumb);
  margin-top:calc((24px - var(--sp-thumb)) / 2);
  border:none;border-radius:50%;background:var(--amber,#FF9D00);cursor:pointer}
.orr-speed::-moz-range-thumb{width:var(--sp-thumb);height:var(--sp-thumb);
  border:none;border-radius:50%;background:var(--amber,#FF9D00);cursor:pointer}

/* In the dead zone the thumb covers the mark, so the mark cannot be what says
   so. The thumb takes the detent's colour instead — and the fill either side
   of it has collapsed to nothing, which is the other half of the same
   statement. */
.orr-speed.at-real::-webkit-slider-thumb{background:var(--ion,#4DE3E1)}
.orr-speed.at-real::-moz-range-thumb{background:var(--ion,#4DE3E1)}

/* 2px, like every other focus ring in both stylesheets. */
.orr-speed:focus-visible{outline:2px solid var(--amber,#FF9D00);outline-offset:2px}
@media (max-width:520px){.orr-speed{width:88px}}

.orr-rate{margin-left:6px;min-width:78px;font-family:var(--mono,monospace);
  font-size:10.5px;color:var(--dim,#93A3B1)}

.orr-clock{flex:1;display:flex;align-items:center;gap:10px}
#orr-date{font-family:var(--mono,monospace);font-size:12px;color:var(--ion,#4DE3E1);
  font-variant-numeric:tabular-nums;letter-spacing:.04em}
#orr-now{border:1px solid var(--rule,#1B242E);padding:3px 9px;
  font-family:var(--cond,sans-serif);font-size:10.5px;font-weight:600;
  color:var(--dimmer,#6E7F8D);background:none;cursor:pointer}
#orr-now:hover{border-color:var(--ion,#4DE3E1);color:var(--ion,#4DE3E1)}


.orrery :focus-visible{outline:2px solid var(--amber,#FF9D00);outline-offset:2px}

/* scrollbars, matching the console's */
.orr-list,.orr-facts{scrollbar-width:thin;
  scrollbar-color:var(--rule,#1B242E) transparent}
.orr-list::-webkit-scrollbar,.orr-facts::-webkit-scrollbar{width:9px}
.orr-list::-webkit-scrollbar-track,.orr-facts::-webkit-scrollbar-track{background:transparent}
.orr-list::-webkit-scrollbar-thumb,.orr-facts::-webkit-scrollbar-thumb{
  background:var(--rule,#1B242E);border:2px solid var(--panel,#0C1116)}
.orr-list::-webkit-scrollbar-thumb:hover,.orr-facts::-webkit-scrollbar-thumb:hover{
  background:var(--dimmer,#6E7F8D)}

@media (max-width:1100px){
  .orr-side{width:var(--left-w,206px)}
  .orr-right{width:var(--right-w,214px)}
}
/* Below this the header cannot hold the title and five ways out, so the two
   that are about Canonn rather than about this system fold into the menu
   that is already there for the tools. */
@media (max-width:1080px){
  .orr-tb.wide,.orrery.has-system .orr-tb.sys.wide{display:none}
  .orr-menu .only-narrow{display:flex}
}
/* And below this even the two system links fold in, so the name keeps its
   room. Everything they did is still one tap away in the menu. The default
   goes above the query, not below it: two rules of equal weight, and the
   later one wins whatever the width is. */
.orr-menu .only-phone{display:none}
@media (max-width:720px){
  /* Matching .orrery.has-system .orr-tb.sys, which is what puts them there —
     four classes, so three would quietly lose. */
  .orrery.has-system .orr-tb.sys{display:none}
  .orr-menu .only-phone{display:flex}
}
@media (max-width:960px){
  .orr-spine,.orr-grip-h{display:none}
}
/* ── stacked ────────────────────────────────────────────────────────────────
   No room for two rails beside a model worth looking at, so they take turns
   under it behind a pair of tabs. The list used to be dropped outright, which
   was defensible when it only held bodies and the panel repeated them — and
   stopped being defensible the moment stations moved into it and nowhere
   else. A phone had the whole station feature missing. */
.orr-tabs{display:none}
@media (max-width:820px){
  .orr-mid{flex-direction:column}
  .orr-stage{order:1;flex:1;min-height:0}
  .orr-tabs{order:2;display:flex;flex:none;background:var(--panel,#0C1116);
    border-top:1px solid var(--rule,#1B242E)}
  .orr-tabs button{flex:1;padding:9px 8px;background:none;border:0;
    border-bottom:2px solid transparent;font-family:var(--cond,sans-serif);
    font-size:12px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
    color:var(--dimmer,#6E7F8D);cursor:pointer}
  .orr-tabs button[aria-selected="true"]{color:var(--amber,#FF9D00);
    border-bottom-color:var(--amber,#FF9D00)}

  /* A definite height, not a cap: the scroller inside is flex:1, and inside a
     parent sized by its own content that resolves to nothing — the panel
     collapsed to 19px. */
  .orr-side{order:3;width:auto;flex:none;height:42%;border:0;
    border-top:1px solid var(--rule,#1B242E)}
  .orr-left,.orr-right{display:none}
  .sheet-list .orr-left{display:flex}
  .sheet-facts .orr-right{display:flex}
  /* Dragging a rail's edge means nothing when it is the width of the screen. */
  .orr-grip-l,.orr-grip-r{display:none}
  .orr-legend{display:none}
}

/* A phone held sideways is short and wide, and stacking is the wrong answer
   to that: it was leaving ninety pixels of model under a full-width sheet.
   Wide is exactly what the desktop layout wants, so it comes back — both
   rails, narrow, either side of the model — and the height is what gives. */
@media (max-height:560px) and (orientation:landscape){
  .orr-mid{flex-direction:row}
  .orr-tabs{display:none}
  /* Capped, not replaced: a width dragged on a desktop is still a preference,
     but two of them at 290px leave 246px of model on an 812px screen. */
  .orr-side{order:0;height:auto;width:min(var(--left-w,152px),22vw)}
  .orr-left,.orr-right{display:flex}
  .orr-left{border-right:1px solid var(--rule,#1B242E);border-top:0}
  .orr-right{width:min(var(--right-w,168px),24vw);
    border-left:1px solid var(--rule,#1B242E);border-top:0}
  .orr-stage{order:0}
  .orr-top{min-height:36px}
  .orr-foot{min-height:32px}
  .orr-find{max-width:180px}
  .orr-hud{top:8px;left:8px;padding:2px 4px;gap:5px}
  .orr-hud .orr-opt span,.orr-hud .orr-opt b,.orr-hud .orr-seg button,
  .orr-hud .orr-tb{padding-top:3px;padding-bottom:3px}
}
/* The strip scrolls sideways when it will not fit, and the scrollbar is
   hidden — which on a phone meant four hundred pixels of controls that looked
   like they did not exist. Given a definite right edge it can wrap instead,
   and everything on it stays visible. */
@media (max-width:820px){
  /* One row that scrolls, not three that wrap: wrapped, the strip stood a
     hundred pixels tall over a stage only three-and-a-half hundred deep, and
     the model is the reason anyone opened this. Scrolling was the original
     behaviour and it was fine — what was missing is any sign that there is
     more, so the right edge fades and the bar is left visible. */
  .orr-hud{right:12px;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin;
    scrollbar-color:var(--rule,#1B242E) transparent;
    -webkit-overflow-scrolling:touch;
    mask-image:linear-gradient(to right,#000 calc(100% - 26px),transparent)}
  .orr-hud::-webkit-scrollbar{height:3px}
  .orr-hud::-webkit-scrollbar-thumb{background:var(--rule,#1B242E)}
  /* Room for a thumb to land on. */
  .orr-hud .orr-opt span,.orr-hud .orr-opt b,.orr-hud .orr-seg button,
  .orr-hud .orr-tb{padding-top:7px;padding-bottom:7px}
}

@media (max-width:560px){
  /* The header cannot hold a search box and everything else on one line at
     this width — it was down to a single letter. It gets its own row. */
  .orr-top{flex-wrap:wrap;gap:8px;padding:6px 8px}
  .orr-find{order:10;flex-basis:100%;max-width:none}
  .orr-home span,.orr-title span{display:none}
  .orr-wip{display:none}
  .orr-foot{gap:10px;padding:0 8px}
  .orr-clock{flex:1;min-width:0}
  #orr-date{font-size:10.5px}
}


/* ── controls get a boundary you can see ──────────────────────────────────
   The console's --rule-strong, applied to the orrery's own pressables for the
   same reason and by the same mechanism. orrery.html loads console.css, so the
   token is defined here too. */
.orr-tb,
.orr-opt,
.orr-seg,
.orr-seg button + button,
.orr-chip,
.orr-filter,
.orr-x,
.orr-s-key,
#orr-now,
.orr-ports button,
.orr-seeds button,
.orr-lost-do button{border-color:var(--rule-strong)}


/* The body list's numeric column is light-seconds from arrival, for bodies and
   stations alike. Saying so once in the header beats repeating a unit on every
   one of Sol's hundred-odd rows — and beats the previous arrangement, which
   was two different units in the same column with no label at all. */
.orr-s-u{margin-left:auto;font-family:var(--mono);font-size:9px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--dimmer)}
