:root {
  --bg: #02060d;
  --panel: rgba(8, 16, 28, 0.78);
  --line: rgba(110, 200, 255, 0.18);
  --text: #cfe8ff;
  --dim: #7891a8;
  --accent: #67c8ff;
  --accent2: #ff6b6b;
  --green: #67e8a4;
  --mono: 'JetBrains Mono', 'Fira Code', 'Consolas', ui-monospace, monospace;
  /* Aesthetic display + script families for the brand + tagline. */
  --display: 'Orbitron', 'JetBrains Mono', ui-monospace, monospace;
  --script:  'Caveat', 'Brush Script MT', cursive;
}

* { box-sizing: border-box; }
html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
}
body {
  color: var(--text);
  font-family: var(--mono);
  /* Base bumped 12 → 14 (~+17 %) — combined with the per-component
     bumps below, most HUD text reads ~30 % larger overall. */
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  /* Positioning context for the absolute .top-logo so that, on pages whose
     body scrolls, the mark scrolls up with the content instead of staying
     pinned to the viewport. */
  position: relative;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

#globe {
  position: fixed;
  inset: 0;
  z-index: 0;
  touch-action: none;
}
#globe.hidden-view { display: none; }

/* Left-edge HUD used by the Cone page's Show button to surface the
   per-satellite list.  Mirrors .hud-tr on the right; starts hidden and
   gets revealed once Show populates it. */
.hud-tl {
  position: fixed;
  top: 60px;
  left: 14px;
  width: 320px;
  max-width: calc(100vw - 28px);
  z-index: 10;
  display: none;          /* shown via .shown class after first Show pass */
  flex-direction: column;
  gap: 8px;
  max-height: calc(100vh - 74px);
}
.hud-tl.shown { display: flex; }
@media (max-width: 600px) {
  .hud-tl { width: calc(100vw - 16px); left: 8px; top: 56px; max-height: calc(100vh - 70px); }
}

/* Google Maps satellite-view container on the Cone page.  Sits in the
   same z-stack as #globe; gets shown once we have a Maps key and the
   user has pressed Compute.  Native pinch-zoom is enabled at JS level
   via gestureHandling: 'greedy'. */
#gmap {
  position: fixed;
  inset: 0;
  z-index: 1;
  display: none;
  /* let Google handle gestures itself; CSS touch-action: manipulation
     keeps double-tap-to-zoom on while letting maps own pinch */
  touch-action: manipulation;
}
#gmap.shown { display: block; }

/* Pink down-arrow overlay marker on the Cone globe.  globe.gl puts the
   centre of the element at the lat/lng/altitude; we shift left by 50 %
   and up by 98 % so the bottom-centre — which is precisely the SVG
   arrowhead tip — sits on the point. */
.arrow-marker {
  width: 28px;
  height: 42px;
  transform: translate(-50%, -98%);
  pointer-events: none;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.65));
}
.arrow-marker svg {
  width: 100%;
  height: 100%;
  display: block;
}

.topbar {
  position: fixed;
  top: 0;
  left: 0;
  padding: 14px 18px;
  z-index: 10;
  pointer-events: none;
}
.brand {
  font-family: var(--display);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: 0.22em;
  color: var(--accent);
  text-shadow:
    0 0 10px rgba(103, 200, 255, 0.55),
    0 0 24px rgba(103, 200, 255, 0.18);
}
.brand .brand-short {
  font-weight: 900;
  font-size: 22px;
  letter-spacing: 0.34em;
}
.brand .brand-long {
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 0.18em;
  color: var(--text);
  opacity: 0.75;
}
.sub {
  font-family: var(--script);
  font-size: 22px;
  color: var(--accent2);
  letter-spacing: 0.02em;
  margin-top: 2px;
  font-style: normal;
  text-shadow: 0 0 8px rgba(255, 107, 107, 0.35);
}

.hud-tr {
  position: fixed;
  top: 86px;
  right: 14px;
  /* Symmetric with .left-nav — both panels are 240 px wide. */
  width: 240px;
  max-width: calc(100vw - 28px);
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: calc(100vh - 100px);
  /* Allow internal scrolling when expanded <details> push the total
     content past the viewport — otherwise the overflow is invisible. */
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 10px 12px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, .35) inset,
    0 6px 24px rgba(0, 0, 0, .45);
}

/* --- Clock --- */
.clock .row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 2px 0;
}
.clock .row.date {
  justify-content: flex-end;
  margin-top: 2px;
}
.clock .label,
.panel .label {
  color: var(--dim);
  font-size: 14px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.clock .time {
  font-variant-numeric: tabular-nums;
  font-size: 26px;
  color: var(--accent);
  letter-spacing: 0.05em;
  text-shadow: 0 0 10px rgba(103, 200, 255, 0.55);
}
.dim { color: var(--dim); font-size: 10px; }

/* --- Collapsible satellite panels --- */
details.sats > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  user-select: none;
  gap: 8px;
}
details.sats > summary::-webkit-details-marker { display: none; }
details.sats > summary::after {
  content: '▾';
  color: var(--dim);
  margin-left: 6px;
  transform: rotate(-90deg);
  transition: transform .15s ease;
  font-size: 12px;
}
details.sats[open] > summary::after { transform: rotate(0deg); }

.hint-inline {
  color: var(--dim);
  font-size: 12px;
  letter-spacing: 0.12em;
  margin-left: 6px;
  text-transform: uppercase;
}
.count {
  font-variant-numeric: tabular-nums;
  font-size: 22px;
  color: var(--green);
  text-shadow: 0 0 8px rgba(103, 232, 164, 0.45);
}
#cn-count { color: var(--accent2); text-shadow: 0 0 8px rgba(255, 107, 107, 0.45); }

.hint {
  color: var(--dim);
  margin: 8px 0 4px;
  font-size: 14px;
  line-height: 1.45;
}

.list {
  margin-top: 4px;
  max-height: 280px;
  overflow-y: auto;
  padding-right: 4px;
}

/* Observer-lookup form (lat / lon / recompute) */
.lookup-form {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 8px 0 4px;
}
.lookup-form label {
  flex: 1 1 92px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 13.5px;
  color: var(--dim);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.lookup-form input[type="number"] {
  background: rgba(0, 0, 0, 0.32);
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--text);
  font-family: var(--mono);
  font-size: 14px;
  padding: 5px 7px;
  outline: none;
  width: 100%;
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
}
.lookup-form input[type="number"]::-webkit-outer-spin-button,
.lookup-form input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.lookup-form input[type="number"]:focus { border-color: var(--accent); }
.lookup-form button {
  flex: 1 1 100%;
  margin-top: 2px;
  background: rgba(103, 200, 255, 0.08);
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--accent);
  font-family: var(--mono);
  /* +30 % font over the original 10 px, padding trimmed so the button
     hugs the label rather than swallowing it in chrome. */
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 4px 7px;
  cursor: pointer;
}
.lookup-form button:hover { border-color: var(--accent); background: rgba(103, 200, 255, 0.14); }

.list::-webkit-scrollbar { width: 6px; }
.list::-webkit-scrollbar-thumb {
  background: rgba(110, 200, 255, 0.22);
  border-radius: 3px;
}
.list::-webkit-scrollbar-track { background: transparent; }

.item {
  padding: 6px 0;
  border-bottom: 1px solid rgba(110, 200, 255, 0.07);
}
.item:last-child { border-bottom: 0; }
.item .name {
  color: var(--text);
  font-size: 14px;
  letter-spacing: 0.04em;
  display: flex;
  align-items: center;
  gap: 6px;
}
.item .meta {
  color: var(--accent);
  font-size: 13px;
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}
.item .meta.muted { color: var(--dim); }
.item .meta strong {
  color: var(--text);
  font-weight: normal;
}

.tag {
  font-size: 9px;
  padding: 1px 5px;
  border-radius: 3px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.tag.cn {
  background: rgba(255, 107, 107, 0.18);
  color: var(--accent2);
  border: 1px solid rgba(255, 107, 107, 0.3);
}

.footer {
  font-size: 11px;
  color: var(--dim);
  padding: 6px 4px 0;
  line-height: 1.55;
}
#status::before {
  content: '●';
  color: var(--green);
  margin-right: 6px;
  text-shadow: 0 0 6px rgba(103, 232, 164, 0.6);
}
#status.err::before { color: var(--accent2); text-shadow: 0 0 6px rgba(255, 107, 107, 0.6); }
#status.warn::before { color: #f7c948; text-shadow: 0 0 6px rgba(247, 201, 72, 0.6); }

/* --- Centre-left stacked nav launchers --- */
/* Left-edge nav panel, mirror of .hud-tr.  Anchored just below the brand
   strip so it stacks symmetrically with the right HUD on the other side
   of the screen. */
.left-nav {
  position: fixed;
  left: 14px;
  top: 86px;
  /* Symmetric with .hud-tr — both panels are 240 px wide. */
  width: 240px;
  max-width: calc(100vw - 28px);
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: calc(100vh - 100px);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.btn-nav {
  display: flex;
  align-items: center;
  gap: 6px;
  /* Tight padding so the button hugs its label rather than dominating it. */
  padding: 5px 9px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 5px;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 14px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  text-shadow: 0 0 8px rgba(103, 200, 255, 0.45);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: pointer;
  transition: background .15s, border-color .15s, transform .15s;
}
.btn-nav:hover {
  border-color: var(--accent);
  background: rgba(8, 16, 28, 0.92);
  transform: translateX(2px);
  text-decoration: none;
}
.btn-nav-icon {
  font-size: 18px;
  line-height: 1;
  color: var(--green);
  text-shadow: 0 0 8px rgba(103, 232, 164, 0.5);
}

/* ChinRepo / accent-coloured nav button.  Lives inside .left-nav as a
   regular row item now; the bottom-left fixed-position anchor has been
   retired so all the launchers stack symmetrically with .hud-tr. */
.btn-bl .btn-nav-icon {
  color: var(--accent2);
  text-shadow: 0 0 8px rgba(255, 107, 107, 0.55);
}


/* --- Theme toggle sits inside .left-nav and inherits .btn-nav styling.
   A small accent on the icon distinguishes it from the page links. */
.btn-theme {
  margin-top: 4px;
  border-top: 1px solid var(--line);
  border-radius: 0 0 5px 5px;
  border-top-left-radius: 5px;
  border-top-right-radius: 5px;
  font-family: inherit;
}
.btn-theme .btn-nav-icon { color: #ffd166; text-shadow: 0 0 8px rgba(255, 209, 102, 0.6); }
body.light .btn-theme .btn-nav-icon { color: #6a1b9a; text-shadow: 0 0 8px rgba(106, 27, 154, 0.45); }

/* --- Main page light theme ----------------------------------------------
   Re-defines the CSS custom properties scoped to body.light, so every rule
   that reads var(--bg)/var(--text)/etc switches palette automatically.  The
   3-D globe canvas itself stays unchanged (it's a textured WebGL scene). */
body.light {
  --bg:       #eef2f6;
  --panel:    rgba(255, 255, 255, 0.88);
  --line:     #cfd8e3;
  --text:     #1a2b40;
  --dim:      #5a6a7d;
  --accent:   #1565c0;
  --accent2:  #c1392b;
  --green:    #2e7d4f;
}
body.light .brand { text-shadow: none; }
body.light .clock .time {
  text-shadow: 0 0 6px rgba(21, 101, 192, 0.25);
}
body.light .count { text-shadow: none; }
body.light .ticker-label { text-shadow: none; }
body.light .btn-nav-icon,
body.light .btn-bl .btn-nav-icon { text-shadow: none; }
body.light .panel .label,
body.light .topbar .sub { color: var(--dim); }

/* --- News ticker (Chinese rocket launches) ------------------------------
   Lives to the right of the ChinRepo button.  The viewport clips, the
   track scrolls right-to-left infinitely.  Items are duplicated in JS so
   the keyframe loop is seamless. */
.news-ticker {
  position: fixed;
  bottom: 14px;
  left: 50%;
  /* Centred on the viewport (translateX -50%).  The 240 px side panels
     (.left-nav, .hud-tr) can run all the way to the bottom, so the ticker
     is bounded to reserve ~290 px each side and clear them completely —
     it shortens rather than slide under a panel. */
  width: min(720px, calc(100vw - 580px));
  transform: translateX(-50%);
  height: 38px;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  overflow: hidden;
}
.ticker-label {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--accent2);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-shadow: 0 0 8px rgba(255, 107, 107, 0.45);
  border-right: 1px solid var(--line);
  padding-right: 12px;
  cursor: pointer;
  text-decoration: none;
  transition: color .15s, text-shadow .15s;
}
a.ticker-label:hover {
  text-decoration: none;
  color: #ff9c9c;
  text-shadow: 0 0 12px rgba(255, 107, 107, 0.8);
}
.ticker-label-go { font-size: 11px; opacity: 0.8; }
.ticker-viewport {
  flex: 1;
  overflow: hidden;
  position: relative;
}
.ticker-track {
  display: inline-flex;
  white-space: nowrap;
  animation: ticker-scroll 180s linear infinite;
  will-change: transform;
}
.news-ticker:hover .ticker-track { animation-play-state: paused; }
@keyframes ticker-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.ticker-item {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  margin-right: 36px;
  font-size: 11px;
  color: var(--text);
}
/* Sequence number badge — replaces the old bullet.  Blue for world items,
   red for China-relevant ones so the China focus reads at a glance. */
.ticker-item .num {
  flex: 0 0 auto;
  min-width: 15px;
  padding: 1px 4px;
  border-radius: 3px;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  text-align: center;
  color: var(--accent);
  background: rgba(103, 200, 255, 0.14);
  font-variant-numeric: tabular-nums;
}
.ticker-item.cn .num {
  color: var(--accent2);
  background: rgba(255, 107, 107, 0.16);
}
.ticker-item a {
  color: var(--accent);
  text-decoration: none;
}
.ticker-item a:hover { text-decoration: underline; }
/* Publication date prefix — dim mono badge, slightly raised cap-height
   so it reads as metadata rather than part of the headline. */
.ticker-item .date {
  color: var(--dim);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.ticker-item .source {
  color: var(--dim);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.ticker-status {
  display: inline-block;
  color: var(--dim);
  font-size: 11px;
  padding: 0 12px;
}

@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  /* Not enough horizontal space to leave 150 px gutters on each side, so
     the ticker drops above the ChinRepo button and uses the full width. */
  .news-ticker {
    left: 8px;
    right: 8px;
    width: auto;
    transform: none;
    bottom: 60px;
  }
}

/* --- Satellite markers (HTML overlay on globe) --- */
.sat-dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 6px var(--green), 0 0 10px rgba(103, 232, 164, 0.5);
  transform: translate(-50%, -50%);
  cursor: crosshair;
  position: relative;
}
/* Expanded transparent hit area so the tiny visible dot is easy to target
   on both desktop and touch.  Pointer events on the pseudo bubble up to
   the parent .sat-dot, which is what the tooltip listeners are bound to. */
.sat-dot::after {
  content: '';
  position: absolute;
  inset: -7px;
  border-radius: 50%;
}
.sat-dot.cn {
  background: var(--accent2);
  box-shadow: 0 0 6px var(--accent2), 0 0 10px rgba(255, 107, 107, 0.5);
  width: 5px;
  height: 5px;
}
.sat-dot.orbit { width: 5px; height: 5px; }

/* --- Immersive mode (orbits.html, while NAZAR is playing) -------------
   Hides the entire HUD / nav / topbar / ticker, leaving only the
   pause toggle floating in the top-right corner.  Lifted automatically
   when the user pauses or exits fullscreen (ESC). */
body.immersive .topbar,
body.immersive .hud-tr,
body.immersive .news-ticker,
body.immersive .float-toggle {
  display: none !important;
}
/* Strip the .left-nav chrome and hide every child except the audio
   toggle, so only the Pause control floats at top-right.
   `display: flex` is forced here because the mobile drawer rule below
   sets the nav to display: none unless body.nav-open. */
body.immersive .left-nav {
  display: flex !important;
  position: fixed;
  top: max(14px, env(safe-area-inset-top, 0px));
  right: 14px;
  left: auto;
  width: auto;
  max-width: none;
  max-height: none;
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
  gap: 0;
  overflow: visible;
  transform: none;
}
body.immersive .left-nav > a,
body.immersive .left-nav > button:not(#audio-toggle) {
  display: none !important;
}
body.immersive #audio-toggle {
  display: flex;
  background: rgba(2, 6, 13, 0.85);
  border: 1px solid var(--accent2);
  padding: 9px 14px;
}

/* --- Globe.gl scene-tooltip (the hover label container) --- */
.scene-tooltip {
  pointer-events: none;
  z-index: 100;
}
.sat-tip {
  background: rgba(8, 16, 28, 0.95);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 8px 12px;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.55;
  color: var(--text);
  white-space: nowrap;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.55);
  max-width: 320px;
}
.sat-tip b {
  color: var(--accent);
  font-weight: normal;
  letter-spacing: 0.04em;
}
.sat-tip .cn {
  margin-top: 2px;
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent2);
}
.sat-tip .cls {
  margin-top: 2px;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* --- Orbits page · class legend --- */
.legend-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 3px 0;
  font-size: 11.5px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.legend-swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* Compact top-corner toggle pills used on mobile to summon the nav menu
   and the data HUD.  Hidden on desktop where the full panels live on
   screen permanently. */
.float-toggle {
  display: none;
  align-items: center;
  gap: 6px;
  position: fixed;
  top: 8px;
  padding: 7px 11px;
  z-index: 12;
  background: var(--panel);
  border: 1px solid var(--accent);
  border-radius: 6px;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-shadow: 0 0 6px rgba(103, 200, 255, 0.45);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: pointer;
}
.float-toggle.menu-toggle { left: 8px; }
.float-toggle.data-toggle { right: 8px; }
.float-toggle .ico { font-size: 14px; line-height: 1; }
body.nav-open  .float-toggle.menu-toggle,
body.hud-open  .float-toggle.data-toggle {
  background: rgba(103, 200, 255, 0.18);
}

@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  /* Topbar squeezed between the MENU button (top-left) and Takshashila
     logo (top-right) — clear the 88 px the button needs on the left
     and ~110 px the logo needs on the right. */
  .topbar { padding: 10px 110px 10px 92px; text-align: center; pointer-events: none; }
  .brand  { font-size: 13px; letter-spacing: 0.18em; }
  .brand .brand-long { display: none; }  /* full expansion is in <title> and on desktop only */
  .sub    { font-size: 9px; font-style: italic; }

  /* The legacy MENU/DATA pills are obsolete — the universal
     mobile-menu.js drop-down replaces them.  Keep them in markup for
     any direct callers but hide on every viewport-mobile case. */
  .float-toggle { display: none !important; }

  .btn-nav { padding: 7px 12px; font-size: 12px; gap: 6px; }
  .btn-nav-icon { font-size: 14px; }
  .panel { padding: 7px 10px; }
}

/* ===========================================================
   Universal mobile drop-down menu (mobile-menu.js).

   - Hidden on desktop (display:none below the media query).
   - On mobile the script moves every chrome panel into .mobile-drawer
     so the globe canvas fills the screen.  The drawer is toggled
     open / closed by the ☰ button and a tap on the backdrop.
   =========================================================== */
.mobile-menu-btn,
.mobile-backdrop,
.mobile-drawer { display: none; }

/* PHONE breakpoint — kept identical to PHONE_MQ in mobile-menu.js so the
   injected chrome is always styled.  The second arm catches landscape
   phones (short height) that exceed 720 px wide. */
@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  /* ☰ MENU button — top-left, compact pill. */
  .mobile-menu-btn {
    position: fixed;
    top: 7px;
    left: 7px;
    z-index: 100;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 9px;
    background: rgba(2, 6, 13, 0.88);
    border: 1px solid var(--accent);
    border-radius: 5px;
    color: var(--accent);
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    text-shadow: 0 0 8px rgba(103, 200, 255, 0.5);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
    cursor: pointer;
    transition: background .15s;
  }
  .mobile-menu-btn .ico { font-size: 12px; line-height: 1; }
  body.menu-open .mobile-menu-btn { background: rgba(103, 200, 255, 0.28); }

  /* Backdrop dims + blurs the globe while the drawer is open. */
  .mobile-backdrop {
    position: fixed;
    inset: 0;
    z-index: 95;
    display: block;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    opacity: 0;
    pointer-events: none;
    transition: opacity .22s;
  }
  body.menu-open .mobile-backdrop { opacity: 1; pointer-events: auto; }

  /* The drop-down drawer itself.  Sits below the menu button,
     full-width minus 16 px of margin, scrollable if its contents are
     taller than the viewport. */
  .mobile-drawer {
    position: fixed;
    top: 44px;
    left: 8px;
    width: calc(100vw - 16px);
    max-height: calc(100vh - 56px);
    z-index: 96;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
    background: rgba(2, 6, 13, 0.95);
    border: 1px solid var(--line);
    border-radius: 10px;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: 0 12px 36px rgba(0, 0, 0, 0.6);
    transform: translateY(-12px);
    opacity: 0;
    pointer-events: none;
    transition: transform .22s ease-out, opacity .22s ease-out;
  }
  body.menu-open .mobile-drawer {
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
  }

  /* Panels are absolutely-positioned on desktop; reset everything when
     they're sitting inside the drawer so they flow as natural blocks. */
  .mobile-drawer > .left-nav,
  .mobile-drawer > .hud-tr,
  .mobile-drawer > .hud-tl,
  .mobile-drawer > .goc-shell,
  .mobile-drawer > .viz-shell,
  .mobile-drawer > .viz-search,
  .mobile-drawer > .right,
  .mobile-drawer > .header-right {
    position: static !important;
    top: auto !important;
    left: auto !important;
    right: auto !important;
    bottom: auto !important;
    width: 100% !important;
    max-width: none !important;
    max-height: none !important;
    margin: 0 !important;
    transform: none !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 8px !important;
    overflow: visible !important;
    background: transparent !important;
    border: 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }

  /* Each .panel inside a drawer gets full width and reasonable padding. */
  .mobile-drawer .panel {
    width: 100%;
    padding: 9px 11px;
  }
  /* Navigation launchers as a tidy 2-column grid instead of seven tall
     full-width rows — much less "ungainly".  Overrides the column-flex
     reset above (same specificity, later in source → wins). */
  .mobile-drawer > .left-nav {
    display: grid !important;
    grid-template-columns: 1fr 1fr !important;
    gap: 6px !important;
  }
  .mobile-drawer .btn-nav,
  .mobile-drawer .btn-back,
  .mobile-drawer .btn-nazar {
    width: 100%;
    justify-content: flex-start;
    padding: 7px 9px;
    font-size: 11px;
    letter-spacing: 0.08em;
    border-radius: 5px;
  }
  .mobile-drawer .btn-nav-icon { font-size: 13px; }
  /* The theme toggle (if present) spans both columns so it reads as a
     full-width control, not a stray half-button. */
  .mobile-drawer > .left-nav .btn-theme { grid-column: 1 / -1; }

  /* News ticker covers the bottom strip — keep it visible but slim. */
  .news-ticker { font-size: 10px; }

  /* Hide the in-header right section on table pages when its contents
     are already cloned into the drawer.  The page brand alone stays
     visible at the top so the user knows what page they're on. */
  body.menu-open .repo-header,
  body.menu-open .page-2d-header,
  body.menu-open .header-inner {
    /* No special override needed — the .right child has been moved out. */
  }

  /* Re-restore Takshashila logo z-index — without the legacy float
     pills there's no longer a need to drop below z=12 on mobile.  Keep
     it just under the drawer (z=96) so the drawer floats on top. */
  .top-logo { z-index: 50; }
}

/* =======================================================================
   Keep the globe visible behind / beside the open drawer.

   .has-globe is set by mobile-menu.js on any page with a #globe.  The
   default drawer dims the globe to black; on globe pages we never want
   that.  The main page (.page-main) gets a top sheet that leaves the
   lower strip of globe showing (and the globe shows through as you
   scroll the menu); the other globe pages re-centre the globe into the
   open area (handled in the slider-pages block further down).

   PHONE breakpoint — must match mobile-menu.js.
   ======================================================================= */
@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  /* Globe pages: backdrop never paints a black wall over the globe.  It
     stays click-to-close (pointer-events auto) on the main page; the
     slider-pages block flips it to pass-through where live interaction
     with the globe is wanted. */
  body.has-globe .mobile-backdrop {
    background: transparent !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }

  /* Main page — the menu is long (nav + full HUD), so make it a top
     sheet capped to 74 % height that scrolls internally.  The bottom
     quarter of the screen always shows the live globe, and the globe
     also glows faintly through the translucent sheet. */
  body.page-main .mobile-drawer {
    max-height: 74vh;
    background: rgba(2, 6, 13, 0.92);
  }
}

@media (max-width: 600px) {
  /* Inside-drawer tweaks only — geometry (transform / position) is
     handled by the 720-px drawer block above, not duplicated here. */
  .panel { padding: 8px 10px; }
  .clock .time { font-size: 22px; }
  .clock .label, .panel .label { font-size: 12px; }
  .count { font-size: 18px; }
  .list { max-height: 50vh; }
  .item .name { font-size: 13px; }
  .item .meta { font-size: 12px; }
  /* >=16px font-size on form fields suppresses iOS focus-zoom */
  .lookup-form input[type="number"],
  .repo-toolbar input[type="search"] { font-size: 16px; }
}

/* Respect iOS / Android notch & home-bar so fixed chrome doesn't sit
   under them.  Falls back to the plain 8 / 14 px values if the env()
   variables aren't supported. */
@supports (padding: env(safe-area-inset-top)) {
  .hud-tr     { top:    calc(86px + env(safe-area-inset-top));    right:  max(8px, env(safe-area-inset-right)); }
  .left-nav   { top:    calc(86px + env(safe-area-inset-top));    left:   max(8px, env(safe-area-inset-left)); }
  .btn-bl     { left:   max(8px,  env(safe-area-inset-left));   bottom: max(8px,  env(safe-area-inset-bottom)); }
  .news-ticker{ bottom: max(14px, env(safe-area-inset-bottom)); }
  @media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
    .news-ticker { bottom: calc(60px + env(safe-area-inset-bottom)); }
  }
}

/* =======================================================================
   Welcome flash popup (flash-popup.js, main page only)

   A red announcement card that fades in over a dim backdrop, sits
   centred on top of the globe for AUTO_CLOSE_MS, and fades out via
   the .closing class.  Inert before .shown is applied so the entrance
   animation can run from a known state.
   ======================================================================= */
.flash-backdrop {
  position: fixed;
  inset: 0;
  z-index: 199;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  opacity: 0;
  pointer-events: none;
  transition: opacity .28s ease-out;
}
.flash-backdrop.shown {
  opacity: 1;
  pointer-events: auto;
}

/* Colours pulled from the Takshashila lighthouse SVG:
       #5c1237  (deep maroon — primary)
       #4f112e  (darker maroon — bottom of gradient)
       #f19914  (warm orange — accent line)
       #fbc814  (warm yellow — border + title glow)
       #ffffff  (white — body text)
   Net effect: the popup reads as a Takshashila-branded panel rather
   than the previous siren red. */
.flash-popup {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 200;
  width: min(540px, calc(100vw - 32px));
  padding: 56px 56px 32px;     /* extra top room for the logo / × row */
  text-align: center;
  color: #ffffff;
  background:
    radial-gradient(ellipse at top left, rgba(251, 200, 20, 0.16) 0%, transparent 55%),
    linear-gradient(135deg, #5c1237 0%, #4f112e 100%);
  border: 2px solid #fbc814;
  border-radius: 12px;
  box-shadow:
    0 0 0 1px rgba(251, 200, 20, 0.18) inset,
    0 0 80px rgba(251, 200, 20, 0.32),
    0 18px 48px rgba(0, 0, 0, 0.7);
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, -50%) scale(0.88);
  transition: opacity .32s ease-out, transform .32s ease-out;
}
.flash-popup.shown {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, -50%) scale(1);
}
.flash-popup.closing {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.94);
}

/* Takshashila logo, anchored top-left — mirrors the × button on the
   right.  Already designed for dark backgrounds (white text, warm
   illuminated lighthouse), so no recolouring needed. */
.flash-logo {
  position: absolute;
  top: 12px;
  left: 14px;
  height: 36px;
  width: auto;
  filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.45));
  pointer-events: none;
}

.flash-close {
  position: absolute;
  top: 12px;
  right: 14px;
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.10);
  border: 1px solid rgba(251, 200, 20, 0.55);
  border-radius: 50%;
  color: #fbc814;
  font-family: var(--mono);
  font-size: 22px;
  line-height: 1;
  padding: 0;
  cursor: pointer;
  transition: background .15s, transform .15s, border-color .15s;
}
.flash-close:hover {
  background: rgba(251, 200, 20, 0.22);
  border-color: #fbc814;
  transform: scale(1.06);
}
.flash-close:active { transform: scale(0.96); }

.flash-eye {
  font-size: 44px;
  line-height: 1;
  margin-bottom: 14px;
  filter: drop-shadow(0 0 12px rgba(251, 200, 20, 0.55));
}
.flash-title {
  font-family: 'Orbitron', sans-serif;
  font-weight: 900;
  font-size: 40px;
  letter-spacing: 0.3em;
  margin: 0 0 10px;
  color: #ffffff;
  text-shadow:
    0 0 18px rgba(251, 200, 20, 0.6),
    0 0 4px rgba(255, 255, 255, 0.5);
}
.flash-subtitle {
  font-family: 'Orbitron', sans-serif;
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: #f4ec07;
  opacity: 0.95;
  text-shadow: 0 0 10px rgba(251, 200, 20, 0.45);
}

@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  .flash-popup {
    padding: 50px 28px 22px;
    width: calc(100vw - 24px);
  }
  .flash-logo    { height: 28px; top: 10px; left: 12px; }
  .flash-close   { top: 10px; right: 12px; width: 28px; height: 28px; font-size: 18px; }
  .flash-eye     { font-size: 32px; margin-bottom: 10px; }
  .flash-title   { font-size: 26px; letter-spacing: 0.20em; }
  .flash-subtitle{ font-size: 10px; letter-spacing: 0.18em; }
}

/* =======================================================================
   About / landing page (about.html)
   ======================================================================= */
body.page-about {
  overflow-y: auto;
  background: var(--bg);
  -webkit-overflow-scrolling: touch;
}
body.page-about #globe { display: none; }

.about-shell {
  max-width: 880px;
  margin: 0 auto;
  padding: 60px 28px 80px;
  color: var(--text);
  font-family: var(--mono);
  font-size: 14px;
  line-height: 1.6;
}

/* --- Hero ----------------------------------------------------------- */
.about-hero {
  text-align: center;
  margin-bottom: 70px;
  padding-bottom: 40px;
  border-bottom: 1px solid var(--line);
}
.about-brand {
  font-family: 'Orbitron', sans-serif;
  font-weight: 900;
  font-size: 56px;
  letter-spacing: 0.22em;
  margin: 0 0 8px;
  color: var(--accent);
  text-shadow: 0 0 28px rgba(103, 200, 255, 0.6);
}
.about-tagline {
  font-size: 12px;
  letter-spacing: 0.18em;
  color: var(--dim);
  text-transform: uppercase;
  margin: 0 0 14px;
  line-height: 1.4;
}
.about-caveat {
  font-family: 'Caveat', cursive;
  font-size: 30px;
  font-weight: 700;
  color: var(--accent2);
  margin: 0 0 26px;
  text-shadow: 0 0 12px rgba(255, 107, 107, 0.35);
}
.about-blurb {
  max-width: 620px;
  margin: 0 auto 30px;
  font-size: 14px;
  line-height: 1.65;
  color: var(--text);
}
.about-blurb a, .about-section a, .about-footer a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-color: rgba(103, 200, 255, 0.35);
  text-underline-offset: 3px;
}
.about-blurb a:hover, .about-section a:hover, .about-footer a:hover {
  text-decoration-color: var(--accent);
}

.about-cta-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 12px;
}
.about-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 24px;
  border-radius: 5px;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background .15s, transform .15s, border-color .15s;
}
.about-cta.primary {
  background: rgba(103, 232, 164, 0.18);
  border: 1px solid var(--green);
  color: var(--green);
  text-shadow: 0 0 8px rgba(103, 232, 164, 0.55);
}
.about-cta.primary:hover {
  background: rgba(103, 232, 164, 0.30);
  transform: translateY(-1px);
}
.about-cta.secondary {
  background: rgba(103, 200, 255, 0.10);
  border: 1px solid var(--accent);
  color: var(--accent);
}
.about-cta.secondary:hover {
  background: rgba(103, 200, 255, 0.20);
  transform: translateY(-1px);
}

/* --- Section --------------------------------------------------------- */
.about-section { margin-bottom: 60px; }
.about-section h2 {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: 19px;
  letter-spacing: 0.2em;
  color: var(--accent);
  text-transform: uppercase;
  margin: 0 0 22px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.about-section h3 {
  font-family: 'Orbitron', sans-serif;
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 0.18em;
  color: var(--text);
  text-transform: uppercase;
  margin: 28px 0 10px;
}
.about-section p { margin: 0 0 14px; }
.about-section ul { padding-left: 24px; margin: 0 0 18px; }
.about-section li { margin-bottom: 8px; }
.about-section code {
  font-family: var(--mono);
  font-size: 12px;
  padding: 1px 6px;
  background: rgba(2, 6, 13, 0.65);
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--accent);
}
.about-section em {
  font-style: italic;
  color: var(--text);
}
.about-section strong {
  color: var(--text);
  font-weight: 700;
}

/* --- Capability grid (section 2) ------------------------------------ */
.cap-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px;
  margin: 20px 0 16px;
}
.cap-card {
  padding: 18px 18px 16px;
  background: rgba(2, 6, 13, 0.55);
  border: 1px solid var(--line);
  border-radius: 6px;
}
.cap-ico {
  font-size: 28px;
  line-height: 1;
  margin-bottom: 10px;
  filter: drop-shadow(0 0 8px rgba(103, 200, 255, 0.45));
}
.cap-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 12px;
  letter-spacing: 0.16em;
  color: var(--accent);
  text-transform: uppercase;
  margin-bottom: 8px;
}
.cap-desc {
  font-size: 12.5px;
  color: var(--dim);
  line-height: 1.55;
}

/* --- Feature bullet list (section 3) -------------------------------- */
.feature-list {
  list-style: none !important;
  padding: 0 !important;
}
.feature-list li {
  padding: 12px 16px;
  margin-bottom: 10px;
  background: rgba(103, 200, 255, 0.05);
  border-left: 3px solid var(--accent);
  border-radius: 0 4px 4px 0;
  font-size: 13.5px;
  line-height: 1.55;
}

/* --- Page card grid (section 4) ------------------------------------- */
.page-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 14px;
  margin: 22px 0 18px;
}
.page-card {
  display: block;
  padding: 18px 20px;
  background: rgba(2, 6, 13, 0.55);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  transition: all .15s;
}
.page-card:hover {
  border-color: var(--accent);
  background: rgba(103, 200, 255, 0.08);
  text-decoration: none;
  transform: translateY(-2px);
}
.page-card .ico {
  font-size: 28px;
  line-height: 1;
  color: var(--accent);
  margin-bottom: 10px;
  text-shadow: 0 0 10px rgba(103, 200, 255, 0.55);
}
.page-card .name {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.18em;
  color: var(--text);
  text-transform: uppercase;
  margin-bottom: 8px;
}
.page-card .desc {
  font-size: 12.5px;
  color: var(--dim);
  line-height: 1.55;
}

/* --- Footer --------------------------------------------------------- */
.about-footer {
  margin-top: 60px;
  padding-top: 30px;
  border-top: 1px solid var(--line);
  text-align: center;
  color: var(--dim);
  font-size: 12.5px;
  line-height: 1.6;
}
.about-footer p { margin: 0 0 10px; }
.about-footer .about-cta-row { margin-top: 24px; }

/* --- Mobile -------------------------------------------------------- */
@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  .about-shell  { padding: 70px 14px 50px; }
  .about-brand  { font-size: 38px; letter-spacing: 0.18em; }
  .about-tagline{ font-size: 10px; }
  .about-caveat { font-size: 24px; }
  .about-blurb  { font-size: 13.5px; }
  .about-section h2 { font-size: 15px; }
  .about-section h3 { font-size: 12px; }
  .about-section, .about-hero { margin-bottom: 40px; }
  .cap-grid, .page-grid { grid-template-columns: 1fr; gap: 10px; }
  .about-cta { padding: 10px 18px; font-size: 12px; }
}

/* --- 3-D Visualiser launcher icon tint (.left-nav main page).
   Keeps the hex glyph distinct from the green ◯ Globe icon. */
.btn-viz3d .btn-nav-icon {
  color: #d77eff;
  text-shadow: 0 0 8px rgba(215, 126, 255, 0.55);
}
body.light .btn-viz3d .btn-nav-icon { color: #6a1b9a; text-shadow: none; }

/* --- About / Help launcher — warm-gold tint so newcomers spot it as
   the entry point, distinct from the green / cyan / purple of the
   data-viz pages. */
.btn-about .btn-nav-icon {
  color: #ffd166;
  text-shadow: 0 0 8px rgba(255, 209, 102, 0.55);
  font-size: 17px;
}
body.light .btn-about .btn-nav-icon { color: #b87333; text-shadow: none; }

/* --- SATs-by-OPs launcher — warm orange to suggest categorisation /
   aggregation, distinct from the 3D Visualiser's purple hex. */
.btn-sbo .btn-nav-icon {
  color: #ff9966;
  text-shadow: 0 0 8px rgba(255, 153, 102, 0.55);
}
body.light .btn-sbo .btn-nav-icon { color: #d35400; text-shadow: none; }

/* --- "NAZAR" back-to-home button anchored top-left of the dedicated
   secondary pages (3-D Visualiser, Sats-by-OPs, Game of Cones).
   Sits in the same visual register as the top-right Takshashila logo
   so the two pieces of brand chrome bookend the topbar.  On mobile
   it tucks below the ☰ MENU button (which holds top:8 left:8). */
.top-nazar-btn {
  position: fixed;
  top: 14px;
  left: 14px;
  z-index: 60;                /* over .left-nav (10) and .top-logo (50) */
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  background: rgba(2, 6, 13, 0.85);
  border: 1px solid var(--accent);
  border-radius: 6px;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  text-shadow: 0 0 10px rgba(103, 200, 255, 0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
  transition: background .15s, transform .15s, border-color .15s;
}
.top-nazar-btn:hover {
  background: rgba(103, 200, 255, 0.22);
  border-color: var(--accent);
  transform: scale(1.04);
  text-decoration: none;
}
.top-nazar-btn:active { transform: scale(0.98); }
.top-nazar-btn .ico {
  font-size: 16px;
  line-height: 1;
  color: var(--green);
  text-shadow: 0 0 8px rgba(103, 232, 164, 0.55);
}
@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  /* Stack neatly below the ☰ MENU drawer-toggle (top:8 left:8, z=100)
     so the two top-left controls don't overlap. */
  .top-nazar-btn {
    top: 52px;
    left: 8px;
    padding: 6px 12px;
    font-size: 11px;
    letter-spacing: 0.18em;
  }
  .top-nazar-btn .ico { font-size: 13px; }
}

/* Desktop-only: clear the topbar brand text out from under the fixed
   NAZAR button (~130 px wide at left:14).  Scoped to min-width so the
   720-px centered-topbar rule keeps winning on mobile, where the
   button sits below the ☰ MENU toggle instead. */
@media (min-width: 721px) {
  body.page-viz3d  .topbar,
  body.page-sbo    .topbar,
  body.page-goc    .topbar,
  body.page-debris .topbar { padding-left: 165px; }
}

/* --- Switch 2D-3D view-mode toggle on the main page HUD.  Full-width
   row button; the trailing state chip flips between 3D and 2D. */
.btn-viewmode {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 7px 10px;
  background: rgba(103, 200, 255, 0.10);
  border: 1px solid var(--line);
  border-radius: 4px;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .15s, border-color .15s;
}
.btn-viewmode:hover {
  background: rgba(103, 200, 255, 0.22);
  border-color: var(--accent);
}
.btn-viewmode-icon {
  font-size: 15px;
  line-height: 1;
  color: var(--green);
  text-shadow: 0 0 8px rgba(103, 232, 164, 0.5);
}
.btn-viewmode-label { flex: 1; text-align: left; }
.btn-viewmode-state {
  padding: 1px 8px;
  background: rgba(103, 232, 164, 0.16);
  border: 1px solid var(--green);
  border-radius: 3px;
  color: var(--green);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  font-variant-numeric: tabular-nums;
}

/* --- Observer-city dropdown on the main page HUD.  Matches the
   lookup-form input chrome so the panel reads as one family. */
.observer-select {
  background: rgba(0, 0, 0, 0.32);
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 13px;
  padding: 4px 8px;
  outline: none;
  cursor: pointer;
  max-width: 60%;
}
.observer-select:hover,
.observer-select:focus { border-color: var(--accent); }
.observer-select option { background: var(--bg); color: var(--text); }

/* --- Sats-by-OPs page: offset the globe canvas to the right of the
   .sbo-shell panel so the Earth sits visually centred in the
   *remaining* viewport, not under the panel.  Panel is 320 px wide
   at left:14, so it ends at x=334 — leave a 14 px gap and start the
   globe at 348.  On mobile the panel collapses into the drawer and
   we want full-width again. */
body.page-sbo #globe {
  position: fixed;
  top: 0;
  left: 348px;
  right: 0;
  bottom: 0;
  width: auto;
  height: auto;
}
/* On phones the panel collapses into the drawer, so the globe reclaims
   the whole viewport and sits centred.  PHONE breakpoint (incl. landscape
   phones) — must match mobile-menu.js. */
@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  body.page-sbo #globe { left: 0; right: 0; width: 100%; }
}

/* --- NAZAR back-button — primary CTA style used on china-sat-repo
   pages and any other page where the muted .btn-back doesn't read
   clearly enough as "go home".  Cyan-accent background + border so it
   looks like a navigation primary, not a generic back-arrow link. */
.btn-nazar {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  background: rgba(103, 200, 255, 0.16);
  border: 1px solid var(--accent);
  border-radius: 4px;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  text-shadow: 0 0 8px rgba(103, 200, 255, 0.45);
  transition: background .15s, transform .15s, border-color .15s;
}
.btn-nazar:hover {
  background: rgba(103, 200, 255, 0.28);
  transform: translateY(-1px);
  text-decoration: none;
}
body.light .btn-nazar {
  background: rgba(21, 101, 192, 0.10);
  border-color: var(--accent);
  color: var(--accent);
  text-shadow: none;
}
body.light .btn-nazar:hover { background: rgba(21, 101, 192, 0.18); }

/* --- Takshashila Institution logo — top-right corner on every page.
   Fixed position with z-50 so it floats above all page chrome
   (topbar, hud-tr, repo-header, page-2d-header, etc.).  Clicking
   opens https://takshashila.org.in/ in a new tab.

   The logo sits inside a thin dark panel so it reads cleanly whether
   the canvas behind is the bright Blue-Marble atmosphere, the
   night-sky stars, a light-theme table page, or anything else. */
/* Just the mark, no panel/border — it sits at the top-right and scrolls
   up with the page (position: absolute, not fixed) so it never obstructs
   content once you scroll down. */
.top-logo {
  position: absolute;
  top: 10px;
  right: 14px;
  z-index: 50;
  display: block;
  text-decoration: none;
  padding: 0;
  transition: opacity .15s, transform .15s;
}
.top-logo:hover  { transform: scale(1.04); }
.top-logo:active { transform: scale(0.98); }
.top-logo img {
  height: 52px;
  width: auto;
  display: block;
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.55));
}
/* Space-Policy credit that hugs the lighthouse logo (mark is position:absolute,
   top:10 right:14, ~79 px wide).  mobile-menu.js injects the two-line markup.
   Default: two compact lines tucked directly BENEATH the mark, right-aligned to
   it so it reads as part of the logo.  position:absolute (like .top-logo) so it
   scrolls up with the mark on pages whose body scrolls.  Only the link is
   clickable.  Per-page overrides move it BESIDE the logo where something sits in
   the space right beneath it. */
.logo-credit {
  position: absolute;
  top: 66px;
  right: 14px;
  z-index: 55;
  text-align: right;
  white-space: nowrap;
  font-family: var(--mono);
  font-size: 9.5px;
  line-height: 1.4;
  letter-spacing: 0.02em;
  color: var(--dim);
  pointer-events: none;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
.logo-credit a {
  pointer-events: auto;
  color: var(--accent);
  text-decoration: none;
}
.logo-credit a:hover { text-decoration: underline; }
/* Pages with a top-right HUD (index, orbits) or a results card (overpass) place
   a panel directly below the logo — too tight for two lines beneath it.  Sit the
   credit BESIDE the mark instead, in the open band to its left (between the
   header text and the logo). */
body:has(.hud-tr)  .logo-credit,
body.page-overpass .logo-credit {
  top: 22px;
  right: 100px;
}
/* Repo tables (sat-stats, chinrepo): a toolbar sits right under the logo.  Keep
   the credit beneath the mark, give it a small chip backing (it overlays the
   dense header/table), and nudge the toolbar down so the two never touch. */
body.page-stats .logo-credit,
body.page-repo  .logo-credit {
  top: 60px;
  font-size: 9px;
  text-shadow: none;
  color: var(--dim);
  background: rgba(2, 6, 13, 0.9);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 3px 8px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
body.page-stats .repo-toolbar,
body.page-repo  .repo-toolbar { margin-top: 18px; }
/* Full-width headers (chinrepo, sat-stats, 2d-views) pack content
   right-of-flex.  Reserve ~110 px on the right so the (now panel-less)
   logo mark sits over empty space, not on top of the header buttons. */
body.page-repo  .repo-header,
body.page-stats .repo-header,
body.page-2d    .page-2d-header { padding-right: 110px; }

@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  .top-logo { padding: 0; z-index: 50; }
  .top-logo img { height: 34px; }
  /* On phones the logo shrinks to 34 px; sit the credit tight beneath it
     everywhere (the beside-slot used on index only exists at desktop width). */
  .logo-credit { top: 46px; right: 10px; font-size: 8px; line-height: 1.3; max-width: 155px; }
  body.page-main  .logo-credit { top: 46px; right: 10px; }
  body.page-stats .logo-credit,
  body.page-repo  .logo-credit { top: 44px; font-size: 8px; }
  body.page-repo  .repo-header,
  body.page-stats .repo-header,
  body.page-2d    .page-2d-header { padding-right: 85px; }
}

/* --- Cursor-tracking tooltip on the 3-D Visualiser page.
   pointer-events:none so it never absorbs the mousemove events that drive
   itself; raycasting lives in viz3d.js. */
.sat-tip-3d {
  position: fixed;
  pointer-events: none;
  z-index: 100;
  max-width: 300px;
  background: rgba(2, 6, 13, 0.94);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 10px 12px;
  font-family: var(--mono);
  font-size: 13.5px;
  color: var(--text);
  line-height: 1.55;
  letter-spacing: 0.03em;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.sat-tip-3d b {
  display: block;
  margin-bottom: 4px;
  color: var(--accent);
  font-size: 14.5px;
  letter-spacing: 0.05em;
}
.sat-tip-3d .cls {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 2px;
  font-size: 11.5px;
  letter-spacing: 0.16em;
  margin: 2px 0 4px;
}
.sat-tip-3d strong { color: var(--accent); font-weight: normal; font-variant-numeric: tabular-nums; }
.sat-tip-3d .muted { color: var(--dim); }

/* =======================================================================
   Secondary globe pages — Orbit Visualisation, Game of Cones, 3-D
   Visualiser, SATs-by-OPs (every globe page except the main one).

   These pages have a single centred globe (some with live slider /
   cone controls whose whole point is watching the globe react as you
   drag).  When their drawer opens it must NOT cover the globe: the
   backdrop goes pass-through, the drawer shrinks to a side panel
   (landscape) or bottom sheet (portrait), AND the globe is shifted so
   its whole sphere re-centres in the open area beside / above the
   drawer instead of hiding behind it.  The shift is purely visual — the
   pages' own pointer maths read getBoundingClientRect, which already
   accounts for the transform, so clicking / dragging stays accurate.

   PHONE breakpoint — must match mobile-menu.js.
   ======================================================================= */
@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  /* Globe fills the viewport; the recentre transform animates smoothly. */
  body.has-globe:not(.page-main) #globe {
    position: fixed;
    inset: 0;
    transition: transform .25s ease;
  }

  /* Pass-through transparent backdrop → globe stays visible AND
     draggable while the controls are open.  The ☰ / ✕ button closes. */
  body.has-globe:not(.page-main) .mobile-backdrop {
    background: transparent !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    pointer-events: none !important;
  }

  /* Landscape — drawer is a translucent left side panel; the globe
     slides right by half the panel width so the sphere sits centred in
     the clear area on the right. */
  body.has-globe:not(.page-main) .mobile-drawer {
    width: min(330px, 46vw);
    right: auto;
    background: rgba(2, 6, 13, 0.82);
  }
  body.has-globe:not(.page-main).menu-open #globe {
    transform: translateX(calc(min(330px, 46vw) / 2));
  }

  /* Portrait — drawer is a bottom sheet; the globe slides up so the
     sphere centres in the clear area above it. */
  @media (orientation: portrait) {
    body.has-globe:not(.page-main) .mobile-drawer {
      top: auto;
      bottom: 8px;
      left: 8px;
      width: calc(100vw - 16px);
      max-height: 46vh;
    }
    body.has-globe:not(.page-main).menu-open #globe {
      transform: translateY(-23vh);
    }
  }
}

/* =======================================================================
   Rotate-to-landscape prompt (mobile-menu.js, globe pages, portrait).
   ======================================================================= */
.rotate-prompt {
  position: fixed;
  inset: 0;
  z-index: 250;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 32px;
  text-align: center;
  background: rgba(2, 6, 13, 0.96);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.rotate-prompt .rotate-icon {
  font-size: 56px;
  line-height: 1;
  color: var(--accent);
  text-shadow: 0 0 18px rgba(103, 200, 255, 0.6);
  animation: rotate-hint 2.4s ease-in-out infinite;
}
@keyframes rotate-hint {
  0%, 60%   { transform: rotate(0deg); }
  80%, 100% { transform: rotate(90deg); }
}
.rotate-prompt .rotate-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text);
}
.rotate-prompt .rotate-sub {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--dim);
  max-width: 280px;
  line-height: 1.5;
}
.rotate-prompt .rotate-dismiss {
  margin-top: 8px;
  padding: 8px 16px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 5px;
  color: var(--dim);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  cursor: pointer;
}
.rotate-prompt .rotate-dismiss:hover { border-color: var(--accent); color: var(--accent); }

/* --- SAT-STATS launcher on the main-page tracking-summary panel.
   Sits below the count + as-of date, hugs the panel chrome, and styles
   itself as a CTA bar with a chevron pointing at the new page. */
.btn-statsline {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding: 7px 10px;
  background: linear-gradient(90deg, rgba(103, 200, 255, 0.10), rgba(103, 232, 164, 0.05));
  border: 1px solid var(--line);
  border-radius: 4px;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s, border-color .15s, transform .15s;
}
.btn-statsline:hover {
  border-color: var(--accent);
  background: linear-gradient(90deg, rgba(103, 200, 255, 0.20), rgba(103, 232, 164, 0.10));
  transform: translateY(-1px);
  text-decoration: none;
}
.btn-statsline-icon { color: var(--green); font-size: 16px; line-height: 1; }
.btn-statsline-label { flex: 1; }
.btn-statsline-arrow {
  color: var(--accent);
  font-size: 18px;
  transition: transform .15s;
}
.btn-statsline:hover .btn-statsline-arrow { transform: translateX(2px); }

/* --- Sat-Stats page (cumulative catalogue + graphs view) ----------------
   Inherits most chrome from .repo-* but adds a tab strip, the photo
   thumbnail column, country-cell flag composition, and the charts grid. */
body.page-stats { overflow: auto; }
body.page-stats #globe { display: none; }
.stats-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background:
    radial-gradient(ellipse at top, rgba(103, 200, 255, 0.06), transparent 60%),
    var(--bg);
}
body.page-stats .repo-header .brand {
  color: var(--accent);
  text-shadow: 0 0 12px rgba(103, 200, 255, 0.55);
}
.stats-tabs {
  display: flex;
  gap: 8px;
  padding: 10px 20px 0;
  border-bottom: 1px solid var(--line);
}
.stats-tabs button {
  background: rgba(103, 200, 255, 0.05);
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: 4px 4px 0 0;
  color: var(--dim);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 8px 18px;
  cursor: pointer;
  position: relative;
  top: 1px;
}
.stats-tabs button.active {
  background: var(--bg);
  border-color: var(--accent);
  color: var(--accent);
}
.stats-view { flex: 1; display: flex; flex-direction: column; }
.stats-table-wrap {
  flex: 1;
  overflow: auto;
  padding: 0 20px 20px;
}
.stats-table { width: 100%; border-collapse: collapse; font-size: 11px; }
.stats-table thead th {
  position: sticky;
  top: 0;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  color: var(--dim);
  font-weight: normal;
  text-align: left;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-size: 10px;
  padding: 10px 8px;
  white-space: nowrap;
}
.stats-table tbody td {
  padding: 8px;
  border-bottom: 1px solid rgba(110, 200, 255, 0.06);
  color: var(--text);
  vertical-align: middle;
}
.stats-table tbody tr:hover td { background: rgba(103, 200, 255, 0.05); }
.stats-table .col-photo { width: 60px; padding: 6px 8px; }
.stats-table .col-name { color: var(--accent); letter-spacing: 0.03em; min-width: 180px; }
.stats-table .col-country { min-width: 160px; }
.stats-table .col-status { width: 90px; text-align: center; }

/* Photo column composition: link wraps the <img> so clicks open
   Wikipedia in a new tab.  Placeholder card for "loading"/"no series". */
.photo-thumb {
  width: 48px;
  height: 36px;
  object-fit: cover;
  border-radius: 3px;
  border: 1px solid var(--line);
  background: rgba(0, 0, 0, 0.4);
}
.photo-link { display: inline-block; line-height: 0; }
.photo-link:hover .photo-thumb { border-color: var(--accent); }
.photo-ph {
  width: 48px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed var(--line);
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.25);
  color: var(--dim);
  font-size: 16px;
}

/* Country cell: flag + name, side-by-side.  Globe glyph for multinational
   / unknown owners.  flagcdn.com PNGs are 24×18 — match that aspect. */
.flag {
  width: 22px;
  height: 16px;
  vertical-align: middle;
  margin-right: 6px;
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5);
}
.flag-glyph {
  display: inline-block;
  width: 22px;
  height: 16px;
  vertical-align: middle;
  margin-right: 6px;
  text-align: center;
  font-size: 13px;
  line-height: 16px;
}
.ctry-name { color: var(--text); font-size: 11px; display: inline-block; vertical-align: middle; }
.ctry-name.muted { color: var(--dim); }
/* Two-line variant used by the Launch Country column: bold country
   on top, dim launch-site name below.  Both lines wrap inside the
   same cell so the table layout doesn't shift. */
.ctry-name .ctry-main { display: block; line-height: 1.3; }
.ctry-name .site-name {
  display: block;
  margin-top: 1px;
  color: var(--dim);
  font-size: 10px;
  letter-spacing: 0.02em;
  line-height: 1.25;
}

/* Filter dropdown styled as a column header — looks like a thead cell
   until you hover it, then surfaces as an interactive control. */
.col-filter {
  background: transparent;
  border: 1px solid transparent;
  border-radius: 3px;
  color: var(--dim);
  font-family: var(--mono);
  font-weight: normal;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 4px 24px 4px 6px;
  cursor: pointer;
  outline: none;
  max-width: 100%;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  /* Hand-built chevron in the right padding via background-image so
     the dropdown reads as filterable without relying on the native
     <select> arrow (which varies wildly across browsers). */
  background-image: linear-gradient(45deg, transparent 50%, var(--dim) 50%),
                    linear-gradient(135deg, var(--dim) 50%, transparent 50%);
  background-position: calc(100% - 12px) calc(50% - 1px),
                       calc(100% - 7px)  calc(50% - 1px);
  background-size: 5px 5px;
  background-repeat: no-repeat;
}
.col-filter:hover,
.col-filter:focus {
  border-color: var(--accent);
  background-color: rgba(103, 200, 255, 0.10);
  color: var(--accent);
  background-image: linear-gradient(45deg, transparent 50%, var(--accent) 50%),
                    linear-gradient(135deg, var(--accent) 50%, transparent 50%);
  background-position: calc(100% - 12px) calc(50% - 1px),
                       calc(100% - 7px)  calc(50% - 1px);
  background-size: 5px 5px;
  background-repeat: no-repeat;
}
.col-filter option { background: var(--bg); color: var(--text); }

/* Tiny ACTIVE / DECAYED badge in the rightmost column. */
.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 9px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.badge-active { background: rgba(103, 232, 164, 0.18); color: var(--green); }
.badge-decay  { background: rgba(255, 107, 107, 0.18); color: var(--accent2); }

/* Inline pagination buttons inside the toolbar pill. */
.pill.nowrap { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.page-btn {
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  width: 22px;
  height: 22px;
  cursor: pointer;
  padding: 0;
  line-height: 1;
}
.page-btn:hover { border-color: var(--accent); background: rgba(103, 200, 255, 0.12); }

/* Graphs view: responsive grid of cards.  Each card hosts a Chart.js
   canvas inside a fixed-height box so the canvases don't stretch
   unboundedly. */
.charts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 16px;
  padding: 20px;
}
.chart-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 16px 18px 12px;
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, .35) inset,
    0 6px 24px rgba(0, 0, 0, .35);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.chart-card.chart-wide { grid-column: 1 / -1; }
.chart-card h3 {
  margin: 0 0 4px;
  font-family: 'Orbitron', sans-serif;
  font-size: 14px;
  letter-spacing: 0.14em;
  color: var(--accent);
  text-shadow: 0 0 8px rgba(103, 200, 255, 0.35);
}
.chart-card .chart-sub {
  margin: 0 0 12px;
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 0.04em;
}
.chart-card .chart-sub code {
  font-size: 10px;
  background: rgba(103, 200, 255, 0.10);
  padding: 1px 5px;
  border-radius: 2px;
}
.chart-box {
  position: relative;
  height: 280px;
}
.chart-card.chart-wide .chart-box { height: 240px; }

@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  .stats-tabs { padding: 8px 12px 0; }
  .stats-tabs button { padding: 6px 12px; font-size: 10px; }
  .stats-table-wrap { padding: 0 12px 12px; }
  .stats-table .col-name { min-width: 140px; }
  .stats-table .col-country { min-width: 120px; }
  .charts-grid { grid-template-columns: 1fr; padding: 12px; gap: 12px; }
  .chart-card { padding: 12px; }
  .chart-box { height: 240px; }
}

/* --- ChinRepo page (Chinese-payload repository view) -------------------- */
body.page-repo { overflow: auto; }
body.page-repo #globe { display: none; }

.repo-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background:
    radial-gradient(ellipse at top, rgba(255, 107, 107, 0.05), transparent 60%),
    var(--bg);
}
.repo-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
  gap: 10px;
}
.repo-header .brand {
  font-size: 13px;
  letter-spacing: 0.22em;
  color: var(--accent2);
  text-shadow: 0 0 12px rgba(255, 107, 107, 0.55);
}
.repo-header .right {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 10px;
  color: var(--dim);
  letter-spacing: 0.1em;
}
.repo-toolbar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 0.08em;
}
.repo-toolbar input[type="search"] {
  flex: 1;
  min-width: 200px;
  max-width: 360px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 4px;
  color: var(--text);
  font-family: var(--mono);
  font-size: 11px;
  padding: 7px 10px;
  letter-spacing: 0.04em;
  outline: none;
}
.repo-toolbar input[type="search"]:focus { border-color: var(--accent); }
.repo-toolbar .pill {
  display: inline-block;
  padding: 3px 8px;
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  font-size: 10px;
}
.repo-toolbar .pill strong { color: var(--accent2); font-weight: normal; }
.repo-table-wrap {
  flex: 1;
  overflow: auto;
  padding: 0 20px 20px;
}
table.repo-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.repo-table thead th {
  position: sticky;
  top: 0;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  color: var(--dim);
  font-weight: normal;
  text-align: left;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-size: 10px;
  padding: 10px 8px;
  white-space: nowrap;
}
.repo-table tbody td {
  padding: 7px 8px;
  border-bottom: 1px solid rgba(110, 200, 255, 0.06);
  color: var(--text);
  vertical-align: top;
}
.repo-table tbody tr:hover td { background: rgba(255, 107, 107, 0.04); }
.repo-table .col-name { color: var(--accent); letter-spacing: 0.03em; }
.repo-table .col-num { text-align: right; font-variant-numeric: tabular-nums; }
.repo-table .muted { color: var(--dim); }

/* Mobile pass for ChinRepo — keep the table readable on narrow phones
   without trying to shoehorn 9 wide columns; horizontal scroll inside
   .repo-table-wrap takes over.  Header and toolbar wrap to two/three
   rows so the search field and pills stay full-width and tappable. */
@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  .repo-header   { padding: 10px 12px; gap: 8px; }
  .repo-header .brand { font-size: 11px; letter-spacing: 0.14em; }
  .repo-toolbar  { padding: 10px 12px; gap: 10px; }
  .repo-toolbar input[type="search"] { flex: 1 1 100%; min-width: 0; max-width: none; font-size: 16px; }
  .repo-table-wrap { padding: 0 12px 12px; -webkit-overflow-scrolling: touch; }
  .repo-table thead th { font-size: 9px; padding: 8px 6px; }
  .repo-table tbody td { padding: 6px; }
  .btn-back { padding: 5px 10px; font-size: 10px; }
}
@media (max-width: 480px) {
  .repo-header .right { flex-wrap: wrap; gap: 6px; }
  .repo-table { font-size: 10px; }
}

/* Light-mode override for the ChinRepo page — toggled via the theme button.
   Re-defines the CSS custom properties scoped to body.page-repo.light, so
   every existing rule that reads var(--bg)/var(--text)/etc picks up the
   light palette automatically. */
body.page-repo.light {
  --bg:       #f4f6f9;
  --panel:    rgba(255, 255, 255, 0.92);
  --line:     #cfd8e3;
  --text:     #1a2b40;
  --dim:      #5a6a7d;
  --accent:   #1565c0;
  --accent2:  #c1392b;
  --green:    #2e7d4f;
  background: var(--bg);
  color: var(--text);
}
body.page-repo.light .repo-header .brand { text-shadow: none; }
body.page-repo.light .repo-shell {
  background:
    radial-gradient(ellipse at top, rgba(193, 57, 43, 0.06), transparent 60%),
    var(--bg);
}
body.page-repo.light .repo-table tbody tr:hover td { background: rgba(193, 57, 43, 0.05); }
body.page-repo.light .repo-toolbar input[type="search"] {
  background: #ffffff;
  border-color: var(--line);
}
body.page-repo.light .repo-table tbody td {
  border-bottom-color: rgba(26, 43, 64, 0.08);
}
body.page-repo.light #repo-status::before { text-shadow: none; }
body.page-repo.light .btn-back {
  background: rgba(255, 255, 255, 0.7);
}

/* --- 2-D views page (light theme) --------------------------------------- */
/* Override the dark-theme custom properties for descendants of body.page-2d.
   Every existing rule that uses var(--bg)/var(--accent)/etc picks up the
   light palette automatically. */
body.page-2d {
  --bg:       #eef2f6;
  --panel:    rgba(255, 255, 255, 0.92);
  --line:     #cfd8e3;
  --text:     #1a2b40;
  --dim:      #5a6a7d;
  --accent:   #1565c0;
  --accent2:  #c62828;
  --green:    #2e7d4f;
  background: var(--bg);
  color: var(--text);
  overflow: auto;
}
body.page-2d #globe { display: none; }

/* Top bar reads black, in tune with the dark map below it (rather than the
   light page palette). */
body.page-2d .page-2d-shell { background: #02080f; }
body.page-2d .page-2d-header {
  background: #02080f;
  border-bottom: 1px solid #16324a;
}
body.page-2d .page-2d-header .brand { color: #6fb8ff; text-shadow: 0 0 12px rgba(103, 200, 255, 0.35); }
body.page-2d .page-2d-header .right { color: #8aa0b5; }
body.page-2d .page-2d-header .btn-back { color: #7fc0ff; border-color: #1d3a52; }
body.page-2d .page-2d-header .btn-back:hover { border-color: #6fb8ff; }

/* Realistic-Earth map cell: deep ocean letterbox + NASA Blue Marble +
   bathymetry raster as the chart basemap (Plate-Carrée projection, so it
   aligns with amCharts' geoEquirectangular polygons). */
body.page-2d .map-cell {
  background: #02080f;
  /* Equirectangular world is 360°×180° = 2:1.  Forcing the cell aspect to
     match means amCharts' aspect-preserving fit and the CSS basemap stretch
     produce the same rectangle, so country strokes line up with coastlines. */
  aspect-ratio: 2 / 1;
  align-self: center;
  justify-self: center;
  width: 100%;
  max-width: 100%;
  max-height: 100%;
  min-height: 0;
  margin: 0 auto;
}
body.page-2d .maps-grid {
  align-items: center;
  justify-items: center;
  background: #02080f;
}

/* 2-D map + companion 3-D globe, side by side.  The map keeps its 2:1 shape
   and shrinks to leave room; the globe takes ~1/6 of the width on the right. */
body.page-2d .map-row {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 0;
  padding: 10px 14px;
  background: #02080f;
}
body.page-2d .map-area {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
body.page-2d .globe-cell {
  flex: 0 0 clamp(150px, 16vw, 240px);
  align-self: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 14px;
}
body.page-2d .globe-unit {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}
body.page-2d .mini-globe {
  /* JS sizes both to a square that fits the column; this is the first-paint
     fallback before that runs. */
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 0 26px rgba(80, 150, 230, 0.28), inset 0 0 0 1px rgba(120, 170, 220, 0.25);
}
/* Globe 2 is a rounded square, not a circle, so an elliptical orbit can use the
   corner space and its far apogee isn't clipped away. */
body.page-2d #mini-globe2 { border-radius: 14px; }
/* Brighten the rendered globes to match the flat 2-D Blue-Marble map. */
body.page-2d .mini-globe canvas {
  filter: brightness(1.22) saturate(1.1) contrast(1.02);
}
body.page-2d .globe-cap {
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #7fa8cf;
  text-align: center;
}
/* Globe 2 keeps its Earth in the little column slot; for a very elliptical
   orbit only the RING is drawn in this full-page SVG overlay, so it can reach
   out over the 2-D map.  Transparent + pointer-events off so the map/panel stay
   usable; below the track panel (z 8) so that stays on top. */
.globe2-orbit-svg {
  position: fixed;
  left: 0; top: 0;
  width: 100vw; height: 100vh;
  z-index: 5;
  pointer-events: none;
  overflow: visible;
}
.globe2-orbit-svg .g2o-front  { fill: none; stroke: #ffd23f; stroke-width: 2;   opacity: 0.9; stroke-linecap: round; }
.globe2-orbit-svg .g2o-behind { fill: none; stroke: #ffd23f; stroke-width: 1.6; opacity: 0.5; stroke-dasharray: 4 5; stroke-linecap: round; }
.globe2-orbit-svg .g2o-nadir   { stroke: #bfe0ff; stroke-width: 1; stroke-dasharray: 2 3; }
.globe2-orbit-svg .g2o-mk      { fill: #8bff9e; }
.globe2-orbit-svg .g2o-mk-ring { fill: none; stroke: #8bff9e; stroke-width: 2.4; }
/* On narrow screens the side-by-side would crush both; drop the globe and
   let the map use the full width. */
@media (max-width: 820px) {
  body.page-2d .globe-cell { display: none; }
  body.page-2d .map-row { padding: 6px; }
}
/* Equirectangular raster on its own layer, stretched to fill the 2:1 cell so
   the SVG track (which maps lon/lat linearly to the same rectangle) sits on
   the coastlines.  Brightened per request — this layer's filter can't touch
   the track, which lives in a sibling SVG above it. */
body.page-2d .map-basemap {
  position: absolute;
  inset: 0;
  z-index: 1;
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
  filter: brightness(1.32) saturate(1.08) contrast(1.02);
}
/* SVG track overlay — above the basemap, below the chrome. */
body.page-2d .track-svg {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  overflow: visible;
}
/* Very light edge vignette — kept subtle so the map stays bright. */
body.page-2d .map-cell::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  background: radial-gradient(ellipse at center, transparent 72%, rgba(0, 0, 0, 0.22));
}

/* ---- SVG track styling (stroke widths are in viewBox units; 1 unit ≈ map
   width / 360 px, so they scale gently with the map) ---- */
body.page-2d .graticule path {
  fill: none;
  stroke: #ffffff;
  stroke-opacity: 0.12;
  stroke-width: 0.12;
}
body.page-2d .track-halo {
  fill: none;
  stroke: rgba(3, 10, 22, 0.6);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
body.page-2d .track-line {
  fill: none;
  stroke-width: 0.95;
  stroke-linecap: round;
  stroke-dasharray: 0.1 2.6;
}
/* Time-based ground track — past green, next 24 h red. */
body.page-2d .track-line.past   { stroke: #3ddc84; }
body.page-2d .track-line.future { stroke: #ff5b5b; }

/* Rev-mode trail — thin, semi-transparent silver, drawn as the sat flies.
   (Only the rev-based orbit line is silver; the time-based track keeps its
   green / red colours.) */
body.page-2d .rev-line {
  fill: none;
  stroke: #cdd6de;
  stroke-opacity: 0.72;
  stroke-width: 0.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

body.page-2d .mark-hit { fill: transparent; }
body.page-2d .mark { cursor: help; }
body.page-2d .mark-arrow { stroke: rgba(3, 10, 22, 0.85); stroke-width: 0.35; stroke-linejoin: round; }
body.page-2d .mark.past   .mark-arrow { fill: #3ddc84; }
body.page-2d .mark.future .mark-arrow { fill: #ff5b5b; }

body.page-2d .now-ring { stroke: #8bff9e; stroke-width: 0.7; }
body.page-2d .now-glow { fill: #8bff9e; opacity: 0.28; }
body.page-2d .now-dot  { fill: #ffffff; stroke: #0a2a14; stroke-width: 0.45; }

/* Current-position name tag (HTML, kept crisp + fixed size). */
body.page-2d .now-label {
  position: absolute;
  z-index: 5;
  transform: translate(-50%, -230%);
  padding: 2px 7px;
  background: rgba(9, 20, 33, 0.82);
  border: 1px solid rgba(139, 255, 158, 0.5);
  border-radius: 5px;
  color: #eafff0;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  pointer-events: none;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
}
body.page-2d .now-label[hidden] { display: none; }

/* Hover tooltip for the 30-min marks. */
body.page-2d .track-tooltip {
  position: absolute;
  z-index: 9;
  max-width: 220px;
  padding: 7px 10px;
  background: rgba(6, 15, 26, 0.94);
  border: 1px solid rgba(120, 170, 220, 0.4);
  border-radius: 7px;
  color: #eaf3fb;
  font-size: 11.5px;
  line-height: 1.4;
  white-space: pre-line;
  pointer-events: none;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55);
}
body.page-2d .track-tooltip[hidden] { display: none; }
body.page-2d .map-cell .map-title {
  color: #f1f7ff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85);
}
body.page-2d .map-cell .map-sub {
  color: #b8cbe2;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
}

/* ---- Ground-track control panel (search + selected-sat readout + legend).
   Dark glass card floating top-left over the map. ---- */
.track-panel {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 8;
  width: 300px;
  max-width: calc(100% - 24px);
  /* Never taller than the map — the header stays put and the body scrolls. */
  max-height: calc(100% - 24px);
  display: flex;
  flex-direction: column;
  background: rgba(8, 17, 28, 0.86);
  border: 1px solid rgba(120, 170, 220, 0.28);
  border-radius: 10px;
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
  color: #dbe8f5;
  font-size: 12px;
  overflow: hidden;
}
.track-panel .tp-drag { flex: 0 0 auto; }
.track-panel .tp-body { flex: 1 1 auto; overflow-y: auto; }
.track-panel.dragging {
  box-shadow: 0 14px 44px rgba(0, 0, 0, 0.62);
  border-color: rgba(120, 170, 220, 0.55);
}
/* Drag handle — the whole title bar moves the panel. */
.track-panel .tp-drag {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 11px;
  cursor: grab;
  user-select: none;
  touch-action: none;
  background: rgba(103, 200, 255, 0.09);
  border-bottom: 1px solid rgba(120, 170, 220, 0.22);
}
.track-panel.dragging .tp-drag { cursor: grabbing; }
.track-panel .tp-grip { color: #5f7d99; letter-spacing: -1px; font-size: 13px; }
.track-panel .tp-title {
  flex: 1;
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #7fd4ff;
}
.tp-collapse {
  flex: 0 0 auto;
  width: 22px;
  height: 20px;
  padding: 0;
  border: 1px solid rgba(120, 170, 220, 0.3);
  border-radius: 5px;
  background: rgba(3, 10, 18, 0.6);
  color: #9fc3e6;
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
}
.tp-collapse:hover { border-color: #63d5ff; color: #eaf3fb; }
.track-panel .tp-body { padding: 12px 13px; }
/* Collapsed: only the drag/title bar remains, for a clear view of the map. */
.track-panel.collapsed .tp-body { display: none; }
.track-panel.collapsed .tp-drag { border-bottom: none; }
.track-search-wrap { position: relative; }
#sat-search {
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  background: rgba(3, 10, 18, 0.9);
  border: 1px solid rgba(120, 170, 220, 0.35);
  border-radius: 7px;
  color: #eaf3fb;
  font-size: 13px;
  font-family: inherit;
}
#sat-search:focus {
  outline: none;
  border-color: #63d5ff;
  box-shadow: 0 0 0 2px rgba(99, 213, 255, 0.18);
}
#sat-search::placeholder { color: #6f8399; }

.sat-results {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  z-index: 8;
  max-height: 264px;
  overflow-y: auto;
  background: #08121e;
  border: 1px solid rgba(120, 170, 220, 0.3);
  border-radius: 7px;
  box-shadow: 0 12px 34px rgba(0, 0, 0, 0.6);
}
.sat-results[hidden] { display: none; }
.sat-opt {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  cursor: pointer;
  font-size: 12px;
  color: #cfe0f0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}
.sat-opt:last-child { border-bottom: none; }
.sat-opt:hover,
.sat-opt.active { background: rgba(99, 213, 255, 0.14); }
.sat-opt .nid { color: #7f93a6; font-size: 10.5px; flex: 0 0 auto; }
.sat-none { padding: 9px 10px; color: #7f93a6; font-size: 12px; }

.sat-info { margin-top: 11px; }
.sat-info[hidden] { display: none; }
.si-name { font-size: 13.5px; font-weight: 700; color: #fff; margin-bottom: 6px; line-height: 1.25; }
.si-grid { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; font-size: 12px; }
.si-grid span { color: #8aa0b5; }
.si-grid b { color: #eaf3fb; font-weight: 600; }
.si-anchor { margin-top: 8px; font-size: 10.5px; color: #7f93a6; letter-spacing: 0.02em; }

.track-legend {
  margin-top: 11px;
  padding-top: 9px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 11.5px;
  color: #a9bccf;
}
.track-legend span { display: flex; align-items: center; gap: 7px; }
.track-legend i { flex: 0 0 auto; }
.track-legend .lg-line { width: 20px; height: 0; border-top: 2px dotted currentColor; }
.track-legend .lg-line.past { color: #3ddc84; }
.track-legend .lg-line.future { color: #ff5b5b; }
.track-legend .lg-mark {
  width: 0; height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 8px solid #3ddc84;
}
.track-legend .lg-now {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: #8bff9e;
  box-shadow: 0 0 0 2px rgba(139, 255, 158, 0.3);
}
.track-legend .lg-line.gold { border-top-style: solid; color: #cdd6de; }

/* ---- mode toggle (TIME / REV based) ---- */
.mode-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 12px;
}
.mode-name {
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #9fb6c9;
}
.switch {
  position: relative;
  flex: 0 0 auto;
  width: 46px;
  height: 23px;
  padding: 0;
  border-radius: 999px;
  border: 1px solid rgba(120, 170, 220, 0.4);
  background: rgba(3, 10, 18, 0.9);
  cursor: pointer;
  transition: background .16s, border-color .16s;
}
.switch .switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: #8fb3d4;
  transition: left .16s, background .16s;
}
.switch.on { background: rgba(255, 180, 61, 0.28); border-color: #ffb43d; }
.switch.on .switch-thumb { left: 25px; background: #ffb43d; }
.mode-state {
  margin-top: 6px;
  font-size: 11px;
  letter-spacing: 0.03em;
  color: #7fd4ff;
}

/* ---- rev-mode speed controls, snapped to the bottom of the panel ---- */
.rev-section {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.rev-section[hidden] { display: none; }
.rev-sec-title {
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #ffcf7a;
  margin-bottom: 7px;
}
.rev-speed { width: 100%; margin: 0; accent-color: #ffb43d; cursor: pointer; }
.rev-ticks {
  display: flex;
  justify-content: space-between;
  margin-top: 3px;
  font-size: 7px;
  letter-spacing: -0.03em;
  color: #7f93a6;
  font-variant-numeric: tabular-nums;
}
.rev-line1 {
  display: flex;
  justify-content: space-between;
  margin-top: 8px;
  font-size: 11px;
  color: #a9bccf;
}
.rev-line1 b { color: #ffd27a; font-weight: 700; }
.rev-clock {
  display: flex;
  gap: 22px;
  margin-top: 7px;
  padding-top: 7px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.rev-clock div { display: flex; flex-direction: column; gap: 1px; }
.rev-clock span { font-size: 9.5px; letter-spacing: 0.14em; color: #7f93a6; }
.rev-clock b { font-size: 15px; font-variant-numeric: tabular-nums; color: #eafff0; letter-spacing: 0.02em; }
.rev-clock em { font-style: normal; font-size: 9.5px; color: #9fb6c9; letter-spacing: 0.02em; }

@media (max-width: 560px) {
  .track-panel { width: 258px; top: 8px; left: 8px; }
  .track-panel .tp-body { padding: 10px 11px; }
  .sat-results { max-height: 200px; }
}

.page-2d-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background:
    radial-gradient(ellipse at top, rgba(78, 168, 255, 0.06), transparent 60%),
    var(--bg);
}

.page-2d-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
  gap: 10px;
}
.page-2d-header .brand {
  font-size: 13px;
  letter-spacing: 0.22em;
  color: var(--accent);
  text-shadow: 0 0 12px rgba(103, 200, 255, 0.55);
}
.page-2d-header .right {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 10px;
  color: var(--dim);
  letter-spacing: 0.1em;
}
.page-2d-header .legend-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 5px;
  vertical-align: middle;
}
.page-2d-header .legend-dot.green { background: var(--green); box-shadow: 0 0 6px var(--green); }
.page-2d-header .legend-dot.red   { background: var(--accent2); box-shadow: 0 0 6px var(--accent2); }

.btn-back {
  color: var(--accent);
  text-decoration: none;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 6px 12px;
}
.btn-back:hover { border-color: var(--accent); }

.maps-grid {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 1px;
  background: var(--line);
  min-height: calc(100vh - 56px);
}
@media (max-width: 900px) {
  .maps-grid {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(4, minmax(360px, 1fr));
  }
}
.maps-grid.maps-single {
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
}

.map-cell {
  position: relative;
  background: var(--bg);
  overflow: hidden;
  min-height: 320px;
}
.map-cell .map-title {
  position: absolute;
  top: 10px;
  left: 14px;
  z-index: 5;
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  text-shadow: 0 0 8px rgba(103, 200, 255, 0.5);
  pointer-events: none;
}
.map-cell .map-sub {
  position: absolute;
  top: 26px;
  left: 14px;
  z-index: 5;
  font-size: 9px;
  color: var(--dim);
  letter-spacing: 0.1em;
  pointer-events: none;
}
.map-cell .chart {
  width: 100%;
  height: 100%;
}

/* =======================================================================
   TLE Repository modal (sat-stats.js, ⌗ TLE Repo button)

   Full-screen overlay with a centred card; scrolls internally so the
   underlying SatStats page doesn't have to.  Fades in via the .shown
   class added one tick after the [hidden] attribute is removed.
   ======================================================================= */
.tle-modal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 28px;
  background: rgba(0, 0, 0, 0.62);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  opacity: 0;
  transition: opacity .22s ease-out;
}
.tle-modal[hidden] { display: none; }
.tle-modal.shown { opacity: 1; }

.tle-modal-card {
  width: min(1280px, 100%);
  height: min(880px, 100%);
  display: flex;
  flex-direction: column;
  background: rgba(2, 6, 13, 0.96);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.7);
  overflow: hidden;
  transform: scale(0.96);
  transition: transform .22s ease-out;
}
.tle-modal.shown .tle-modal-card { transform: scale(1); }

.tle-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line);
}
.tle-modal-title-block { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.tle-modal-header h2 {
  margin: 0;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.2em;
  color: var(--accent);
  text-transform: uppercase;
}
.tle-modal-meta {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 0.06em;
}
.tle-modal-meta strong {
  color: var(--accent);
  font-weight: normal;
  font-variant-numeric: tabular-nums;
}
.tle-modal-close {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--line);
  color: var(--text);
  font-family: var(--mono);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  transition: background .15s, transform .15s, border-color .15s;
}
.tle-modal-close:hover {
  background: rgba(103, 200, 255, 0.20);
  border-color: var(--accent);
  transform: scale(1.06);
}

.tle-modal-toolbar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--line);
  background: rgba(0, 0, 0, 0.18);
}
.tle-modal-toolbar input[type="search"] {
  flex: 1 1 280px;
  max-width: 360px;
  padding: 6px 10px;
  background: rgba(0, 0, 0, 0.32);
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--text);
  font-family: var(--mono);
  font-size: 13px;
  outline: none;
}
.tle-modal-toolbar input[type="search"]:focus { border-color: var(--accent); }
.tle-modal-hint {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 0.04em;
}

/* Pager pill in the toolbar — prev arrow · "Page X / Y" · next arrow */
.tle-modal-pager {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px;
  background: rgba(2, 6, 13, 0.45);
  border: 1px solid var(--line);
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 0.08em;
  white-space: nowrap;
}
.tle-modal-pager strong {
  color: var(--accent);
  font-weight: normal;
  font-variant-numeric: tabular-nums;
}
.tle-modal-page-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  background: rgba(103, 200, 255, 0.10);
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 16px;
  line-height: 1;
  padding: 0;
  cursor: pointer;
  transition: background .12s, border-color .12s, transform .12s;
}
.tle-modal-page-btn:hover:not(:disabled) {
  background: rgba(103, 200, 255, 0.24);
  border-color: var(--accent);
  transform: scale(1.06);
}
.tle-modal-page-btn:active:not(:disabled) { transform: scale(0.96); }
.tle-modal-page-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.tle-modal-body {
  flex: 1 1 auto;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

.tle-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--text);
  background: transparent;
}
.tle-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 8px 10px;
  background: rgba(2, 6, 13, 0.94);
  border-bottom: 1px solid var(--line);
  color: var(--dim);
  font-weight: normal;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: left;
  white-space: nowrap;
}
.tle-table tbody td {
  padding: 6px 10px;
  border-bottom: 1px solid rgba(110, 200, 255, 0.07);
  vertical-align: top;
}
.tle-table tbody tr:hover td { background: rgba(103, 200, 255, 0.06); }
.tle-table td.mono { font-variant-numeric: tabular-nums; }
.tle-table td.col-country { white-space: nowrap; }
.tle-table .col-tle { min-width: 380px; }
.tle-table .tle-cell div {
  font-family: 'Courier New', monospace;
  font-size: 10.5px;
  white-space: pre;
  letter-spacing: 0;
  color: var(--text);
  line-height: 1.35;
}
.tle-table .tle-cell div + div { color: var(--dim); }

.tle-validity {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 2px;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.tle-validity-fresh   { background: rgba(35, 206, 95, 0.18);  color: #23ce5f; }
.tle-validity-stale   { background: rgba(249, 210, 76, 0.18); color: #f9d24c; }
.tle-validity-expired { background: rgba(255, 107, 107, 0.18); color: #ff6b6b; }
.tle-validity-future  { background: rgba(103, 200, 255, 0.18); color: #67c8ff; }
.tle-validity-unknown { background: rgba(255, 255, 255, 0.10); color: var(--dim); }

/* --- "How to decode a TLE" explainer below the table -------------- */
.tle-explainer {
  margin: 24px 14px 18px;
  padding: 22px;
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text);
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.65;
}
.tle-explainer h3 {
  margin: 0 0 12px;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}
.tle-explainer p { margin: 0 0 14px; }
.tle-explainer code {
  font-family: 'Courier New', monospace;
  font-size: 12px;
  padding: 1px 5px;
  background: rgba(2, 6, 13, 0.65);
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--accent);
}
.tle-explainer em     { color: var(--text); font-style: italic; }
.tle-explainer strong { color: var(--text); font-weight: 700; }

/* Sample TLE shown above each per-line field table.  Sits on its own
   highlighted strip so the user can see which characters the table
   below is talking about. */
.tle-decoded { margin: 18px 0 10px; }
.tle-decoded-label {
  font-family: 'Orbitron', sans-serif;
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 6px;
}
.tle-decoded-sample {
  margin: 0;
  padding: 10px 14px;
  background: rgba(2, 6, 13, 0.7);
  border: 1px solid var(--accent);
  border-radius: 4px;
  font-family: 'Courier New', monospace;
  font-size: 12.5px;
  line-height: 1.5;
  letter-spacing: 0;
  color: var(--accent);
  text-shadow: 0 0 6px rgba(103, 200, 255, 0.35);
  white-space: pre;
  overflow-x: auto;
}

/* Field-by-field breakdown table — narrower than the main TLE table
   and rendered in the regular palette so it reads as documentation,
   not a third data view. */
.tle-fields-table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 8px;
  font-size: 12px;
}
.tle-fields-table thead th {
  padding: 6px 10px;
  background: rgba(2, 6, 13, 0.45);
  border-bottom: 1px solid var(--line);
  color: var(--dim);
  font-weight: normal;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: left;
}
.tle-fields-table tbody td {
  padding: 5px 10px;
  border-bottom: 1px solid rgba(110, 200, 255, 0.07);
  vertical-align: top;
  color: var(--text);
}
.tle-fields-table tbody td:first-child {
  font-family: 'Courier New', monospace;
  color: var(--accent);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.tle-fields-table tbody td:nth-child(2) {
  color: var(--text);
  white-space: nowrap;
}
.tle-fields-table tbody td:nth-child(3) {
  font-family: 'Courier New', monospace;
  color: #fbc814;
  white-space: nowrap;
}
.tle-fields-table tbody tr:hover td { background: rgba(103, 200, 255, 0.04); }

.tle-foot {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
  color: var(--dim);
  font-size: 12px;
}

@media (max-width: 720px), (max-height: 500px) and (max-width: 950px) {
  .tle-modal { padding: 8px; }
  .tle-modal-card { height: 100%; }
  .tle-modal-header { padding: 10px 12px; }
  .tle-modal-header h2 { font-size: 13px; }
  .tle-modal-toolbar { padding: 10px 12px; flex-wrap: wrap; gap: 8px; }
  .tle-modal-hint { font-size: 10px; }
  .tle-table thead th, .tle-table tbody td { padding: 5px 6px; font-size: 10.5px; }
  .tle-table .tle-cell div { font-size: 9.5px; }
}

