/* Canonn Map Console — chrome.
 *
 * The interface around the Ed3d map: top bar, icon rail, side panels, status
 * strip, command palette and map index. The map itself is Ed3d's (js/main.js,
 * three.js r185); nothing here draws the scene.
 *
 * Paired with js/console.js, which injects the markup these rules style, so a
 * page opts in with one stylesheet link and one script tag.
 */

/* Ed3d still builds its own HUD — the console drives the real .map_filter
   anchors inside #filters rather than reimplementing category toggling — but
   that HUD is never shown. #controls is Ed3d's own 3D/2D/settings cluster,
   which the console replaces with .viewmode; #hud-toggle collapses a panel
   that is not on screen. #nav-controls is deliberately absent: those are
   lcunfool's zoom and pan arrows, kept and restyled further down. */
#hud, #systemDetails, #optionsPanel,
#controls, #hud-toggle { display: none !important; }

:root{
  --void:#05070A; --panel:#0C1116; --panel-2:#111820; --rule:#1B242E;
  --amber:#FF9D00; --ion:#4DE3E1; --text:#CAD4DC;
  /* Raised for legibility: at #6B7986 / #414E5A the labels, toggles and the
     search placeholder sat around 3:1 and 1.9:1 against --panel, which is
     below the 4.5:1 that small text needs. Now ~7:1 and ~4.6:1. */
  --dim:#93A3B1; --dimmer:#6E7F8D;
  /* --rule is #1B242E, which is 1.21:1 against --panel and 1.29:1 against
     --void. As a hairline separating blocks that is the point — quiet
     structure. As the *only* boundary a ghost button has, it is not: WCAG
     1.4.11 asks 3:1 for the visual boundary of a control, and at 1.21:1 these
     read as flat labels until hovered, then vanish on a poor monitor.

     So two tokens with one meaning each. --rule-strong is 3.05:1 on --panel
     and 3.24:1 on --void, measured; it is applied at the bottom of this file
     to things you press, and nowhere else. (The design review suggested
     #2A3846 for this — it measures 1.58:1, so it would not have fixed it.) */
  --rule-strong:#4A637D;
  --sans:'IBM Plex Sans',ui-sans-serif,system-ui,sans-serif;
  --cond:'IBM Plex Sans Condensed','IBM Plex Sans',ui-sans-serif,sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,Menlo,monospace;
}
*{box-sizing:border-box}
html,body{height:100%}
body{margin:0;background:var(--void);color:var(--text);font-family:var(--sans);
  font-size:14px;overflow:hidden;-webkit-font-smoothing:antialiased}
:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
input[type=range]{accent-color:var(--amber)}
.app{display:grid;grid-template-rows:44px 1fr 30px;height:100vh}
/* Embedded in another site (window.CONSOLE = { bare: true }): the map's own
   controls stay, this site's furniture goes. dcoh.watch frames one of these. */
body.bare .app{grid-template-rows:1fr}
body.bare .top, body.bare .strip{display:none}

/* top */
.top{display:flex;align-items:center;gap:12px;padding:0 12px;
  border-bottom:1px solid var(--rule);background:var(--panel);z-index:30}
.top .mark{width:19px;height:19px;flex:none}
.switch{display:flex;align-items:center;gap:8px;border:1px solid var(--rule);
  padding:5px 10px;font-family:var(--cond);font-size:13px;font-weight:600}
.switch:hover{border-color:var(--amber);color:var(--amber)}
.switch .ch{color:var(--dimmer);font-size:9px}
.find{flex:1;max-width:400px;display:flex;align-items:center;gap:9px;
  border:1px solid var(--rule);padding:5px 11px;color:var(--dimmer);
  font-family:var(--mono);font-size:12px}
.find:hover{border-color:var(--dim)}
.find .k{margin-left:auto;border:1px solid var(--rule);padding:1px 5px;font-size:9.5px}
.top .sp{flex:1}
.feed{display:flex;align-items:center;gap:6px;font-family:var(--mono);font-size:10.5px;color:var(--dimmer)}
.feed .d{width:6px;height:6px;border-radius:50%;background:var(--dimmer)}
.feed.live .d{background:#5FD08A;box-shadow:0 0 6px #5FD08A}
.feed.snapshot .d{background:var(--amber)}
.toprail{display:flex;align-items:stretch;gap:0;border:1px solid var(--rule)}
.toprail .tb{display:flex;align-items:center;gap:6px;padding:5px 11px;
  font-family:var(--cond);font-size:12px;font-weight:600;color:var(--dim);
  text-decoration:none;white-space:nowrap}
.toprail .tb + .tb{border-left:1px solid var(--rule)}
.toprail .tb:hover{color:var(--ion)}
.toprail .tb.donate{color:var(--amber)}
.toprail .tb.donate:hover{background:var(--amber);color:#0B0700}

/* body */
.mid{display:flex;min-height:0;position:relative}
.rail{width:56px;flex:none;background:var(--panel);border-right:1px solid var(--rule);
  display:flex;flex-direction:column;align-items:center;padding:8px 0;gap:3px;z-index:20}
.rail button{width:42px;height:42px;display:grid;place-items:center;color:var(--dim);font-size:17px;line-height:1}
.rail button:hover{color:var(--text);background:var(--panel-2)}
.rail button.on{color:var(--amber);background:var(--panel-2);box-shadow:inset 2px 0 0 var(--amber)}
.side{width:300px;flex:none;position:relative;background:var(--panel);border-right:1px solid var(--rule);
  overflow-y:auto;padding:13px;z-index:20}
.side.hidden{display:none}
.s-t{font-family:var(--cond);font-size:10px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--dimmer);margin-bottom:4px}
.s-sub{font-family:var(--mono);font-size:10px;color:var(--dimmer);margin-bottom:11px}
.s-sub b{color:var(--amber);font-weight:500}
/* A second section inside one panel — the site plan under the filters. */
.s-t.sec{margin-top:18px;padding-top:14px;border-top:1px solid var(--rule)}
.grp{margin-top:15px}
.grp:first-child{margin-top:0}

/* Whose filters these are, when a map groups them — one group per faction on
   the landing page, where "Controlled" alone says nothing. */
.lgrp{font-family:var(--cond);font-size:11px;font-weight:600;color:var(--dim);
  margin:11px 0 3px;padding-bottom:3px;border-bottom:1px solid var(--rule)}
.lgrp:first-child{margin-top:0}
.layer{display:flex;align-items:center;gap:9px;padding:5px 5px;cursor:pointer;
  border-left:2px solid transparent}
.layer:hover{background:var(--panel-2)}
.layer.sel{background:var(--panel-2);border-left-color:var(--amber)}
.layer .sw{width:10px;height:10px;flex:none;border-radius:1px}
.layer .nm{flex:1;font-family:var(--mono);font-size:11.5px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.layer .ct{font-family:var(--mono);font-size:10.5px;color:var(--dimmer);font-variant-numeric:tabular-nums}
.layer.off{opacity:.4}
.layer.off .sw{background:transparent!important;box-shadow:inset 0 0 0 1px var(--dim)}
.note{margin-top:11px;padding:9px 10px;border:1px solid var(--rule);background:#080C10;
  font-family:var(--mono);font-size:10px;color:var(--dimmer);line-height:1.6}
.note b{color:var(--text);font-weight:500}
.tmpl{margin-top:12px;border:1px solid var(--rule);background:#080C10}
.tmpl-h{padding:8px 10px;border-bottom:1px solid var(--rule);font-family:var(--cond);
  font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--dimmer);
  display:flex;justify-content:space-between;align-items:center}
.tmpl-h b{color:var(--amber);font-weight:600}
.tmpl img{display:block;width:100%;height:auto;background:#0C1116}
.tmpl-f{padding:7px 10px;font-family:var(--mono);font-size:10px;color:var(--dimmer);
  border-top:1px solid var(--rule);line-height:1.5}

.sysfilter{width:100%;background:var(--panel-2);border:1px solid #24303B;color:var(--text);
  font-family:var(--mono);font-size:11.5px;padding:6px 9px;outline:none;margin-bottom:2px}
.sysfilter:focus{border-color:var(--amber)}
.sysfilter::placeholder{color:var(--dimmer)}
.syssort{display:flex;gap:4px;margin:7px 0 4px}
.syssort button{flex:1;border:1px solid var(--rule);padding:4px 6px;font-family:var(--cond);
  font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--dim)}
.syssort button.on{border-color:var(--amber);color:var(--amber)}
.syslist{margin:0 -13px}
.sysrow{display:flex;align-items:center;gap:8px;padding:6px 13px;cursor:pointer;
  border-left:2px solid transparent}
.sysrow:hover{background:var(--panel-2)}
.sysrow.on{background:var(--panel-2);border-left-color:var(--amber)}
.sysrow .wedge{display:flex;flex:none;gap:2px}
.sysrow .wedge i{width:6px;height:6px;border-radius:1px;display:block}
.sysrow .nm{flex:1;min-width:0;font-family:var(--mono);font-size:11px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sysrow .nm mark{background:none;color:var(--amber);font-weight:600}
.sysrow .ly{font-family:var(--mono);font-size:9.5px;color:var(--dimmer);flex:none;
  font-variant-numeric:tabular-nums}
.sysrow.dim{opacity:.35}
.row{display:flex;align-items:center;gap:9px;padding:6px 0;font-size:12.5px}
.row .lb{flex:1;color:var(--text)}
.row .vv{font-family:var(--mono);font-size:10.5px;color:var(--dimmer)}
.btnrow{display:grid;grid-template-columns:1fr 1fr;gap:4px;margin-top:4px}
.btnrow button{border:1px solid var(--rule);padding:6px 8px;font-size:11.5px;color:var(--text)}
.btnrow button:hover{border-color:var(--ion);color:var(--ion)}
.sw-t{position:relative;width:32px;height:17px;border:1px solid var(--rule);flex:none;cursor:pointer}
.sw-t::after{content:'';position:absolute;top:2px;left:2px;width:11px;height:11px;
  background:var(--dim);transition:left .12s,background .12s}
.sw-t.on{border-color:var(--amber)}
.sw-t.on::after{left:17px;background:var(--amber)}
.drop{margin-top:8px;border:1px dashed var(--rule);padding:16px 12px;text-align:center;
  font-family:var(--mono);font-size:10.5px;color:var(--dimmer);cursor:pointer;line-height:1.6}
.drop:hover,.drop.over{border-color:var(--amber);color:var(--text)}
/* A choice about what to do with a dropped file, sitting under the place
   you drop it rather than in the display panel with the scene toggles. */
.p-check{display:flex;align-items:center;gap:7px;margin-top:9px;cursor:pointer;
  font-family:var(--mono);font-size:10px;color:var(--dimmer);line-height:1.5}
.p-check:hover{color:var(--text)}
.p-check input{accent-color:var(--amber);cursor:pointer;flex:0 0 auto}
/* What was left out of a drop that otherwise worked: a note under the
   prompt rather than in place of it, because the route did load. */
.drop .skipped{margin-top:8px;padding-top:8px;border-top:1px solid var(--rule);
  color:var(--dimmer);font-size:10px}

/* The real named stars, labelled over the map. The host is inert; only the
   two dozen nearest the middle of the view are ever shown. */
.far-lbls{position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:6}
.far-lbl{position:absolute;top:0;left:0;margin:5px 0 0 6px;white-space:nowrap;
  font-family:var(--mono);font-size:9px;letter-spacing:.06em;color:#7C8A99;
  text-shadow:0 0 5px var(--void),0 0 5px var(--void);opacity:.85}
.far-lbl.off{display:none}

/* stage — the REAL Ed3d canvas lives here */
.stage{flex:1;position:relative;min-width:0;background:var(--void)}
#edmap{position:absolute;inset:0}
#edmap #ed3dmap{width:100%;height:100%}
/* lcunfool's zoom + pan cluster, kept and restyled rather than replaced.
   Its handlers are bound by HUD.initHudAction(), which runs even with
   withHudPanel:false, so the buttons work as they always did. */
/* Clear of the status strip, which is 28px tall and drawn over the stage. */
#nav-controls{position:absolute;right:12px;bottom:44px;z-index:8;
  display:flex;flex-direction:column;align-items:center;gap:6px}
#nav-controls .nav-zoom{display:flex;flex-direction:column;gap:4px}
#nav-controls .nav-pan{display:flex;flex-direction:column;align-items:center;gap:4px}
#nav-controls .nav-pan-row{display:flex;gap:4px}
#nav-controls .nav-btn{width:28px;height:28px;border:1px solid var(--rule);
  background:var(--panel);color:var(--dim);display:grid;place-items:center;
  font-size:12px;cursor:pointer;text-decoration:none}
#nav-controls .nav-btn:hover{border-color:var(--amber);color:var(--amber)}
/* Boot screen. Keeps id="loading" because all 35 MapData-*.js files dismiss the
   overlay themselves with document.getElementById('loading').style.display='none'.
   A MutationObserver (console.js) turns that abrupt hide into a fade. */
#loading{position:absolute;inset:0;z-index:40;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:58px;background:var(--void);
  transition:opacity .5s ease;
  /* The boot logo is scaled 1.55x below. A transform does not change an
     element's layout width but it does contribute to scrollable overflow, and
     #bootlogo's clip-path crops the look without touching that — so on a
     360px window the page was permanently 49px wider than the viewport, for a
     logo nobody can see any more. `clip` rather than `hidden` because hidden
     would make this a scroll container. */
  overflow:clip}
/* Faded out, and out of the way: at z-index 40 over the map an invisible
   overlay that still took pointer events would be the whole interaction. */
#loading.done{opacity:0;pointer-events:none}
/* rd-banner is a 1600x400 banner with the atom centred in a lot of empty
   canvas, so it reads small at full width. Scaling the SVG up rather than
   widening the box keeps the limpets' fly-in on screen; the extra gap below
   leaves room for the overflow. */
#bootlogo{width:min(760px,72vw);aspect-ratio:4/1;
  /* clip left/right at the box edge so stray limpets parked out at the banner's
     far ends are cropped, while letting the scaled atom overflow vertically */
  clip-path:inset(-100% 0 -100% 0)}
#bootlogo svg{display:block;width:100%;height:100%;transform:scale(1.55)}
/* Shown only if bodymovin fails or the JSON 404s */
#bootfallback{display:none;font-family:var(--cond);font-size:26px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;color:var(--amber)}
#loading.nolottie #bootlogo{display:none}
#loading.nolottie #bootfallback{display:block}
#bootbar{width:min(320px,50vw);height:2px;background:var(--rule);overflow:hidden}
#bootbar i{display:block;height:100%;width:35%;background:var(--amber);
  animation:bootsweep 1.15s cubic-bezier(.6,0,.35,1) infinite}
@keyframes bootsweep{0%{transform:translateX(-100%)}100%{transform:translateX(386%)}}
#bootmsg{font-family:var(--mono);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--dim);min-height:1em}
#bootmsg b{color:var(--ion);font-weight:400}
@media (prefers-reduced-motion:reduce){
  #loading{transition:none}
  #bootbar i{animation:none;width:100%}
}
.hint{position:absolute;left:14px;bottom:12px;font-family:var(--mono);font-size:10.5px;
  color:var(--dimmer);pointer-events:none;line-height:1.7;z-index:6}
.viewmode{position:absolute;right:12px;top:12px;display:flex;border:1px solid var(--rule);
  background:var(--panel);z-index:8}
.viewmode button{padding:5px 12px;font-family:var(--cond);font-size:11.5px;font-weight:600;
  letter-spacing:.06em;color:var(--dim)}
.viewmode button + button{border-left:1px solid var(--rule)}
.viewmode button.on{background:var(--amber);color:#0B0700}
.viewmode button:not(.on):hover{color:var(--text)}

/* card */
.card{position:absolute;right:12px;top:46px;width:280px;background:var(--panel);
  border:1px solid var(--rule);box-shadow:0 8px 28px rgba(0,0,0,.6);z-index:9;
  /* Stops clear of the zoom/pan cluster below it, which is about 160px tall
     and sits 44px off the bottom. */
  /* 275px was reserved for chrome that is ~160px tall, and the overflow hid
     the two links that take a commander anywhere: at 1280x720 .c-acts began
     395px into a 371px-tall card, so "Open the orrery" and "Open in Signals"
     were simply not on screen, with a scrollbar thumb at 1.21:1 as the only
     hint. The actions are pinned below instead, so they never scroll away. */
  /* A floor, because `calc(100% - Npx)` collapses to nothing on a short stage
     — at 275px reserved it went to zero in a small window, and even at 150px a
     200px-tall stage leaves 50. Never smaller than 220px; the sticky actions
     below mean a short card still shows its way out. */
  max-height:max(220px, calc(100% - 150px));overflow-y:auto;resize:none}
.card.hidden{display:none}
.c-h{padding:11px 13px;border-bottom:1px solid var(--rule);display:flex;
  justify-content:space-between;align-items:flex-start;gap:8px}
.c-h .n{font-family:var(--cond);font-size:15.5px;font-weight:600;color:#E4EBF1;line-height:1.25}
/* 24px square minimum. It was 21x17, which is under the smallest target
   a pointer should have to hit, and the orrery's close was the same size
   with the same problem — the same control, undersized in both places. */
.c-h .x{color:var(--dimmer);font-size:15px;line-height:1;flex:none;
  min-width:24px;min-height:24px;display:grid;place-items:center;margin:-4px -6px -4px 0}
.c-h .x:hover{color:var(--text)}
.c-meta{padding:9px 13px;font-family:var(--mono);font-size:10.5px;color:var(--dimmer);
  line-height:1.7;border-bottom:1px solid var(--rule)}
.c-sec{padding:10px 13px 4px;font-family:var(--cond);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--dimmer);display:flex;justify-content:space-between;gap:8px}
.c-sec b{color:var(--amber);font-weight:600;text-align:right}
.c-link{margin:0 13px 10px;padding:8px 10px;border:1px solid var(--rule);background:#080C10;
  font-family:var(--mono);font-size:10px;color:var(--dimmer);line-height:1.6}
.c-link a{color:var(--ion);text-decoration:none;border-bottom:1px solid rgba(77,227,225,.3)}
/* Pinned to the bottom of the card's scroll box: these are the only way out
   of the card, so they are the last thing that should scroll out of reach. The
   background is opaque because content passes underneath. */
.c-acts{padding:9px 13px 13px;display:grid;grid-template-columns:1fr 1fr;gap:4px;
  position:sticky;bottom:0;background:var(--panel);
  box-shadow:0 -8px 12px -6px var(--panel)}
.c-acts a,.c-acts button{display:flex;align-items:center;gap:6px;padding:6px 9px;
  border:1px solid var(--rule);font-size:11.5px;color:var(--text);text-decoration:none}
.c-acts a:hover,.c-acts button:hover{border-color:var(--ion);color:var(--ion)}
.c-acts .ax{margin-left:auto;color:var(--dimmer);font-size:9px}
.c-acts a.wide{grid-column:1/-1;border-color:var(--amber-dim,#8A5600);color:var(--amber);
  font-weight:600;justify-content:flex-start}
.c-acts a.wide:hover{background:var(--amber);color:#0B0700;border-color:var(--amber)}
.c-acts a.wide .ax{color:inherit}
/* Two wide actions that are not the same kind of thing: the orrery stays on
   this page and takes the console's data colour; Signals leaves for another
   site and keeps the amber. */
.c-acts .wide.alt{grid-column:1/-1;border-color:#2E6E6D;color:var(--ion)}
.c-acts .wide.alt:hover{background:var(--ion);color:#04100F;border-color:var(--ion)}
.c-acts .wide.alt .ax{color:inherit;font-size:11px}
.c-acts .wide.alt[hidden]{display:none}

/* strip */
.strip{display:flex;align-items:stretch;border-top:1px solid var(--rule);
  background:var(--panel);font-family:var(--mono);font-size:11px;z-index:30}
.strip .cell{padding:0 13px;display:flex;align-items:center;gap:7px;border-right:1px solid var(--rule)}
.strip .cell.end{border-right:0;margin-left:auto}
.strip .lb{color:var(--dimmer);font-size:9px;letter-spacing:.09em;text-transform:uppercase}
.strip .vl{color:var(--text);font-variant-numeric:tabular-nums}
.strip .vl.ion{color:var(--ion)}

/* overlays */
.scrim{position:fixed;inset:0;background:rgba(3,5,8,.78);display:none;z-index:60}
.scrim.open{display:flex}
.scrim.pal-scrim{align-items:flex-start;justify-content:center;padding-top:12vh}
.pal{width:min(600px,92vw);background:var(--panel);border:1px solid var(--rule);
  box-shadow:0 24px 70px rgba(0,0,0,.7)}
.pal-in{display:flex;align-items:center;gap:11px;padding:0 15px;border-bottom:1px solid var(--rule)}
.pal-in .cr{color:var(--amber);font-family:var(--mono)}
#pq{flex:1;background:none;border:0;outline:none;color:var(--text);
  font-family:var(--mono);font-size:15px;padding:14px 0}
#pq::placeholder{color:var(--dimmer)}
.pal-res{max-height:46vh;overflow-y:auto;padding:6px}
.pg{font-family:var(--cond);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--dimmer);padding:11px 8px 5px}
.pr{display:flex;align-items:center;gap:11px;padding:8px 9px;cursor:pointer;
  border-left:2px solid transparent}
.pr[aria-selected="true"]{background:var(--panel-2);border-left-color:var(--amber)}
.pr .ic{width:15px;text-align:center;color:var(--dim);font-size:11px;flex:none}
.pr.ext .ic{color:var(--ion)}
.pr .nm{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pr .nm mark{background:none;color:var(--amber);font-weight:600}
.pr .mt{font-family:var(--mono);font-size:10px;color:var(--dimmer);flex:none}
.pal-foot{padding:8px 15px;border-top:1px solid var(--rule);font-family:var(--mono);
  font-size:10px;color:var(--dimmer);display:flex;gap:16px;flex-wrap:wrap}
.pal-empty{padding:22px 10px;font-family:var(--mono);font-size:12px;color:var(--dimmer)}

/* map index — the browsable alternative to searching */
.scrim.idx-scrim{align-items:stretch;justify-content:center;padding:5vh 4vw}
.idx{width:100%;max-width:1080px;background:var(--panel);border:1px solid var(--rule);
  display:flex;flex-direction:column;box-shadow:0 24px 70px rgba(0,0,0,.7)}
.idx-h{padding:15px 20px;border-bottom:1px solid var(--rule);display:flex;
  align-items:baseline;gap:14px}
.idx-h h2{margin:0;font-family:var(--cond);font-size:19px;font-weight:700;color:#E4EBF1}
.idx-h .sub{font-family:var(--mono);font-size:11px;color:var(--dimmer)}
.idx-h .x{margin-left:auto;color:var(--dimmer);font-size:20px;line-height:1}
.idx-h .x:hover{color:var(--text)}
.idx-b{overflow-y:auto;padding:6px 20px 20px}
.idx-g{margin-top:18px}
.idx-gt{font-family:var(--cond);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--amber);padding:8px 0;border-bottom:1px solid var(--rule);margin-bottom:10px}
.idx-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(238px,1fr));gap:6px}
.idx-i{border:1px solid var(--rule);padding:10px 12px;text-align:left;display:block;
  text-decoration:none;color:inherit}
.idx-i:hover{border-color:var(--amber);background:var(--panel-2)}
.idx-i .n{font-family:var(--cond);font-size:13.5px;font-weight:600;color:var(--text)}
.idx-i .d{font-size:11.5px;color:var(--dim);margin-top:3px;line-height:1.45}
.idx-i .s{font-family:var(--mono);font-size:9px;letter-spacing:.06em;text-transform:uppercase;
  margin-top:7px;color:var(--dimmer)}
.idx-i.cur{border-color:var(--amber)}
.idx-i.cur .s{color:var(--amber)}
/* ── narrow and short windows ─────────────────────────────────────────────

   There used to be one media query here, and it did nothing: its
   `.side{position:absolute}` was overridden by a later `.side{position:relative}`
   added for the drag grip, so `left:44px` became a *relative* nudge — the panel
   kept its 300px in the flex flow and also shifted right, leaving a 44px dead
   gutter and painting over the stage's left edge. Which is what sliced the
   system card into "URFACE TEMP" and "uel scoopable" on a folding phone.

   Three things drive the rules below.

   The stage is `flex:1;min-width:0`, but the rail (56px) and the panel (300px)
   are not, so at 360px the stage was left 4px and everything anchored inside it
   — the camera cluster, the 2D toggle, the card, the hint — went off-screen.
   With `body{overflow:hidden}` and `user-scalable=no` there was no way to reach
   any of it. Floating the panel gives the stage the full width back.

   The header's own min-content is ~537px, wider than a phone, and every child
   is `white-space:nowrap`. Shrinking the box is not enough; it has to shed
   items, so GitHub and Donate fold away and the search is allowed to narrow.

   And height matters as much as width, which is the lesson of a folding phone:
   unfolded it is ~752×650 CSS, *wider* than the 360×670 cover screen and
   *shorter*, because the browser adds a tab strip. Keying on width alone means
   unfolding changes nothing. Hence the max-height rule, which also catches a
   short landscape window on a laptop. */

/* Tablet portrait, a folding phone opened, a half-screen laptop window. The
   rail stays; the panel floats over the map instead of squeezing it. */
@media(max-width:1023px){
  .side{position:absolute;left:56px;top:0;bottom:0;z-index:20;
    box-shadow:6px 0 18px rgba(0,0,0,.55)}
  /* The card is anchored in .stage, which now spans the window, so it can sit
     at the right edge and clear the floating panel. It must also outrank it:
     at 752px the two overlap, and the panel is opaque. */
  .card{z-index:21;max-width:calc(100vw - 80px)}
  .toprail .tb.only-wide{display:none}
}

/* Phone. The panel is the whole width because 300px of panel beside 60px of
   map is not a choice worth offering. */
@media(max-width:599px){
  .side{left:56px;right:0;width:auto;box-shadow:none}
  .top{gap:8px;padding:0 8px}
  .switch{padding:5px 7px;font-size:12px}
  .switch #mapname{display:block;max-width:9ch;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap}
  /* Let the search give up width rather than force the row wider than the
     window. `flex:1` alone kept its min-content. */
  .find{min-width:0;flex:1 1 0}
  .find .k{display:none}
  .top .sp{display:none}
  #feedtxt{display:none}
  /* Target and Sol are what a commander reads off. The last cell repeats the
     map's name, which the header already carries, so it goes; what is left is
     allowed to scroll rather than widen the window. */
  .strip .cell.end{display:none}
  .strip{overflow-x:auto}
  .strip .cell{white-space:nowrap}
  .card{right:8px;left:8px;max-width:none;width:auto}
}

/* Short windows, whatever their width. This is the folding-phone case and the
   short-landscape case at once. */
@media(max-height:700px){
  .app{grid-template-rows:38px 1fr 26px}
  .card{top:auto;bottom:8px;max-height:min(58vh, 420px)}
  #nav-controls{bottom:12px}
}

@media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ── touch ────────────────────────────────────────────────────────────────
   Not one control in the console met 44×44. These are the ones a commander
   has to hit while holding the thing in one hand. */
@media(pointer:coarse){
  .rail button{width:44px;height:44px;font-size:19px}
  .rail{width:56px}
  #nav-controls .nav-btn{width:44px;height:44px}
  .viewmode button{padding:10px 16px}
  .selrow button,.syssort button,.p-act{min-height:44px}
  .layer,.sysrow{min-height:44px}
  .c-h .x,.idx-h .x,.card .c-reset{min-width:44px;min-height:44px}
  .tchip{min-height:36px}
  /* A .sw-t toggle is 32×17. The .row around it already spans the panel, so
     it is the real target — it just was not tall enough to be a comfortable
     one, and it carries no handler of its own, so the toggle stays the thing
     that is pressed. */
  .row{min-height:44px}
  /* The base rule positions the knob with `left`, so stay in that idiom — a
     transform here would stack on top of it and overshoot the track. A 40px
     track with a 14px knob and 2px of padding puts the on-state at 22px. */
  .sw-t{width:40px;height:22px}
  .sw-t::after{width:14px;height:14px}
  .sw-t.on::after{left:22px}
}


/* ── details added after the first round of real use ─────────────────────── */

/* Scrollbars inside the chrome, so the card and the panels do not show the
   host's default light ones against a dark surface. */
.card, .side, .syslist, .idx, .pal-res{
  scrollbar-width:thin; scrollbar-color:var(--rule) transparent}
.card::-webkit-scrollbar, .side::-webkit-scrollbar, .syslist::-webkit-scrollbar,
.idx::-webkit-scrollbar, .pal-res::-webkit-scrollbar{width:10px;height:10px}
.card::-webkit-scrollbar-track, .side::-webkit-scrollbar-track,
.syslist::-webkit-scrollbar-track, .idx::-webkit-scrollbar-track,
.pal-res::-webkit-scrollbar-track{background:transparent}
.card::-webkit-scrollbar-thumb, .side::-webkit-scrollbar-thumb,
.syslist::-webkit-scrollbar-thumb, .idx::-webkit-scrollbar-thumb,
.pal-res::-webkit-scrollbar-thumb{
  background:var(--rule);border:2px solid var(--panel);border-radius:6px}
.card::-webkit-scrollbar-thumb:hover, .side::-webkit-scrollbar-thumb:hover,
.syslist::-webkit-scrollbar-thumb:hover, .idx::-webkit-scrollbar-thumb:hover,
.pal-res::-webkit-scrollbar-thumb:hover{background:var(--dimmer)}
/* Nothing in the chrome should ever scroll sideways. */
.card, .side{overflow-x:hidden}

/* System "infos" is authored HTML and carries site thumbnails and links; they
   have to sit inside the card rather than forcing it wide. */
.card .bd img{max-width:100%;height:auto;display:block;margin:6px 0;
  border:1px solid var(--rule)}
.card .bd a{color:var(--ion)}
.card .bd a:hover{color:var(--amber)}
.card .bd{display:block;overflow-wrap:anywhere}

/* System names run long — "Col 173 Sector PF-E b28-3" is 25 characters — and
   were being clipped to about 20. The panel is wider now, the distance column
   is fixed and narrow so it cannot squeeze the name, and the condensed face
   fits more in the same space than the mono one did. */
.sysrow{gap:6px}
.sysrow .nm{font-family:var(--cond);font-size:12px;letter-spacing:.01em}
.sysrow .ly{width:46px;text-align:right;flex:none}
.sysrow .wedge{max-width:26px;overflow:hidden}

/* ── systems panel: sticky controls, paging, back to top ─────────────────── */

/* The filter and sort buttons stay put while the list scrolls; -13px cancels
   the panel's own padding so the header sits flush at the top. */
.syshead{position:sticky;top:-13px;z-index:3;background:var(--panel);
  padding-top:13px;margin:-13px -13px 0;padding-left:13px;padding-right:13px;
  border-bottom:1px solid var(--rule);padding-bottom:9px}
.sysmore{font-family:var(--mono);font-size:9.5px;color:var(--dimmer);
  padding:8px 13px 2px;text-align:center}
.totop{position:sticky;bottom:6px;margin:6px auto 0;display:none;
  font-family:var(--cond);font-size:11px;font-weight:600;letter-spacing:.06em;
  padding:5px 12px;background:var(--panel-2);color:var(--dim);
  border:1px solid var(--rule);cursor:pointer;z-index:4}
.totop.show{display:block}
.totop:hover{color:var(--amber);border-color:var(--amber)}

/* ── resizable panel ─────────────────────────────────────────────────────── */

/* `.side{position:relative}` used to live here, for .side-grip's benefit. It
   is in the base rule above now: down here it came *after* the narrow-layout
   media query and had the same specificity, so it won — and the one rule that
   made the console usable on a small window never applied at all. */
.side-grip{position:absolute;top:0;right:-3px;width:7px;height:100%;
  cursor:col-resize;z-index:25;touch-action:none}
.side-grip::after{content:'';position:absolute;top:0;right:3px;width:1px;height:100%;
  background:transparent;transition:background .12s ease}
.side-grip:hover::after{background:var(--amber)}
body.resizing{cursor:col-resize;user-select:none}
body.resizing .side-grip::after{background:var(--amber)}

/* Layers panel: bulk selection and the hide-vs-dim choice. */
.selrow{display:flex;gap:6px;margin:0 0 8px}
.selrow button{flex:1;font-family:var(--cond);font-size:11px;font-weight:600;
  letter-spacing:.05em;padding:5px 0;background:var(--panel-2);color:var(--dim);
  border:1px solid var(--rule);cursor:pointer}
.selrow button:hover:not(:disabled){color:var(--amber);border-color:var(--amber)}
.selrow button:disabled{opacity:.4;cursor:default}
.hidechk{display:flex;align-items:center;gap:8px;margin:0 0 12px;padding-bottom:11px;
  border-bottom:1px solid var(--rule);
  font-family:var(--cond);font-size:11.5px;color:var(--dim);cursor:pointer}
.hidechk input{accent-color:var(--amber);cursor:pointer}
.hidechk:hover{color:var(--text)}


/* ── system card: sizing, moving, and per-site thumbnails ───────────────── */

/* Each site's own "infos" carries a thumbnail, and a system with three ruins
   was stacking three full-width images plus the template map — which is what
   made the card run the height of the screen. The per-site ones are shown as
   small stamps; the selected site's template map below stays full width. */
.card .site .bd img{max-width:64px;margin:4px 0 2px}

.card.moved{right:auto;top:auto}
.c-h{cursor:grab;user-select:none}
.c-h:active{cursor:grabbing}
.card .c-grip{position:absolute;left:0;bottom:0;width:16px;height:16px;
  cursor:nesw-resize;z-index:2;touch-action:none}
.card .c-grip::after{content:'';position:absolute;left:3px;bottom:3px;
  width:7px;height:7px;border-left:2px solid var(--rule);border-bottom:2px solid var(--rule)}
.card .c-grip:hover::after{border-color:var(--amber)}
.card .c-reset{display:block;margin-left:auto;min-height:24px;font-family:var(--mono);
  font-size:9.5px;color:var(--dimmer);
  background:none;border:0;cursor:pointer;padding:0 13px 9px}
.card .c-reset:hover{color:var(--amber)}
body.card-dragging{user-select:none;cursor:grabbing}


/* Card: the types present, and the concatenated site blocks. */
/* Which site plan to show, picked explicitly rather than by hovering the layer
   rows — hovering meant the plan changed whenever the pointer crossed the
   list on its way somewhere else. */
.tmplpick{display:flex;flex-wrap:wrap;gap:4px;margin:10px 0 8px}
.tchip{display:flex;align-items:center;gap:6px;padding:4px 9px;background:var(--panel-2);
  border:1px solid var(--rule);color:var(--dim);font-family:var(--cond);font-size:11px;
  font-weight:600;cursor:pointer}
.tchip .sw{width:8px;height:8px;border-radius:1px;display:block}
.tchip:hover{color:var(--text)}
.tchip.on{border-color:var(--amber);color:var(--amber)}
/* ── the primary star ───────────────────────────────────────────────────────
   What you actually arrive at, from the system dump Signals reads.

   --star is the star's own colour, out of data/spectral-colors.json, set per
   card from the spectral class. It paints the disc and the rule under the
   header and nothing else: half that table is dark (Y-class browns are
   #5d347e) and would fail contrast as text, so type stays on the console's
   own palette and the colour stays where it is safe and truthful. */
.c-star{padding:10px 13px 11px;border-bottom:1px solid var(--rule);--star:var(--dim)}
.c-star-h{display:flex;align-items:center;gap:9px;min-height:16px}
.c-star-lb{flex:1;min-width:0;font-family:var(--cond);font-size:9.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--dimmer)}
.c-star-h b{font-family:var(--mono);font-size:11px;letter-spacing:.06em;
  font-weight:500;color:var(--amber)}

/* The star itself: its real colour, at a size that follows its radius. The one
   thing on this card that is the object rather than a description of it. */
.c-star-disc{flex:none;width:var(--d,12px);height:var(--d,12px);border-radius:50%;
  background:var(--star);box-shadow:0 0 11px -1px var(--star)}

.c-star-n{margin:7px 0 0;font-family:var(--cond);font-size:12.5px;color:var(--text)}
/* Which star, when there is more than one: "A", "B"… */
.c-star-n i{font-family:var(--mono);font-style:normal;font-size:11px;color:var(--dim);
  margin-right:7px}

/* Four measurements on hairlines, the way an instrument would show them. The
   1px gap over a --rule ground is the rule: no doubled borders to reconcile. */
.c-star-m{display:grid;grid-template-columns:1fr 1fr;gap:1px;margin:9px 0 0;
  background:var(--rule);border:1px solid var(--rule)}
.c-star-m > div{background:var(--panel);padding:7px 9px 8px;min-width:0}
.c-star-m 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}
/* The number is the datum: large, bright, tabular so the two rows line up.
   The unit is a footnote and is sized and coloured like one. */
.c-star-m 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}
.c-star-m dd em{font-style:normal;font-size:9.5px;color:var(--dimmer);
  letter-spacing:.02em;white-space:nowrap}

.c-star-f{margin-top:9px}
/* Refuelling is the one fact here you act on, so it leads and takes the
   colour the console uses for live data. */
.c-star-scoop{display:block;font-family:var(--cond);font-size:11.5px;
  font-weight:600;line-height:16px}
.c-star-scoop.yes{color:var(--ion)}
/* transform, not vertical-align: nudging an inline ::before up by its
   baseline grows the line box, and this line has to stay exactly 16px whether
   it holds the diamond or the waiting bar. */
.c-star-scoop.yes::before{content:'\25C6';margin-right:6px;font-size:8px;
  display:inline-block;line-height:1;transform:translateY(-1px)}
.c-star-scoop.no{color:var(--dimmer)}
.c-star-c{display:block;margin-top:2px;font-family:var(--mono);font-size:10px;
  line-height:15px;color:var(--dimmer);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* Waiting. Same block, same height — the point of it. The disc searches
   rather than shining, and the numbers are held open by bars. */
.c-star.wait .c-star-disc{width:12px;height:12px;background:transparent;
  box-shadow:inset 0 0 0 1.5px var(--dim);animation:starseek 1.5s ease-in-out infinite}
.c-star.wait .c-star-n{color:var(--dimmer)}
.c-star .bar{display:inline-block;vertical-align:middle;background:var(--panel-2);
  animation:starbar 1.5s ease-in-out infinite}
.c-star-m .bar{height:11px;align-self:center}
.c-star-f .bar{height:9px}
.c-star-m > div:nth-child(1) .bar{width:66%}
.c-star-m > div:nth-child(2) .bar{width:44%;animation-delay:.12s}
.c-star-m > div:nth-child(3) .bar{width:50%;animation-delay:.24s}
.c-star-m > div:nth-child(4) .bar{width:60%;animation-delay:.36s}
@keyframes starseek{
  0%,100%{box-shadow:inset 0 0 0 1.5px var(--rule)}
  50%{box-shadow:inset 0 0 0 1.5px var(--dim),0 0 8px -2px var(--dim)}
}
@keyframes starbar{0%,100%{opacity:.45}50%{opacity:1}}
@media (prefers-reduced-motion:reduce){
  .c-star.wait .c-star-disc,.c-star .bar{animation:none}
  .c-star.wait .c-star-disc{box-shadow:inset 0 0 0 1.5px var(--dim)}
}

.c-body{padding:2px 13px 10px;font-family:var(--mono);font-size:10.5px;
  line-height:1.75;color:var(--dim);border-bottom:1px solid var(--rule)}
.c-body a{color:var(--ion);text-decoration:none}
.c-body a:hover{color:var(--amber);text-decoration:underline}


/* The site plans are drawn in a dark navy that all but disappears against the
   panel. Their colour lives inside <defs> and is reached through <use>, so
   there is nothing to restyle from here — brightening the rendered image is
   both simpler and easier to tune. Kept well short of washing out: the lines
   should read as blueprint, not glow. */
#tmpl-img{filter:brightness(1.8) saturate(1.2)}


/* Saved views: a place you framed and want back. Same row as a layer, so the
   panel reads as one thing, with a way to forget one. */
.marks{margin:6px 0 10px}
.marks .layer{cursor:pointer}
.marks .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.marks .mk-x{flex:none;padding:0 4px;background:none;border:0;color:var(--dimmer);
  font-size:15px;line-height:1;cursor:pointer}
.marks .mk-x:hover{color:var(--amber)}
/* A panel action across the full width. `.wide` belongs to the card's action
   grid and does nothing out here, which left these two sitting side by side
   at a hundred pixels each. */
.p-act{display:block;width:100%;margin-top:8px;border:1px solid var(--rule);
  padding:7px 8px;font-size:11.5px;color:var(--text);background:none;cursor:pointer}
.p-act:hover{border-color:var(--ion);color:var(--ion)}


/* ── controls get a boundary you can see ──────────────────────────────────
   Appended deliberately: equal specificity, later in source, so it lifts the
   border colour of everything you press without touching the 50-odd places
   --rule is doing its real job as structure. See the note beside
   --rule-strong for the measurements. */
.switch,
.find,
.viewmode,
.viewmode button + button,
#nav-controls .nav-btn,
.selrow button,
.syssort button,
.btnrow button,
.p-act,
.tchip,
.sw-t,
.c-acts a,
.c-acts button,
.c-h .x,
.idx-h .x,
.totop,
.sysfilter,
.find .k{border-color:var(--rule-strong)}


/* The systems list's numeric column is light-years from Sol, which is the
   origin of Elite's coordinates. Naming it once above the list beats a unit on
   each of the sixteen thousand rows multifaction.html?factions=All produces —
   and beats what was there before, which was nothing at all. */
.syscol{margin-left:auto;font-family:var(--mono);font-size:9px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--dimmer);
  white-space:nowrap;align-self:center}
