/* Mars Remembers */

:root {
  --accent:       #004445;
  --accent-light: #006668;
  --focus-glow:   #FFD166;
  --ink:          #2C3E3E;
  --muted:        #5A6E6E;

  /* Scene chrome — a dark, warm shell so the butterscotch Mars sky reads as
     daylight rather than as a bright page. Recorded as a COLOR-3 exception. */
  --shell-top:    #241a15;
  --shell-bottom: #17100c;
  --panel:        rgba(42, 30, 24, 0.96);
  --card:         rgba(58, 42, 33, 0.72);
  --border:       rgba(216, 158, 108, 0.26);
  --scene-ink:    #F2E4D6;
  --scene-muted:  #C0A48D;
  --rust:         #C4633A;   /* tints and accents only — never behind text */
  --rust-fill:    #A04A28;   /* selected/hover fills: 4.8:1 with --scene-ink */
  --rust-bright:  #E4864F;
  --focus:        #60a5fa;

  --radius-xl: 22px;
  --radius-lg: 16px;
  --radius-md: 12px;
  --radius-sm: 9px;
  --shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
}

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* An author display rule outranks the UA stylesheet's [hidden] { display:none },
   so every card that toggles with `hidden` needs this to actually hide. */
[hidden] { display: none !important; }

html, body {
  height: 100%;
  overflow: hidden;
  font-family: Roboto, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

body {
  background: linear-gradient(180deg, var(--shell-top) 0%, var(--shell-bottom) 100%);
  color: var(--scene-ink);
}

button, input {
  font: inherit;
}

button {
  cursor: pointer;
  font-family: Roboto, Arial, sans-serif;
}

button:focus-visible {
  outline: 3px solid var(--focus);
  box-shadow: 0 0 0 6px rgba(12, 8, 5, 0.62);
  outline-offset: 2px;
}

#sim-app {
  display: flex;
  flex-direction: column;
  height: 100%;
}

#stage-panel {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  background: var(--panel);
  overflow: hidden;
}

#canvas-frame {
  position: relative;
  min-height: 0;
  overflow: hidden;
  background: linear-gradient(180deg, #d9b389 0%, #c08d63 55%, #6d4530 100%);
}

#sim-canvas {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
}

#sim-canvas:focus-visible {
  outline: 3px solid var(--focus);
  box-shadow: 0 0 0 6px rgba(12, 8, 5, 0.62);
  outline-offset: -3px;
}

/* ── Scene HUD ── */
.hud-chip {
  position: absolute;
  top: 12px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 8px 12px;
  border-radius: var(--radius-md);
  background: rgba(28, 18, 13, 0.82);
  border: 1px solid rgba(226, 176, 130, 0.3);
  pointer-events: none;
  min-width: 96px;
}

#hud-sols { left: 12px; }
#hud-site { left: auto; right: 12px; top: 12px; max-width: 224px; }

/* The chip ignores the pointer so it never blocks the scene behind it. The age
   line has to take it back, or its explanation can only be reached by keyboard. */
#site-age { pointer-events: auto; }

.hud-label {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--scene-muted);
}

.hud-value {
  font-size: 24px;
  font-weight: 700;
  line-height: 1.05;
  color: #FFE8CF;
}

.hud-value.hud-low { color: #FF9E6B; }

.hud-sub {
  font-size: 12px;
  color: var(--scene-muted);
  max-width: 190px;
}

.map-hint {
  position: absolute;
  left: 12px;
  top: 222px;   /* replaced at runtime: it hangs under the tile */
  max-width: 232px;
  padding: 6px 11px;
  border-radius: var(--radius-md);
  background: rgba(28, 18, 13, 0.78);
  border: 1px solid rgba(226, 176, 130, 0.26);
  color: var(--scene-muted);
  font-size: 12px;
  line-height: 1.35;
  text-align: left;
  pointer-events: none;
}

.map-hint[hidden] { display: none; }

.link-strip {
  position: absolute;
  left: 50%;
  bottom: 96px;
  transform: translateX(-50%);
  width: max-content;
  max-width: 92%;
  padding: 9px 14px;
  border-radius: var(--radius-md);
  background: rgba(20, 13, 9, 0.92);
  border: 1px solid rgba(226, 176, 130, 0.34);
  pointer-events: none;
}

.link-strip[hidden] { display: none; }

.link-stages {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  justify-content: center;
}

.link-stage {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--scene-muted);
}

.link-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1px solid var(--scene-muted);
  flex: none;
}

.link-stage.done { color: #A7DCBB; }
.link-stage.done .link-dot { background: #4FA97A; border-color: #7FD8A4; }
.link-stage.now { color: #FFE8CF; font-weight: 700; }
.link-stage.now .link-dot { background: var(--rust-bright); border-color: #FFD9B0; }

.link-light {
  margin-top: 5px;
  text-align: center;
  font-size: 12px;
  color: var(--scene-muted);
  font-variant-numeric: tabular-nums;
}

.interaction-hint {
  position: absolute;
  left: 50%;
  bottom: 96px;
  transform: translateX(-50%);
  width: max-content;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: 999px;
  background: rgba(28, 18, 13, 0.7);
  border: 1px solid rgba(226, 176, 130, 0.26);
  color: var(--scene-ink);
  font-size: 12px;
  pointer-events: none;
  transition: opacity 0.4s;
}

.interaction-hint.hint-used {
  opacity: 0;
}

.hint-arrow {
  color: var(--rust-bright);
  font-size: 14px;
}

.scene-toast {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: max-content;
  max-width: 78%;
  padding: 14px 22px;
  border-radius: var(--radius-lg);
  background: rgba(24, 15, 11, 0.93);
  border: 1px solid rgba(226, 176, 130, 0.4);
  color: #FFE8CF;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.5;
  text-align: center;
  box-shadow: var(--shadow);
}

.scene-toast[hidden] { display: none; }

.scene-toast strong { color: var(--rust-bright); }

/* ── Scene overlay: the controls live on the thing they act on ── */
.scene-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.leader-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.leader {
  stroke: rgba(255, 224, 184, 0.85);
  stroke-width: 1.6;
  stroke-dasharray: 4 3;
}

.badge-wrap {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  width: max-content;
  pointer-events: auto;
}

.badge {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-height: 28px;
  padding: 5px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(226, 176, 130, 0.5);
  background: rgba(24, 15, 11, 0.88);
  color: var(--scene-ink);
  text-align: left;
  white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
}

.badge:hover { background: rgba(46, 28, 19, 0.94); border-color: var(--rust-bright); }

.badge-name { font-size: 14px; font-weight: 600; line-height: 1.15; }
.badge-sub,
.badge-cost { font-size: 12px; color: var(--scene-muted); line-height: 1.15; }

.badge-act {
  min-height: 32px;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid #7fd8a4;
  background: #14603c;
  color: #E8FBF0;
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
}

.badge-act:hover:not(:disabled) { background: #1a7a4c; }
.badge-act:disabled { opacity: 0.4; cursor: not-allowed; }
.badge-act.act-go { background: var(--rust-fill); border-color: var(--rust-bright); color: var(--scene-ink); }
.badge-act.act-go:hover:not(:disabled) { background: #8F3F22; }

/* Map pins */
.badge-map { z-index: 1; }
.badge-map.is-sel { z-index: 3; }
.badge-map.is-here { z-index: 2; }
.badge-map.is-sel .badge { border-color: #FFD166; background: rgba(58, 34, 18, 0.94); }
.badge-map.is-here .badge-name::before {
  content: '';
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 6px;
  border-radius: 50%;
  background: #7fe0a0;
  vertical-align: middle;
}
.badge-map:not(.is-sel) .badge { opacity: 0.9; }

/* Instrument callouts on the rover */
.badge-instr .badge { border-color: rgba(159, 228, 255, 0.55); }
.badge-instr .badge.is-off { opacity: 0.45; }
.badge-instr.is-armed .badge {
  border-color: #7fd8a4;
  background: rgba(18, 62, 42, 0.94);
  box-shadow: 0 0 0 2px rgba(127, 216, 164, 0.35), 0 4px 14px rgba(0, 0, 0, 0.45);
}
.badge-instr.is-armed .badge-name::after {
  content: " \2713";
  color: #7fd8a4;
}
.badge-target.is-sel .badge { border-color: #9fe4ff; background: rgba(20, 44, 56, 0.9); }

.badge:focus-visible,
.badge-act:focus-visible {
  outline: 3px solid var(--focus);
  box-shadow: 0 0 0 6px rgba(12, 8, 5, 0.62);
  outline-offset: 2px;
}

/* ── Command bar: fixed, so the primary action never moves ── */
.command-bar {
  position: absolute;
  left: 12px;
  bottom: 12px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-lg);
  background: rgba(20, 13, 9, 0.9);
  border: 1px solid rgba(226, 176, 130, 0.34);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
  max-width: calc(100% - 190px);
  flex-wrap: wrap;
}

.clock {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 96px;
}

/* The divider exists to separate the clock from a button. With no button on
   screen it was a line to nowhere. */
.command-bar.has-action .clock {
  padding-right: 10px;
  border-right: 1px solid rgba(226, 176, 130, 0.24);
}

.clock-label {
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--scene-muted);
}

.clock-read {
  font-size: 12px;
  color: var(--scene-muted);
  line-height: 1.1;
}

.clock-read strong {
  font-size: 20px;
  font-weight: 700;
  color: #FFE8CF;
  margin-right: 3px;
}

.clock-track {
  height: 4px;
  border-radius: 2px;
  background: rgba(226, 176, 130, 0.22);
  overflow: hidden;
}

.clock-fill {
  height: 100%;
  width: 0;
  border-radius: 2px;
  background: var(--rust-bright);
  transition: width 0.35s ease;
}

.clock-fill.is-low { background: #FF9E6B; }

.cmd-btn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-height: 44px;
  padding: 7px 14px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 700;
  white-space: nowrap;
  transform-origin: left center;
  opacity: 0;
  transform: translateY(5px) scale(0.94);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.cmd-btn.is-in {
  opacity: 1;
  transform: none;
}

.cmd-kicker {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  opacity: 0.78;
}

.cmd-main { font-size: 14px; font-weight: 700; line-height: 1.15; }

.cmd-cost {
  font-size: 12px;
  font-weight: 500;
  opacity: 0.82;
  font-variant-numeric: tabular-nums;
}

.cmd-view {
  border: 1px solid var(--rust-bright);
  background: var(--rust-fill);
  color: var(--scene-ink);
}

.cmd-view:hover:not(:disabled) { background: #8F3F22; }

.cmd-uplink {
  border: 1px solid #7fd8a4;
  background: #14603c;
  color: #E8FBF0;
}

.cmd-uplink:hover:not(:disabled) { background: #1a7a4c; }

.cmd-btn:disabled { opacity: 0.4; cursor: not-allowed; }

@media (prefers-reduced-motion: reduce) {
  .clock-fill { transition: none; }
  .cmd-btn { transition: none; }
}

/* Compact map pins: on a narrow frame seven full labels bury the map they
   annotate, so an unselected pin shows only its height. The button's
   aria-label still carries the stop's name, so a screen reader loses nothing. */
.scene-overlay.is-compact .badge-map:not(.is-sel):not(.is-here) .badge-name { display: none; }
.scene-overlay.is-compact .badge-map:not(.is-sel):not(.is-here) .badge-sub {
  font-size: 13px;
  font-weight: 600;
  color: var(--scene-ink);
}
.scene-overlay.is-compact .badge-map.is-here:not(.is-sel) .badge-sub { display: none; }

@media (max-width: 620px) {
  .badge { padding: 4px 8px; min-height: 26px; }
  .badge-name { font-size: 13px; }
  .badge-sub, .badge-cost { font-size: 12px; }
  .badge-act { min-height: 30px; font-size: 12px; padding: 5px 8px; }
  /* Narrow: the bar sizes to its content instead of spanning the frame, and
     stacks. Anchored at the bottom, a second row lifts the clock rather than
     widening the bar into the elevation badges on the right. */
  .command-bar {
    left: 8px;
    right: auto;
    bottom: 8px;
    max-width: calc(100% - 16px);
    gap: 7px;
    padding: 7px 8px;
    flex-direction: column;
    align-items: flex-start;
    flex-wrap: nowrap;
  }
  .cmd-btn { min-height: 36px; padding: 7px 10px; font-size: 13px; }
  .clock { min-width: 78px; }

  /* The stack already separates the two, so the divider is redundant here. */
  .command-bar.has-action .clock {
    padding-right: 0;
    border-right: none;
  }
}

@media (max-width: 560px) {
  .hud-chip {
    gap: 1px;
    padding: 5px 9px;
    min-width: 0;
  }

  .hud-value { font-size: 18px; }
  .hud-sub { max-width: 150px; }

  #hud-sols { left: 8px; top: 8px; }
  #hud-site { left: auto; right: 8px; top: 8px; max-width: 168px; }
  .map-hint { display: none; }
  .link-strip { bottom: 8px; padding: 7px 10px; }
  .link-stages { gap: 4px 10px; }
}

/* ── Accessibility ── */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .interaction-hint { transition: none; }
}

/* ── Info dialog ──
   The dialog is Tuva Sims "chrome", so its accent is the P1 purple (#5c4738),
   NOT the sim's green var(--accent). Header = purple with white text; active
   tab / h3 / footer button = purple; tabs/footer surface = #F8FBFB; body text =
   var(--ink). The shared toolbar stylesheet also injects these purple rules
   (scoped to #info-dialog) so existing green sims reskin automatically — keep
   this block in sync with it; do not redefine per sim. */
#info-dialog {
  border: none;
  border-radius: 12px;
  padding: 0;
  width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - 80px);
  overflow: hidden;
  margin: auto;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.22);
  background: #ffffff;
}

#info-dialog::backdrop {
  background: rgba(30, 16, 48, 0.55);
}

.dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  background: #5c4738;
  color: #ffffff;
}

.dialog-header h2 {
  font-size: 16px;
  font-weight: 600;
}

#dialog-close-btn {
  background: transparent;
  border: none;
  color: #ffffff;
  font-size: 18px;
  cursor: pointer;
  width: 32px;
  height: 32px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

#dialog-close-btn:hover {
  background: rgba(255, 255, 255, 0.15);
}

#dialog-close-btn:focus-visible {
  outline: 3px solid var(--focus-glow);
  box-shadow: 0 0 0 6px rgba(12, 8, 5, 0.62);
  outline-offset: 2px;
}

.dialog-tabs {
  display: flex;
  border-bottom: 2px solid #E5EAE9;
  background: #F8FBFB;
}

.tab-btn {
  flex: 1;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  margin-bottom: -2px;
  padding: 10px 0;
  font-family: Roboto, Arial, sans-serif;
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}

.tab-btn:hover {
  color: #5c4738;
}

.tab-btn.active,
.tab-btn[aria-selected="true"] {
  color: #5c4738;
  border-bottom-color: #5c4738;
}

.tab-btn:focus-visible {
  outline: 3px solid var(--focus-glow);
  box-shadow: 0 0 0 6px rgba(12, 8, 5, 0.62);
  outline-offset: -3px;
}

.dialog-body {
  padding: 16px 20px;
  overflow-y: auto;
  max-height: calc(100vh - 240px);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.55;
}

.dialog-body h3 {
  font-size: 14px;
  font-weight: 600;
  color: #5c4738;
  margin-top: 14px;
  margin-bottom: 6px;
}

.dialog-body h3:first-child {
  margin-top: 0;
}

.dialog-body p {
  margin-bottom: 8px;
}

.dialog-body ul,
.dialog-body ol {
  padding-left: 20px;
  margin-bottom: 8px;
}

.dialog-body li {
  margin-bottom: 4px;
}

.dialog-body summary { cursor: pointer; font-weight: 600; color: var(--accent); }
.dialog-body details[open] summary { margin-bottom: 6px; }

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  padding: 12px 20px;
  border-top: 1px solid #E5EAE9;
  background: #F8FBFB;
}

.dialog-close-footer {
  background: #5c4738;
  color: #ffffff;
  border: none;
  border-radius: 6px;
  padding: 8px 20px;
  font-family: Roboto, Arial, sans-serif;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s;
}

.dialog-close-footer:hover {
  background: #7d6c60;
}

.dialog-close-footer:focus-visible {
  outline: 3px solid var(--focus-glow);
  box-shadow: 0 0 0 6px rgba(12, 8, 5, 0.62);
  outline-offset: 2px;
}

/* Camera authoring readout — only ever shown via ?cam=1 */
.cam-readout {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 12px;
  z-index: 5;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 5px 9px;
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.78);
  color: #9fe4ff;
  font-family: ui-monospace, monospace;
  font-size: 12px;
  pointer-events: none;
}
.cam-readout[hidden] { display: none; }

/* ── Elevation rail (map view) ──
   Every stroke gets a dark casing. A pale line on a pale Mars sky measured
   1.8:1 against the brightest thing behind it, well under the 3:1 that WCAG
   1.4.11 wants for a graphic that carries meaning; the casing is the standard
   cartographic answer and holds on dark terrain too. */
.leader,
.rail-line,
.rail-tick,
.rail-stub,
.rail-val {
  filter: drop-shadow(0 0 1.6px rgba(0, 0, 0, 0.95))
          drop-shadow(0 0 1.6px rgba(0, 0, 0, 0.75));
}

/* ── Elevation rail (map view) ── */
.rail-line {
  stroke: rgba(255, 224, 184, 0.85);
  stroke-width: 2;
  stroke-linecap: round;
}

/* Elevation values sit to the right of the line — the axis states the height so
   the badges do not have to. */
.rail-val {
  fill: #FFE8CF;
  font-family: Roboto, Arial, sans-serif;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  paint-order: stroke;
  stroke: rgba(20, 13, 9, 0.9);
  stroke-width: 3.5;
}

.rail-val.is-sel { fill: #FFD166; font-weight: 700; }
.rail-val.is-here { fill: #9BEDB8; font-weight: 700; }

.rail-tick {
  stroke: rgba(255, 224, 184, 0.9);
  stroke-width: 2;
}

.rail-tick.is-sel { stroke: #FFD166; stroke-width: 3.5; }
.rail-tick.is-here { stroke: #7fe0a0; stroke-width: 3.5; }

/* The connector was too faint to follow across the terrain behind it. */
.rail-stub {
  stroke: rgba(255, 230, 196, 0.95);
  stroke-width: 1.7;
}

.rail-stub.is-sel { stroke: #FFD166; stroke-width: 2.4; }
.rail-stub.is-here { stroke: #9BEDB8; stroke-width: 2.2; }

.leader.is-sel {
  stroke: #FFD166;
  stroke-width: 2.2;
  stroke-dasharray: none;
}

/* ── Variant "tile": the view switch is a picture of where you would go ──
   A thumbnail of the destination is a far stronger affordance than a hotspot on
   the rover, and because it reads as a view rather than a control it never
   competes with the uplink command for "this is the thing to press". */
.view-tile {
  position: absolute;
  left: 12px;
  top: 12px;
  padding: 0;
  border-radius: var(--radius-lg);
  border: 1px solid rgba(226, 176, 130, 0.45);
  background: rgba(20, 13, 9, 0.92);
  overflow: hidden;
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.5);
  line-height: 0;
  transition: transform 0.16s ease, border-color 0.16s ease;
}

.view-tile[hidden] { display: none !important; }

.view-tile:hover:not(:disabled) {
  transform: translateY(-2px) scale(1.02);
  border-color: var(--rust-bright);
}

/* In transit the tile reports what the rover is doing and stops being a door. */
.view-tile:disabled { cursor: default; }
.view-tile.is-transit .view-tile-canvas { filter: grayscale(0.55) brightness(0.55); }
.view-tile.is-transit .view-tile-kicker { color: #7fd8a4; }

.view-tile:focus-visible {
  outline: 3px solid var(--focus);
  box-shadow: 0 0 0 6px rgba(12, 8, 5, 0.62);
  outline-offset: 2px;
}

.view-tile-canvas {
  display: block;
  width: 150px;
  height: 96px;
}

.view-tile-label {
  display: flex;
  flex-direction: column;
  gap: 1px;
  /* The label must not set the tile's width. "Driving to Vera Rubin Ridge" is
     wider than the still, and the tile grew to fit it, leaving its own dark
     background showing beside the image. Held to the still's width, it wraps. */
  width: 150px;
  box-sizing: border-box;
  padding: 7px 10px 8px;
  text-align: left;
  line-height: 1.2;
}

.view-tile-kicker {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--rust-bright);
}

.view-tile-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--scene-ink);
}

/* ── Variant "btn": keep a button, but demote it so only the uplink reads
   as a command. Outline, not a fill. ── */
.command-bar.is-quiet .cmd-view {
  background: transparent;
  border-color: rgba(226, 176, 130, 0.5);
  color: var(--scene-ink);
  font-weight: 600;
}

.command-bar.is-quiet .cmd-view:hover:not(:disabled) {
  background: rgba(226, 176, 130, 0.14);
  border-color: var(--rust-bright);
}

@media (max-width: 620px) {
  .map-hint { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .view-tile { transition: none; }
}

.rail-rover {
  fill: #7fe0a0;
  stroke: rgba(20, 13, 9, 0.9);
  stroke-width: 1;
}

.rail-rover-label {
  fill: #C6F2D6;
  font-family: Roboto, Arial, sans-serif;
  font-size: 12px;
  font-weight: 700;
  text-anchor: end;
  paint-order: stroke;
  stroke: rgba(20, 13, 9, 0.9);
  stroke-width: 3;
}

/* The "here" tag rides inside the title now that the sub-line is spoken for. */
.badge-here-tag {
  margin-left: 7px;
  padding: 1px 6px;
  border-radius: 999px;
  background: rgba(127, 224, 160, 0.2);
  border: 1px solid rgba(155, 237, 184, 0.6);
  color: #9BEDB8;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.badge-map .badge-name {
  display: flex;
  align-items: center;
}

/* Distance rides on the leg it measures. */
.badge-leg .badge {
  border-color: #FFD166;
  background: rgba(58, 40, 14, 0.92);
  cursor: default;
  padding: 4px 9px;
  min-height: 24px;
}

.badge-leg .badge:hover { background: rgba(58, 40, 14, 0.92); border-color: #FFD166; }
.badge-leg .badge-name { font-size: 13px; color: #FFE8CF; }

/* ── The tile as the transition ──
   It already pictures the destination, so instead of laying an effect over the
   switch it becomes the switch: grows from its corner to fill the frame, the
   live view swaps in underneath, then it re-forms in the corner holding the
   view just left. Both directions are the same motion. */
.view-tile-canvas {
  object-fit: cover;
}

.view-tile.is-expanding {
  z-index: 30;
  border-radius: 10px;
  transition: left 0.56s cubic-bezier(0.4, 0, 0.2, 1),
              top 0.56s cubic-bezier(0.4, 0, 0.2, 1),
              width 0.56s cubic-bezier(0.4, 0, 0.2, 1),
              height 0.56s cubic-bezier(0.4, 0, 0.2, 1),
              border-radius 0.56s ease,
              opacity 0.25s linear;
  transform: none !important;
}

.view-tile.is-expanding:hover { transform: none; }

/* The canvas must FOLLOW the growing box, not race it. Transitioning it to
   100% does not work: CSS resolves that percentage against the container's
   size at the moment the transition starts, so the canvas crept 220px -> 222px
   while the box went to full frame, leaving the tile's own dark background
   showing in the gap. Filling absolutely with no transition of its own makes
   the canvas a product of layout, so it matches the box on every frame. */
.view-tile.is-expanding .view-tile-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition: none;
}

.view-tile.is-expanding .view-tile-label {
  opacity: 0;
  transition: opacity 0.22s linear;
}

/* Long enough to read as a dissolve rather than a cut. */
.view-tile.is-handoff { opacity: 0; }
/* Ease IN, so the still holds almost full opacity for the first stretch and
   only then gives way. A fade that drops fast at the start would show any
   remaining mismatch underneath at its most visible. */
.view-tile.is-expanding.is-handoff {
  transition: opacity 0.36s cubic-bezier(0.55, 0, 1, 0.45);
}

/* Re-forming in the corner: a short fade rather than a second slide, so the
   eye follows one movement per switch and not two. */
.view-tile.is-arriving { opacity: 0; }
.view-tile { transition: transform 0.16s ease, border-color 0.16s ease, opacity 0.31s ease; }

@media (prefers-reduced-motion: reduce) {
  .view-tile.is-expanding,
  .view-tile { transition: none; }
}

/* The badges, leader lines and hint describe the view being covered, so they
   go with it instead of sitting under the opening panel. */
#canvas-frame.is-switching .scene-overlay,
#canvas-frame.is-switching .leader-lines,
#canvas-frame.is-switching .map-hint {
  opacity: 0;
  transition: opacity 0.31s ease;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  #canvas-frame.is-switching .scene-overlay,
  #canvas-frame.is-switching .leader-lines,
  #canvas-frame.is-switching .map-hint { transition: none; }
}

/* Nothing in the overlay describes a scene that has not been drawn yet. The
   hints in particular carry no `hidden` of their own — they are switched by
   updateUI, which cannot run until the assets are in — so "Turn the view" was
   painting over an empty canvas before the first frame existed. One class over
   the whole layer is safer than remembering to hide each piece. */
#canvas-frame.is-booting .scene-overlay,
#canvas-frame.is-booting .leader-lines,
#canvas-frame.is-booting .hud-chip,
#canvas-frame.is-booting .interaction-hint,
#canvas-frame.is-booting .map-hint,
#canvas-frame.is-booting .command-bar,
#canvas-frame.is-booting .view-tile,
#canvas-frame.is-booting .link-strip {
  visibility: hidden;
}

/* ── Earth column (trial, ?earth=1) ──
   Deliberately quieter than the Martian rail: the point is the gaps, so the
   line is dashed and the marks are few. Remove this block with the JS behind
   EARTH_COL and nothing else changes. */
.earth-line {
  stroke: rgba(150, 200, 230, 0.55);
  stroke-width: 2;
  stroke-dasharray: 3 7;
}

.earth-tick {
  stroke: #9FD2EE;
  stroke-width: 3;
}

.earth-cap {
  fill: #9FD2EE;
  font: 600 11px var(--sim-font, Roboto), sans-serif;
  letter-spacing: 0.06em;
  text-anchor: middle;
  text-transform: uppercase;
  paint-order: stroke;
  stroke: rgba(18, 12, 8, 0.85);
  stroke-width: 3px;
}

.earth-val {
  fill: #DCEEF9;
  font: 600 11px var(--sim-font, Roboto), sans-serif;
  text-anchor: middle;
  paint-order: stroke;
  stroke: rgba(18, 12, 8, 0.85);
  stroke-width: 3px;
}

/* ── Analysis card (trial, ?card=1) ──
   The readout the instrument actually produces, shown once the downlink lands
   and before the controls return. Remove this block with ANALYSIS_CARD in the
   JS and the markup, and nothing else changes. */
.analysis-h {
  margin-top: 10px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: #FFE8CF;
}

.peek-sub {
  font-size: 12px;
  color: var(--scene-muted);
  margin: -2px 0 6px;
}

.analysis-card {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(760px, calc(100% - 32px));
  padding: 16px 18px 18px;
  border-radius: var(--radius-lg);
  background: rgba(20, 13, 9, 0.96);
  border: 1px solid rgba(226, 176, 130, 0.4);
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.6);
  z-index: 40;
  /* The card grew past the frame on a short window. It scrolls rather than
     spilling off the top, where the title would go missing. */
  max-height: calc(100% - 24px);
  overflow-y: auto;
}

.analysis-card[hidden] { display: none; }

.analysis-title {
  font-size: 17px;
  font-weight: 700;
  color: #FFE8CF;
  line-height: 1.2;
}

.analysis-sub {
  margin-top: 2px;
  font-size: 12px;
  color: var(--scene-muted);
}

.analysis-plot {
  display: block;
  width: 100%;
  height: auto;
  margin: 12px 0 8px;
  border-radius: var(--radius-md);
  background: rgba(10, 7, 5, 0.7);
}

/* The numbers live in the DOM, not in the picture, so they can be read by a
   screen reader and scale with the browser's text size. */
.analysis-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  margin-top: 2px;
}

.analysis-cap {
  caption-side: top;
  text-align: left;
  font-size: 12px;
  color: var(--scene-muted);
  padding-bottom: 6px;
}

.analysis-table th,
.analysis-table td {
  text-align: right;
  padding: 3px 0;
  border-bottom: 1px solid rgba(226, 176, 130, 0.14);
}

.analysis-table th:first-child,
.analysis-table td:first-child {
  text-align: left;
  color: var(--scene-muted);
}

.analysis-table thead th {
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.analysis-table thead th:nth-child(2) { color: #FFB27A; }
.analysis-table thead th:nth-child(3) { color: #8FD0F0; }
.analysis-table td { color: #FFE8CF; font-variant-numeric: tabular-nums; }
.analysis-table tbody tr.is-gap td { color: #FFD166; }

.analysis-note {
  margin-top: 8px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--scene-muted);
}

.analysis-howto {
  margin-top: 8px;
  font-size: 12px;
  line-height: 1.45;
  color: #FFE8CF;
}

.analysis-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 12px;
}

/* .cmd-btn starts invisible and is faded in by morphBtn, which never runs for
   this one. It is shown outright, and sized to its label rather than stretched. */
.analysis-store {
  opacity: 1;
  transform: none;
  width: auto;
  min-width: 132px;
  padding: 0 20px;
  height: 40px;
  align-items: center;
  justify-content: center;
}

@media (max-width: 620px) {
  .analysis-card { padding: 12px 12px 14px; }
  .analysis-title { font-size: 15px; }
}

/* Says what the Earth rock is, next to the column that names it. */
.analysis-earth {
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.4;
  color: #8FD0F0;
}

/* Peak markers and the one tooltip they share. */
.analysis-figure { position: relative; }

.analysis-spots {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* The height of each peak, printed on it. */
.analysis-pct {
  position: absolute;
  transform: translate(-50%, -140%);
  padding: 0 3px;
  border-radius: 3px;
  background: rgba(12, 8, 5, 0.6);
  color: #FFE8CF;
  font: 600 12px Roboto, sans-serif;
  white-space: nowrap;
}

.analysis-tip {
  position: absolute;
  /* Above everything it can be summoned from: the card is 40, the peek 38, the
     expanding tile 30. It used to be 5, from when it lived inside the card. */
  z-index: 60;
  max-width: 300px;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  background: rgba(12, 8, 5, 0.97);
  border: 1px solid rgba(226, 176, 130, 0.45);
  font-size: 12px;
  line-height: 1.4;
  color: #FFE8CF;
  pointer-events: none;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5);
}

.analysis-tip[hidden] { display: none; }

.analysis-table th[data-tip] {
  cursor: help;
  text-decoration: underline dotted rgba(226, 176, 130, 0.6);
  text-underline-offset: 3px;
}

/* Names lifted out of the canvas so they can be read, hovered and translated. */
.analysis-name,
.analysis-panel {
  position: absolute;
  /* Angled, so a long mineral name can sit near its neighbour without
     overlapping it. The leader drawn on the canvas says which peak it means. */
  transform: translate(-50%, -50%) rotate(-24deg);
  padding: 1px 5px;
  border: 0;
  border-radius: 4px;
  background: rgba(12, 8, 5, 0.55);
  color: #FFE8CF;
  font: 600 12px Roboto, sans-serif;
  cursor: help;
  pointer-events: auto;
  white-space: nowrap;
}

.analysis-panel {
  transform: translate(0, -50%);
  font-weight: 700;
  font-size: 13px;
}

.analysis-name:hover, .analysis-name:focus-visible,
.analysis-panel:hover, .analysis-panel:focus-visible {
  background: rgba(255, 209, 102, 0.28);
}

.analysis-term {
  cursor: help;
  text-decoration: underline dotted rgba(226, 176, 130, 0.6);
  text-underline-offset: 3px;
}

/* Axis titles, lifted out of the canvas so each can explain itself. */
.analysis-axis {
  position: absolute;
  padding: 1px 5px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: #FFD9B8;
  font: 600 12px Roboto, sans-serif;
  cursor: help;
  pointer-events: auto;
  white-space: nowrap;
  text-decoration: underline dotted rgba(226, 176, 130, 0.55);
  text-underline-offset: 3px;
}

.analysis-axis-x { transform: translate(-50%, -50%); }
.analysis-axis-y { transform: translate(-50%, -50%) rotate(-90deg); }

.analysis-axis:hover,
.analysis-axis:focus-visible { background: rgba(255, 209, 102, 0.24); }


/* The rock itself, beside the trace it produced. */
.analysis-photos {
  display: flex;
  gap: 12px;
  margin-bottom: 8px;
}

.analysis-plotwrap { position: relative; }

.analysis-photo {
  flex: 1;
  min-width: 0;
  margin: 0;
  padding: 3px;
  border: 2px dashed currentColor;
  border-radius: 6px;
  background: rgba(12, 8, 5, 0.55);
  pointer-events: auto;
}

.analysis-photo img {
  display: block;
  width: 100%;
  height: 132px;
  object-fit: cover;
  border-radius: 3px;
}

.analysis-photo figcaption {
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.25;
  color: #FFE8CF;
}

.analysis-photo.has-note { cursor: help; }

.analysis-photo.has-note figcaption::after {
  content: ' \2139';
  color: #FFD166;
}

.analysis-photo.has-note:hover,
.analysis-photo.has-note:focus-visible { background: rgba(255, 209, 102, 0.2); }

.analysis-tip img {
  display: block;
  width: 100%;
  height: 150px;
  object-fit: cover;
  border-radius: 4px;
  margin-bottom: 6px;
}

/* ── The peek ──
   What came back, at a glance, sitting where the downlink strip reported it.
   Small on purpose: the reason to open the full card is the Earth rock, and
   nothing about Earth appears here. */
.peek {
  position: absolute;
  left: 50%;
  bottom: 96px;
  width: 340px;
  padding: 10px 12px 12px;
  border-radius: var(--radius-lg);
  background: rgba(20, 13, 9, 0.96);
  border: 1px solid rgba(226, 176, 130, 0.4);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
  z-index: 38;
  transform: translateX(-50%);
  transform-origin: 50% 100%;
}

.peek[hidden] { display: none; }

.peek.is-in {
  animation: peek-grow 0.34s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}

@keyframes peek-grow {
  from { opacity: 0; transform: translateX(-50%) translateY(14px) scale(0.72); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .peek.is-in { animation: none; }
}

.peek-title {
  font-size: 12px;
  font-weight: 600;
  color: #FFE8CF;
  margin-bottom: 6px;
}

.peek-row {
  display: flex;
  gap: 8px;
  align-items: stretch;
}

.peek-photo {
  width: 96px;
  height: 75px;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid rgba(226, 176, 130, 0.35);
}

.peek-plot {
  flex: 1;
  height: 75px;
  border-radius: 4px;
  background: rgba(10, 7, 5, 0.72);
}

.peek-actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.peek-btn {
  flex: 1;
  opacity: 1;
  transform: none;
  min-height: 38px;
  padding: 0 10px;
  font-size: 13px;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.peek-more {
  background: rgba(226, 176, 130, 0.16);
  border-color: rgba(226, 176, 130, 0.5);
  color: #FFE8CF;
}

.peek-more:hover:not(:disabled) { background: rgba(226, 176, 130, 0.28); }


/* The card is told how tall it may be, and scrolls inside that. */
.analysis-card {
  scrollbar-width: thin;
  scrollbar-color: rgba(226, 176, 130, 0.5) transparent;
}

.analysis-card::-webkit-scrollbar { width: 10px; }
.analysis-card::-webkit-scrollbar-track { background: transparent; }

.analysis-card::-webkit-scrollbar-thumb {
  background: rgba(226, 176, 130, 0.45);
  border-radius: 6px;
  border: 3px solid transparent;
  background-clip: content-box;
}

.analysis-card::-webkit-scrollbar-thumb:hover { background-color: rgba(226, 176, 130, 0.7); }

/* A subheading under a section title. */
.analysis-sub2 {
  margin-top: 1px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--scene-muted);
}

/* A percentage on a tall peak would sit in the row of names above the plot, so
   it drops inside the plot instead. */
.analysis-pct.is-high { transform: translate(-50%, 30%); }

/* The action only takes permanent vertical space when the card cannot show it.
   When everything fits, it scrolls with the rest. */
.analysis-card.is-scrolling .analysis-actions {
  position: sticky;
  bottom: -18px;
  /* Bleeding to the card edge with negative side margins overshot into the
     scrollbar and made the panel scroll sideways as well as down. It stays
     inside the content box. */
  margin: 12px 0 -18px;
  padding: 10px 0 18px;
  background: linear-gradient(rgba(20, 13, 9, 0), rgba(20, 13, 9, 0.99) 46%);
  border-top: 1px solid rgba(226, 176, 130, 0.16);
}

/* Reset confirmation. Follows the deep_space pattern: reset asks what to do
   with rows already stored rather than discarding a mission's work silently. */
#reset-dialog {
  max-width: 400px;
  padding: 18px 20px 20px;
  border: 1px solid rgba(226, 176, 130, 0.4);
  border-radius: var(--radius-lg);
  background: rgba(20, 13, 9, 0.98);
  color: var(--scene-ink);
}

#reset-dialog::backdrop { background: rgba(0, 0, 0, 0.6); }

#reset-dialog h2 {
  margin-bottom: 8px;
  font-size: 16px;
  font-weight: 700;
  color: #FFE8CF;
}

#reset-dialog p {
  margin-bottom: 16px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--scene-muted);
}

.reset-dialog-controls {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

.reset-btn {
  opacity: 1;
  transform: none;
  min-height: 38px;
  padding: 0 16px;
  align-items: center;
  justify-content: center;
}

.reset-btn-secondary {
  background: transparent;
  border-color: rgba(226, 176, 130, 0.45);
  color: var(--scene-muted);
}

.reset-btn-secondary:hover:not(:disabled) { background: rgba(226, 176, 130, 0.14); }

/* Attention cue. Fires when a click cannot do anything more and the control
   that can is elsewhere on screen. Two beats and done, and it stops being
   offered once the control has been used. */
@keyframes attn-nudge {
  0%, 100% { transform: translateY(0) scale(1); }
  15%      { transform: translateY(-3px) scale(1.035); }
  30%      { transform: translateY(0) scale(1); }
  45%      { transform: translateY(-3px) scale(1.035); }
  60%      { transform: translateY(0) scale(1); }
}

@keyframes attn-glow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 209, 102, 0); }
  30%      { box-shadow: 0 0 0 7px rgba(255, 209, 102, 0.42); }
  60%      { box-shadow: 0 0 0 0 rgba(255, 209, 102, 0); }
}

.attn {
  animation: attn-nudge 1.1s ease-in-out, attn-glow 1.1s ease-in-out;
  border-color: var(--focus-glow) !important;
}

/* Movement is the part some people cannot use. The ring still says where. */
@media (prefers-reduced-motion: reduce) {
  .attn { animation: attn-glow 1.1s ease-in-out; }
}

/* Reflow (1.4.10): at a 320px viewport the figure was six pixels wider than the
   card, which made the panel scroll sideways as well as down. Nothing in here
   may exceed its container. */
.analysis-figure,
.analysis-photos,
.analysis-photo,
.analysis-plotwrap {
  min-width: 0;
  max-width: 100%;
  box-sizing: border-box;
}

.analysis-plot { max-width: 100%; }

.analysis-table { table-layout: fixed; }

.analysis-table th,
.analysis-table td { overflow-wrap: anywhere; }

/* The column explanations are keyboard-reachable, so they need a focus ring. */
.analysis-table th:focus-visible,
.analysis-term:focus-visible,
#site-age:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px rgba(12, 8, 5, 0.62);
}
