/* 
INTERFACE-WRAPPER 
*/

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

body {
  font-family: monospace;
  background: #000000;
  /* Exactly the viewport, never more: the settings panel is taller than the screen, and with
     an auto height the body grew to fit it, so scrolling the panel scrolled the 3D scene too.
     The panel scrolls inside itself instead (see .interface). */
  height: 100vh;
  overflow: hidden;
  padding: 20px;
  font-size: 14px;
  line-height: 1.6;
  color: white;
  display: flex;
}

.interface {
  flex: 1;
  position: relative;
  transition: flex 0.3s ease, width 0.3s ease, padding 0.3s ease, opacity 0.3s ease;
  /* Its own scroll container. `overflow: hidden` here used to clip nothing, because the
     element was as tall as its content; what actually moved was the page. */
  overflow-y: auto;
  overflow-x: hidden;
  /* Keep the wheel inside the panel once it hits an end, rather than handing the scroll on. */
  overscroll-behavior: contain;
}

.interface.collapsed {
  flex: 0 0 0px;
  padding: 0;
  opacity: 0;
  pointer-events: none;
  overflow: hidden;
}

.interface.collapsed .container {
  display: none;
}

.interface-toggle {
  position: fixed;
  top: 10px;
  left: 10px;
  z-index: 1000;
  background: rgba(30, 30, 30, 0.9);
  color: white;
  border: 1px solid #555;
  border-radius: 5px;
  width: 36px;
  height: 36px;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s;
}

.interface-toggle:hover {
  background: rgba(60, 60, 60, 0.9);
}

.container {
  max-width: 1000px;
  margin: 0 auto;
  background: rgba(20, 20, 20, 0.95);
  border-radius: 10px;
  box-shadow: 0 0 30px rgba(0, 123, 255, 0.3);
  padding: 30px;
  border: 1px solid #444;
}

.header {
  margin-bottom: 30px;
  padding-bottom: 20px;
  border-bottom: 1px solid #444;
}

.python-link {
  display: inline-block;
  padding: 12px 24px;
  background: #007bff;
  color: white;
  text-decoration: none;
  border-radius: 5px;
  transition: all 0.3s;
  margin-bottom: 20px;
  font-weight: normal;
  font-size: 14px;
  border: 1px solid #0056b3;
}

.python-link:hover {
  background: #0056b3;
}

.data-source {
  background: rgba(30, 30, 30, 0.9);
  padding: 20px;
  border-radius: 10px;
  margin-bottom: 20px;
  border: 1px solid #444;
}

.data-source h3 {
  margin-bottom: 15px;
  color: #ccc;
  font-weight: normal;
  font-size: 16px;
}

.radio-group {
  margin-bottom: 15px;
}

.radio-group label {
  display: block;
  margin-bottom: 10px;
  cursor: pointer;
  color: white;
  transition: color 0.3s;
  font-size: 14px;
}

.radio-group label:hover {
  color: #aaa;
}

.radio-group input[type="radio"] {
  margin-right: 10px;
}

.file-input-group {
  margin-top: 10px;
}

.file-input-group input[type="file"] {
  width: 100%;
  padding: 10px;
  border: 1px solid #555;
  border-radius: 5px;
  background: #222;
  color: white;
  cursor: pointer;
  font-family: monospace;
}

.section {
  margin-bottom: 30px;
  padding: 24px;
  background: rgba(30, 30, 30, 0.9);
  border-radius: 10px;
  border: 1px solid #444;
}

.section h2 {
  color: white;
  margin-bottom: 20px;
  font-size: 18px;
  font-weight: normal;
}

.form-group {
  margin-bottom: 20px;
}

.form-group label {
  display: block;
  margin-bottom: 8px;
  font-weight: normal;
  color: #ccc;
  font-size: 14px;
}

.form-group select,
.form-group input[type="number"],
.form-group input[type="text"] {
  width: 100%;
  padding: 10px;
  border: 1px solid #555;
  border-radius: 5px;
  font-size: 14px;
  transition: all 0.3s;
  background: #222;
  color: white;
  font-family: monospace;
}

.form-group select:focus,
.form-group input[type="number"]:focus,
.form-group input[type="text"]:focus {
  outline: none;
  border-color: #007bff;
  background: #2a2a2a;
}

.form-group select option {
  background: #222;
  color: white;
}

#frameStepMode { margin-bottom: 8px; }

/* Frame Step in Automatic mode. The field is a live readout of the zoom rather than something
   to type in, so it is styled as text: dashed border, muted ink, no text cursor. */
.form-group input[type="number"].is-derived {
  background: #1b1b1b;
  border-style: dashed;
  color: var(--pv-ink-mute);
  cursor: default;
}

.pickr-form-item {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin: 4px 6px;
}

.pickr-form-item label {
  font-size: 12px;
  color: #ccc;
  text-align: center;
  white-space: nowrap;
}

.axis-group {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 15px;
  margin-top: 15px;
}

.axis-item {
  background: #222;
  padding: 15px;
  border-radius: 5px;
  border: 1px solid #555;
  min-width: 0;
}

.axis-item label {
  display: block;
  font-size: 12px;
  text-transform: uppercase;
  color: #888;
  margin-bottom: 8px;
  white-space: normal;
  word-break: break-word;
}

.axis-item input,
.axis-item select {
  width: 100%;
}

.dim-axis-group.two-col {
  grid-template-columns: 1fr 1fr !important;
}

.slider-with-number {
  display: flex;
  align-items: center;
  gap: 10px;
}

.slider-with-number input[type="range"] {
  flex: 1;
}

.slider-with-number input[type="number"] {
  width: 70px;
  flex: none;
  padding: 6px;
  border: 1px solid #555;
  border-radius: 5px;
  background: #222;
  color: #fff;
  font-size: 14px;
}

.hidden {
  display: none;
}

.custom-geometry-upload {
  margin-top: 15px;
  padding: 15px;
  background: #222;
  border-radius: 5px;
  border: 1px solid #555;
}

.checkbox-group {
  margin: 15px 0;
}

.checkbox-group label {
  display: flex;
  align-items: center;
  cursor: pointer;
  font-weight: normal;
  color: white;
  transition: color 0.3s;
  font-size: 14px;
}

.checkbox-group label:hover {
  color: #aaa;
}

.checkbox-group input[type="checkbox"] {
  margin-right: 10px;
  width: 18px;
  height: 18px;
  cursor: pointer;
}

.machine-topology-fields {
  background: #222;
  padding: 15px;
  border-radius: 5px;
  margin-top: 15px;
  border: 1px solid #555;
}

.advanced-button {
  background: #007bff;
  color: white;
  border: 1px solid #0056b3;
  padding: 12px 24px;
  border-radius: 5px;
  cursor: pointer;
  margin-top: 15px;
  transition: all 0.3s;
  font-weight: normal;
  font-family: monospace;
  font-size: 14px;
}

.advanced-button:hover {
  background: #0056b3;
}

.projection-fields {
  background: #222;
  padding: 15px;
  border-radius: 5px;
  margin-top: 15px;
  border: 1px solid #555;
}

.projection-item {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 15px;
  margin-bottom: 10px;
  padding: 12px;
  background: #2a2a2a;
  border-radius: 5px;
  border: 1px solid #444;
}

.dual-view-container {
  display: grid;
  /* One column, so the two metric panels stack. Side by side they each got half of an
     already-narrow panel, which left the ramp editors and swatch rows inside them cramped. */
  grid-template-columns: 1fr;
  gap: 14px;
  margin-top: 15px;
}

.metric-panel {
  background: #222;
  padding: 15px;
  border-radius: 5px;
  border: 1px solid #555;
}

.rgba-input {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  margin-top: 10px;
}

.rgba-input input {
  padding: 8px;
  border: 1px solid #555;
  border-radius: 5px;
  background: #222;
  color: white;
  transition: all 0.3s;
  font-family: monospace;
  font-size: 14px;
}

.rgba-input input:focus {
  outline: none;
  border-color: #007bff;
}

.color-inputs {
  margin-top: 15px;
}

.color-input-item {
  margin-bottom: 15px;
  padding: 12px;
  background: #2a2a2a;
  border-radius: 5px;
  border: 1px solid #444;
}

.color-input-item label {
  color: #888;
  font-size: 12px;
  margin-bottom: 8px;
  display: block;
}

.hover-options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-top: 10px;
}

.hover-options label {
  color: white;
  font-weight: normal;
  font-size: 14px;
  display: flex;
  align-items: center;
  cursor: pointer;
  transition: color 0.3s;
}

.hover-options label:hover {
  color: #aaa;
}

.hover-options input[type="checkbox"] {
  margin-right: 8px;
}

.time-boundaries {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 15px;
  margin-top: 10px;
}

.boundary-item {
  display: flex;
  align-items: center;
  gap: 10px;
  background: #222;
  padding: 12px;
  border-radius: 5px;
  border: 1px solid #555;
}

.boundary-item label {
  color: #ccc;
  font-size: 14px;
  white-space: nowrap;
}

.boundary-item input[type="number"] {
  flex: 1;
  background: #2a2a2a;
  border: 1px solid #555;
  color: white;
}

.boundary-item input[type="checkbox"] {
  margin: 0;
}

.number-spinner {
  display: flex;
  align-items: center;
  gap: 5px;
}

.spinner-btn {
  background: #007bff;
  color: white;
  border: 1px solid #0056b3;
  width: 32px;
  height: 32px;
  border-radius: 5px;
  cursor: pointer;
  font-size: 16px;
  font-weight: bold;
  transition: all 0.3s;
  font-family: monospace;
}

.spinner-btn:hover {
  background: #0056b3;
}

.spinner-btn:active {
  transform: scale(0.95);
}

/* Scrollbar styling */
::-webkit-scrollbar {
  width: 10px;
}

::-webkit-scrollbar-track {
  background: #222;
}

::-webkit-scrollbar-thumb {
  background: #555;
  border-radius: 5px;
}

::-webkit-scrollbar-thumb:hover {
  background: #666;
}

/* Input number spinner buttons */
input[type="number"] {
  -moz-appearance: textfield;
}

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  opacity: 1;
}

/* Tooltip styles */
.tooltip-icon {
  display: inline-block;
  width: 16px;
  height: 16px;
  background: #555;
  color: white;
  border-radius: 50%;
  text-align: center;
  line-height: 16px;
  font-size: 12px;
  margin-left: 5px;
  cursor: help;
  position: relative;
}

.tooltip-icon:hover::after {
  content: attr(data-tooltip);
  position: absolute;
  left: 20px;
  top: -5px;
  background: rgba(40, 40, 40, 0.95);
  color: white;
  padding: 8px 12px;
  border-radius: 5px;
  border: 1px solid #666;
  white-space: nowrap;
  z-index: 1000;
  font-size: 12px;
  font-weight: normal;
}

.label-with-tooltip {
  display: flex;
  align-items: center;
}

.cutoff-item {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 10px;
  padding: 10px;
  background: #2a2a2a;
  border-radius: 5px;
}



/* 
VIZUALIZATION-WRAPPER 
*/

.viz-wrapper {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  /* The body's own content box, which is 100vh minus its padding. At 100vh the scene hung
     40px past the bottom of the window and the page scrolled even with the panel closed. */
  height: 100%;
  overflow: hidden;
  background-color: #000;
  color: white;
  flex: 1;
}

/* The wrapper is a column now: scene on top, timeline band underneath. The scene is a flex
   item rather than an absolutely-positioned fill, so the band takes real space from it instead
   of covering it. */
.renderer-container {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
}

.ui-panel {
  position: absolute;
  padding: 10px;
  background: rgba(20, 20, 20, 0.8);
  border-radius: 5px;
  font-size: 16px;
  z-index: 10;
}

/* The readout stack down the left edge. Absolutely placed once, as a column, so the panels
   inside it flow: switching one off closes the gap rather than leaving a hole, which fixed
   positions could not do once any of them became optional. */
#hud-left {
  position: absolute;
  z-index: 2;      /* same reason as #controls-panel: never hidden by a stage-mode timeline */
  top: 10px;
  left: 10px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  max-width: 300px;
  /* Taller than the window would otherwise push the legend off the bottom. */
  max-height: calc(100% - 20px);
  overflow: hidden;
}
#hud-left .ui-panel {
  position: static;
  max-width: 100%;
}

#legend-panel-right {
  max-width: 260px;
}

#legend-panel-right {
  top: 60px;
  right: 10px;
}

.legend-panel {
  font-size: 13px;
}

/* Same stacked-checkbox treatment as the hover options, so the two groups in step 4 read as
   one kind of control. */
/* A control the Vampir metric has taken over: still readable, visibly not yours to set. */
.checkbox-group label.is-disabled { opacity: 0.45; cursor: not-allowed; }

.readout-options { display: flex; flex-direction: column; gap: 6px; }
.readout-options label {
  display: flex; align-items: center; gap: 8px; font-size: 12px; cursor: pointer;
}

.legend-title {
  font-weight: bold;
  margin-bottom: 6px;
}

.legend-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 4px 0;
}

.legend-swatch {
  width: 14px;
  height: 14px;
  border-radius: 3px;
  flex: 0 0 auto;
  border: 1px solid rgba(255, 255, 255, 0.3);
}

#controls-panel {
  /* Above a stage-mode timeline: the playback controls stay usable whatever is behind them. */
  z-index: 2;
  /* Sits above the timeline band and its splitter, not on top of them. --strip-total covers
     both and is 0 while the band is hidden. */
  bottom: calc(var(--strip-total, 0px) + 10px);
  width: calc(100% - 40px);
  left: 10px;
}

#uploader {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: rgba(30, 30, 30, 0.9);
  padding: 25px;
  border-radius: 10px;
  border: 1px solid #444;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 15px;
  z-index: 10;
}

.file-input-label {
  cursor: pointer;
  background: #333;
  padding: 10px 15px;
  border-radius: 5px;
  border: 1px solid #555;
  display: inline-block;
}

.file-input-label:hover {
  background: #444;
}

.input-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.dim-group {
  display: flex;
  align-items: center;
  gap: 5px;
}

.dim-group>span {
  color: #888;
}

.input-label {
  font-size: 14px;
  color: #ccc;
}

.text-input {
  background: #222;
  color: white;
  border: 1px solid #555;
  border-radius: 5px;
  padding: 8px;
  font-family: monospace;
  font-size: 16px;
  width: 80px;
  text-align: center;
}

input[type='file'] {
  display: none;
}

#visualize-btn {
  background: #007bff;
  color: white;
  border: none;
  padding: 12px;
  border-radius: 5px;
  font-size: 16px;
  cursor: pointer;
}

#visualize-btn:hover {
  background: #0056b3;
}

#visualize-btn:disabled {
  background: #555;
  cursor: not-allowed;
}

#timeline-container {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
}

#play-pause, #prev-frame, #next-frame {
  padding: 8px 12px;
  cursor: pointer;
  background: #333;
  border: 1px solid #555;
  border-radius: 5px;
  color: white;
}

#prev-frame, #next-frame {
  padding: 8px 10px;
}

#slider {
  width: 100%;
}

#timeline-time-display {
  font-family: monospace;
  font-size: 12px;
  color: #ccc;
  white-space: nowrap;
  flex: none;
}

#record-btn {
  padding: 8px 12px;
  cursor: pointer;
  background: #333;
  border: 1px solid #555;
  border-radius: 5px;
  color: white;
  white-space: nowrap;
}

#record-btn.recording-active {
  background: #c0392b;
  border-color: #e74c3c;
}

/* Only visible while a region is selected on the timeline — tinted to match the selection
   flags drawn on the HUD, so the two read as the same thing. */
#clear-selection {
  padding: 8px 12px;
  cursor: pointer;
  background: #1d3a57;
  border: 1px solid #4aa3ff;
  border-radius: 5px;
  color: #cfe6ff;
  white-space: nowrap;
  font-family: monospace;
}

#clear-selection:hover {
  background: #27506f;
}

#recording-indicator {
  color: #ff4d4d;
  font-weight: bold;
  font-family: monospace;
  animation: blink 1s step-start infinite;
}

@keyframes blink {
  50% { opacity: 0; }
}

.filename {
  font-style: italic;
  color: #aaa;
  font-size: 12px;
  height: 14px;
  margin-top: 5px;
}

.error-message {
  color: #ff6b6b;
}

.hidden {
  display: none !important;
}

/* @import "https://cdn.jsdelivr.net/npm/pickr-widget/dist/pickr.min.css";
        @import '@simonwep/pickr/dist/themes/nano.min.css';
*/


/* 
VAMPIR-TIMELINE 
*/

vampir-timeline {
  background-color: #1a1a2e;
  font-family: monospace;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 100vh;
  padding: 20px;
}

h1 {
  color: #eee;
  margin-bottom: 20px;
}

#canvas-container {
  border: 2px solid #444;
  border-radius: 8px;
  overflow: hidden;
}

#controls {
  margin-top: 20px;
  display: flex;
  gap: 15px;
  align-items: center;
}

button {
  padding: 10px 20px;
  font-family: monospace;
  font-size: 14px;
  cursor: pointer;
  background: #333;
  color: white;
  border: 1px solid #555;
  border-radius: 5px;
  transition: background 0.2s;
}

button:hover {
  background: #444;
}

#timeline-slider {
  width: 300px;
}

.info {
  color: #888;
  margin-top: 15px;
  font-size: 12px;
}
/* ============================================================================================
   Selection panel — numbered step accordion (layout proposal A)

   Appended rather than woven in: everything above still styles the *controls* (.form-group,
   .axis-group, .checkbox-group, …) and is reused as-is. What changes here is the chrome around
   them — the panel is now a fixed-width column of four numbered steps with its own head and
   footer, instead of a stack of cards in a centred container.
   ============================================================================================ */

:root {
  --pv-panel:     #14171c;
  --pv-raised:    #1b1f26;
  --pv-raised-hi: #222731;
  --pv-line:      #2b313a;
  --pv-line-soft: #21262e;
  --pv-ink:       #e9edf2;
  --pv-ink-mute:  #99a3af;
  --pv-ink-faint: #6b7480;
  --pv-accent:    #4aa3ff;
  --pv-accent-dim:#1d4f80;
  --pv-r:   10px;
  --pv-r-s: 7px;
  --pv-ui: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --pv-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;

  /* Native controls — checkboxes, radios, dropdown popups, scrollbars — are painted by the
     browser from this. Without it they keep light-mode defaults on a dark page: the hybrid-view
     checkbox computed black instead of white, and scrollbars came out pale. */
  color-scheme: dark;
}

/* The legacy base above this block sets a monospace, 20px-padded, pure-black page. The padding
   put a black gutter around the whole app and the font made every piece of chrome monospace.
   Overridden here rather than edited in place, so the original rule still documents what the
   page used to be. */
body {
  font-family: var(--pv-ui);
  padding: 0;
  background: #0b0d10;
}

/* …but the readouts stay monospace on purpose: they are numbers that change every frame, and
   proportional digits make them jitter. This is the rule the body font used to provide by
   accident, now stated deliberately. */
.ui-panel, #rank-hover-tooltip, #clock,
#detail-status, #detail-warning, #loading-status { font-family: monospace; }

/* A fixed column, not half the window: the scene is the point, and the panel only has to be
   wide enough for one step's controls. */
.interface {
  flex: 0 0 420px;
  background: var(--pv-panel);
  border-right: 1px solid var(--pv-line);
  /* The panel itself no longer scrolls — .panel-steps does, so the head and the Visualize
     button stay put while the steps move under them. */
  overflow: hidden;
}
.interface.collapsed { flex: 0 0 0px; border-right: 0; }

/* Retract control. Sits above the panel at a fixed spot so it is in the same place whether the
   panel is open or gone. */
.interface-toggle {
  background: var(--pv-raised);
  border: 1px solid var(--pv-line);
  border-radius: var(--pv-r-s);
  color: var(--pv-ink);
  font-size: 15px;
  width: 34px;
  height: 32px;
}
.interface-toggle:hover { background: var(--pv-raised-hi); }
.interface-toggle[aria-expanded="false"] { border-color: var(--pv-accent); color: var(--pv-accent); }

.container {
  max-width: none;
  margin: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  font-family: var(--pv-ui);
}

.panel-head {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 10px;
  /* Left padding clears the fixed retract button, which sits at left:10px and is 34px wide, so
     the brand lands immediately to its right on the same row rather than below it. */
  padding: 10px 16px 10px 54px;
  border-bottom: 1px solid var(--pv-line-soft);
}
.panel-logo { width: 28px; height: 28px; border-radius: 8px; flex: 0 0 auto;
              background: linear-gradient(145deg, var(--pv-accent), #2b6fb3); }
.panel-brand { display: flex; flex-direction: column; line-height: 1.2; }
.pb-name { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; color: var(--pv-ink); }
.pb-sub  { font-size: 11px; color: var(--pv-ink-faint); }

.panel-steps { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }

.panel-foot { flex: 0 0 auto; padding: 13px 16px; border-top: 1px solid var(--pv-line); }
#visualizeButton,
#visualizeAgainButton {
  width: 100%;
  background: var(--pv-accent);
  color: #05203a;
  border: 1px solid var(--pv-accent);
  border-radius: var(--pv-r-s);
  padding: 11px;
  font: 700 13.5px/1 var(--pv-ui);
  cursor: pointer;
  transition: background .15s;
}
#visualizeButton:hover,
#visualizeAgainButton:hover { background: #63b1ff; }

/* ---- a step --------------------------------------------------------------------------- */
.step { border-bottom: 1px solid var(--pv-line-soft); }
.step-head {
  width: 100%; background: none; border: 0; text-align: left; cursor: pointer;
  display: flex; align-items: center; gap: 11px; padding: 13px 16px;
  font-family: var(--pv-ui); color: var(--pv-ink);
}
.step-head:hover { background: #ffffff06; }
.step .num {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center; font-size: 12px; font-weight: 700;
  background: var(--pv-raised); color: var(--pv-ink-faint); border: 1px solid var(--pv-line);
}
.step.open .num, .step.done .num {
  background: var(--pv-accent); color: #05203a; border-color: var(--pv-accent);
}
/* Stacked, not inline: a title and its answer run together on one line read as one sentence. */
.step-head .txt { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.3; }
.step-title { font-size: 13.5px; font-weight: 600; }
/* What a collapsed step chose — the thing that makes an accordion readable without opening it */
.step-sum {
  font-size: 11.5px; font-weight: 700; color: var(--pv-accent); font-family: var(--pv-mono);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.step.open .step-sum { display: none; }
.chev { color: var(--pv-ink-faint); font-size: 11px; transition: transform .18s; }
.step.open .chev { transform: rotate(90deg); }

.step-body { display: none; padding: 2px 16px 20px; }
.step.open .step-body { display: block; }

/* Steps own the spacing now, so the old card chrome on these is dead weight. */
.step-body .section,
.step-body .data-source { background: none; border: 0; padding: 0; margin: 0; border-radius: 0; }
.step-body .form-group { margin-bottom: 14px; }

.step-note { margin: 0 0 12px; font-size: 12.5px; line-height: 1.45; color: var(--pv-ink-mute); }

/* ---- step 1: source branch + converter downloads ---------------------------------------- */
/* The radios keep their name and values — the JS reads them — and only look like a segmented
   control. */
.radio-group { display: flex; gap: 4px; margin-bottom: 14px;
               background: var(--pv-raised); border: 1px solid var(--pv-line);
               border-radius: var(--pv-r-s); padding: 3px; }
.radio-group label {
  flex: 1; margin: 0; text-align: center; padding: 7px 8px; border-radius: 5px;
  font-size: 12.5px; color: var(--pv-ink-mute); transition: background .14s, color .14s;
}
.radio-group label:hover { color: var(--pv-ink); background: var(--pv-raised-hi); }
.radio-group label:has(input:checked) { background: var(--pv-accent); color: #05203a; font-weight: 700; }
.radio-group input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }

.script-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 10px; }
.script-card {
  display: flex; flex-direction: column; gap: 3px;
  padding: 10px 11px; border-radius: var(--pv-r-s);
  background: var(--pv-raised); border: 1px solid var(--pv-line);
  text-decoration: none; color: var(--pv-ink);
}
.script-card:hover { background: var(--pv-raised-hi); border-color: var(--pv-accent); }
.script-card .badge { align-self: flex-start; font-size: 10px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; padding: 2px 7px; border-radius: 99px;
  background: var(--pv-accent-dim); color: #cfe6ff; }
.script-card .sc-name { font-family: var(--pv-mono); font-size: 12px; font-weight: 600; }
.script-card .sc-note { font-size: 11px; color: var(--pv-ink-faint); line-height: 1.35; }
.script-card .sc-dl   { font-size: 11.5px; color: var(--pv-accent); }

/* Wrapped rather than scrolled: at 420px the command is wider than the panel, and a
   horizontal scrollbar inside a vertical one is a poor trade for one line of text. */
.cmd { margin: 0 0 12px; padding: 9px 11px; white-space: pre-wrap; word-break: break-word;
       background: #0a0c0f; border: 1px solid var(--pv-line-soft); border-radius: var(--pv-r-s);
       font: 11.5px/1.5 monospace; color: #9fd0ff; }

/* ---- step 2: geometry family + cards ----------------------------------------------------- */
/* The cards drive the <select id="geometryType"> below them, which stays in the DOM as the
   authoritative control so every existing read of it keeps working. */
.geom-family { display: inline-flex; background: var(--pv-raised); border: 1px solid var(--pv-line);
               border-radius: var(--pv-r-s); padding: 3px; gap: 3px; margin-bottom: 10px; }
.geom-family button { background: none; border: 0; border-radius: 5px; padding: 6px 14px;
                      font: 12.5px var(--pv-ui); color: var(--pv-ink-mute); cursor: pointer; }
.geom-family button[aria-pressed="true"] { background: var(--pv-accent); color: #05203a; font-weight: 700; }
.geom-family button:hover:not([aria-pressed="true"]) { color: var(--pv-ink); }

.geom-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.geom-card {
  display: flex; flex-direction: column; gap: 2px; text-align: left; cursor: pointer;
  padding: 10px 12px; border-radius: var(--pv-r-s);
  background: var(--pv-raised); border: 1px solid var(--pv-line); color: var(--pv-ink);
  /* Set explicitly because the secondary-button rule below excludes .geom-card, which left it
     on the UA default of 13.33px/400 rather than the panel's type scale. */
  font: 550 13px/1.4 var(--pv-ui);
}
.geom-card b { font-size: 13px; font-weight: 550; }
.geom-card i { font-size: 11.5px; font-style: normal; color: var(--pv-ink-faint); line-height: 1.35; }
.geom-card:hover { background: var(--pv-raised-hi); }
.geom-card[aria-pressed="true"] { border-color: var(--pv-accent);
  background: color-mix(in oklab, var(--pv-accent) 13%, var(--pv-raised)); }
.geom-card[aria-pressed="true"] i { color: var(--pv-ink-mute); }

/* Kept operable (not display:none) so it stays focusable and scriptable. */
.vis-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
}

/* ---- controls inside a step --------------------------------------------------------------
   The markup of every control is untouched; these rules only bring the older chrome
   (.axis-item cards, default selects, monospace buttons) in line with the step design. Scoped
   to .step-body so nothing outside the selection panel is affected. */

/* .axis-item label sets text-transform: uppercase and has the same specificity as this rule,
   so this one wins on size and colour but used to leave the shouting in place. */
.step-body label { font-size: 12.5px; color: var(--pv-ink-mute); text-transform: none; }
.step-body .label-with-tooltip label,
.step-body .form-group > label { margin-bottom: 5px; }

.step-body select,
.step-body input[type="number"],
.step-body input[type="text"] {
  width: 100%;
  background: var(--pv-raised);
  color: var(--pv-ink);
  border: 1px solid var(--pv-line);
  border-radius: var(--pv-r-s);
  padding: 7px 9px;
  font: 13px/1.3 var(--pv-ui);
  transition: border-color .14s;
}
.step-body input[type="number"] { font-family: var(--pv-mono); }
.step-body select {
  appearance: none; padding-right: 28px;
  background-image: linear-gradient(45deg, transparent 50%, var(--pv-ink-faint) 50%),
                    linear-gradient(135deg, var(--pv-ink-faint) 50%, transparent 50%);
  background-position: calc(100% - 15px) 52%, calc(100% - 10px) 52%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.step-body select option { background: var(--pv-raised); color: var(--pv-ink); }
.step-body select:hover,
.step-body input:hover { border-color: #39414c; }
.step-body select:focus-visible,
.step-body input:focus-visible,
.step-body button:focus-visible,
.interface-toggle:focus-visible,
.step-head:focus-visible { outline: 2px solid var(--pv-accent); outline-offset: 1px; }

/* An axis was a bordered card holding one field — far too much furniture at this width. */
.step-body .axis-item {
  background: none; border: 0; padding: 0; border-radius: 0;
}
.step-body .axis-group { gap: 10px; margin-top: 10px; }

.step-body .checkbox-group { margin: 10px 0; }
.step-body .checkbox-group label { font-size: 13px; color: var(--pv-ink); gap: 9px; }
.step-body .checkbox-group input[type="checkbox"] { width: 15px; height: 15px; accent-color: var(--pv-accent); }

/* Secondary buttons: Test display topology, Advanced Options, … */
/* Named, not blanket. This used to be `.step-body button:not(...)`, which at specificity
   (0,3,2) outranked every component that styles its own buttons — a selected .trace-card
   (0,2,0) was repainted back to the unselected look, and the ramp handles and +/- with it.
   Reaching for :not() chains to claw back the exceptions is how that happens; listing the two
   legacy buttons this was ever meant for does not. */
.step-body #testTopologyBtn,
.step-body .advanced-button {
  background: var(--pv-raised); color: var(--pv-ink);
  border: 1px solid var(--pv-line); border-radius: var(--pv-r-s);
  padding: 8px 12px; font: 12.5px var(--pv-ui); cursor: pointer;
  transition: background .14s;
}
.step-body #testTopologyBtn:hover,
.step-body .advanced-button:hover { background: var(--pv-raised-hi); }

/* Grouped sub-options (machine topology, traditional view, advanced) read as a nested block. */
.step-body .machine-topology-fields,
.step-body .projection-fields {
  border-left: 2px solid var(--pv-line);
  padding-left: 11px;
  margin: 10px 0;
}

.step-body .hover-options { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
.step-body .hover-options label { display: flex; align-items: center; gap: 7px; font-size: 12.5px;
                                  color: var(--pv-ink); padding: 3px 0; }
.step-body .hover-options input[type="checkbox"] { width: 14px; height: 14px; accent-color: var(--pv-accent); }

.step-body .file-input-label {
  display: block; text-align: center; cursor: pointer;
  padding: 14px; border: 1.5px dashed var(--pv-line); border-radius: var(--pv-r);
  background: #ffffff04; color: var(--pv-ink); font-size: 13px;
}
.step-body .file-input-label:hover { border-color: var(--pv-accent); }

.step-body #serverFileSelect {
  height: auto; padding: 4px;
  background-image: none;            /* it is a list box, not a dropdown — no arrow */
}
.step-body #serverFileSelect option { padding: 5px 7px; border-radius: 4px; }

.step-body .time-boundaries { display: grid; gap: 10px; }
.step-body .boundary-item { display: flex; align-items: center; gap: 8px; }
.step-body .boundary-item input[type="number"] { flex: 1; }
.step-body .boundary-item label { margin: 0; white-space: nowrap; display: flex; align-items: center; gap: 5px; }

.step-body .slider-with-number { display: flex; align-items: center; gap: 8px; }
.step-body .slider-with-number input[type="range"] { flex: 1; accent-color: var(--pv-accent); }
.step-body .slider-with-number input[type="number"] { width: 70px; flex: 0 0 auto; }

.step-body .tooltip-icon {
  background: var(--pv-raised); border: 1px solid var(--pv-line); color: var(--pv-ink-faint);
  width: 16px; height: 16px; font-size: 10px;
}
.step-body .mono-list { font-family: var(--pv-mono); font-size: 12px; }

/* ---- colour picker (Pickr, nano theme) ---------------------------------------------------
   Pickr ships a light popup. With its stylesheet now loaded before this one, these land
   without !important. Only the surfaces are restyled — the saturation/hue/alpha widgets are
   Pickr's own and are colour swatches by nature, so they stay as they are. */

.pcr-app {
  background: var(--pv-raised);
  border: 1px solid var(--pv-line);
  border-radius: var(--pv-r);
  color: var(--pv-ink);
  font-family: var(--pv-ui);
  box-shadow: 0 8px 26px #0009;
}
.pcr-app .pcr-interaction input {
  background: var(--pv-raised-hi);
  color: var(--pv-ink);
  border: 1px solid var(--pv-line);
  border-radius: 5px;
  font-family: var(--pv-mono);
  font-size: 12px;
}
.pcr-app .pcr-interaction .pcr-result:focus { border-color: var(--pv-accent); }
.pcr-app .pcr-interaction .pcr-save {
  background: var(--pv-accent);
  color: #05203a;
  font-weight: 700;
  border-radius: 5px;
}
.pcr-app .pcr-interaction .pcr-save:hover { background: #63b1ff; }

/* The swatch itself. A transparent colour reads as "nothing here" at 26px, so give it a
   little more room and a border to sit in. */
.step-body .pcr-button {
  width: 34px; height: 28px;
  border-radius: var(--pv-r-s);
  border: 1px solid var(--pv-line);
}
.step-body .pcr-button:hover { border-color: var(--pv-accent); }

/* Nano gives .pcr-app no width at all, so it shrink-wraps its content to about 200px, which
   clips the rgba value it shows you ("rgba(255, 0, 0" with the alpha cut off) — the one part
   of the popup you actually read a number from.
   The class is repeated deliberately: at single specificity this declaration is parsed, is the
   last width rule in the cascade, and still does not take effect. I could not account for that
   and did not want to paper over it with !important; doubling the class is the smallest thing
   that works and still loses to anything genuinely more specific. */
.pcr-app.pcr-app { width: 236px; }

/* ---- example-trace cards ------------------------------------------------------------------
   The visible control for #serverFileSelect, which stays in the DOM and stays authoritative.
   Deliberately one column: these are file names, and wrapping them into two columns at 420px
   truncates exactly the part that distinguishes them. */
.trace-cards { display: grid; grid-template-columns: 1fr; gap: 7px; }
.trace-card {
  /* One row, name then size: the size is what you weigh a trace by before opening it, so it
     belongs beside the name rather than on a sub-line under it. */
  display: flex; flex-direction: row; gap: 8px; align-items: baseline; text-align: left;
  /* A grid item defaults to min-width:auto, so without this the card refuses to shrink below
     its longest filename and pushes the size out past the panel. */
  min-width: 0;
  /* Roomier than the text strictly needs: these are the one control in step 1 you actually
     aim at, and the extra height gives the size beside the name space to read as its own
     column rather than as a suffix. */
  padding: 11px 12px; min-height: 42px; border-radius: var(--pv-r-s); cursor: pointer;
  background: var(--pv-raised); border: 1px solid var(--pv-line); color: var(--pv-ink);
  font-family: var(--pv-ui);
}
.trace-card b { font-family: var(--pv-mono); font-size: 12.5px; font-weight: 600;
                flex: 1 1 auto; min-width: 0;
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The size. Tabular figures so they line up down the column and can be compared at a glance,
   and ink-mute rather than ink-faint: at 11px the faint token sits near 3.4:1 on this surface,
   which was legible while it had its own line and is not once it shares one with the name. */
.trace-card i { flex: 0 0 auto; font-size: 12.5px; font-style: normal; color: var(--pv-ink-mute);
                font-family: var(--pv-mono); font-variant-numeric: tabular-nums;
                white-space: nowrap; }
/* The format, deliberately the quietest thing in the row. */
.trace-card u { flex: 0 0 auto; text-decoration: none; font-size: 10px; letter-spacing: 0.04em;
                color: var(--pv-ink-faint); white-space: nowrap; }
.trace-card:hover { background: var(--pv-raised-hi); }
.trace-card[aria-pressed="true"] {
  border-color: var(--pv-accent);
  background: color-mix(in oklab, var(--pv-accent) 13%, var(--pv-raised));
}
.trace-card[aria-pressed="true"] i { color: var(--pv-ink); }
.trace-card[aria-pressed="true"] u { color: var(--pv-ink-mute); }

/* .vis-hidden loses to `.step-body select` on width/height, which left the clipped listbox
   still measuring 419x150. Clipping hid it, but an absolutely-positioned box that size has no
   business sitting in the panel — pin the dimensions where the more specific rule can see them. */
.step-body select.vis-hidden,
.step-body input.vis-hidden { width: 1px; height: 1px; padding: 0; border: 0; min-width: 0; }

/* A disabled checkbox greys its box but not its words, which reads as "clickable, but nothing
   happens". Grey the whole row so the state is legible; the title says why. */
.step-body .checkbox-group:has(input:disabled) label { color: var(--pv-ink-faint); cursor: not-allowed; }

/* ---- colour-ramp editor -------------------------------------------------------------------
   The bar is a picture of the function the renderer applies — same maths, from colorramp.js —
   so what you see is what ranks get painted, including the flat clamp at the ends. */

.ramp-editor { margin: 10px 0 4px; }

.ramp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.ramp-axis-label { font-size: 10.5px; color: var(--pv-ink-faint); letter-spacing: .04em; text-transform: uppercase; }
.ramp-count { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--pv-ink-mute); }
.ramp-count b { min-width: 14px; text-align: center; color: var(--pv-ink); font-family: var(--pv-mono); }
.step-body .ramp-count button { padding: 1px 8px; font-size: 14px; line-height: 1.2; }

.ramp-track { position: relative; height: 34px; }
.ramp-bar {
  width: 100%; height: 100%; display: block;
  border: 1px solid var(--pv-line); border-radius: var(--pv-r-s);
  /* Checkerboard behind the ramp: these colours carry alpha, and "transparent" has to look
     different from "black". */
  background-image:
    linear-gradient(45deg, #2a2f38 25%, transparent 25%, transparent 75%, #2a2f38 75%),
    linear-gradient(45deg, #2a2f38 25%, transparent 25%, transparent 75%, #2a2f38 75%);
  background-size: 10px 10px;
  background-position: 0 0, 5px 5px;
  background-color: #1a1e25;
  image-rendering: auto;
}

.step-body .ramp-handle {
  position: absolute; top: -4px; bottom: -4px; width: 3px; padding: 0;
  transform: translateX(-50%);
  background: var(--pv-ink); border: 1px solid #0008; border-radius: 2px;
  cursor: ew-resize; touch-action: none;
}
/* The line is 3px and centred on its value, so a stop at either end of the axis — the top stop
   sits at 100 by default — would hang half outside the track and be almost ungrabbable. The
   visual stays 3px; only the pointer target grows, which leaves every coordinate mapping alone. */
.step-body .ramp-handle::before { content: ''; position: absolute; inset: -3px -7px; }
.step-body .ramp-handle:hover { background: var(--pv-accent); }
.step-body .ramp-handle.is-selected { background: var(--pv-accent); box-shadow: 0 0 0 2px #4aa3ff44; }
.ramp-handle-tip {
  position: absolute; bottom: calc(100% + 3px); left: 50%; transform: translateX(-50%);
  font: 10px/1 var(--pv-mono); color: var(--pv-ink-mute); white-space: nowrap; pointer-events: none;
}
.step-body .ramp-handle.is-selected .ramp-handle-tip { color: var(--pv-accent); }

.ramp-value-row { display: flex; align-items: center; gap: 8px; margin-top: 16px; }
.ramp-value-row label { flex: 0 0 auto; margin: 0; }
.step-body .ramp-value-row .ramp-value { flex: 1; min-width: 0; font-family: var(--pv-mono); }
.ramp-value-row .faint { flex: 0 0 auto; }

/* One chip per colour, and one colour per stop on the bar above. */
.ramp-swatches { display: flex; flex-wrap: wrap; gap: 6px 10px; margin-top: 12px; }
.ramp-swatches .pickr-form-item { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.ramp-swatches .pickr-form-item label { font-size: 10.5px; color: var(--pv-ink-faint); margin: 0; }

/* The ramp editor's +/- buttons are this control, in context and next to what they change.
   The row stays in the DOM because it is still the source of truth for the stop count that
   the editor is rebuilt from — it just no longer asks you the same question twice. */
.step-body .cutoffs-count-row { display: none; }

/* A disabled select greys its own text but keeps full-strength surroundings; dim the label too
   so "this is not available right now" reads at a glance. The title says why. */
.step-body .form-group:has(select:disabled) > label,
.step-body .form-group:has(select:disabled) .label-with-tooltip label { color: var(--pv-ink-faint); }
.step-body select:disabled { opacity: .55; cursor: not-allowed; }

/* Visualize now lives at the end of step 2, next to the controls that actually need it.
   Steps 3 and 4 apply as you change them, so there is nothing for a footer button to do. */
.visualize-row { margin-top: 16px; }
.visualize-row #visualizeButton { width: 100%; }
.visualize-row .step-note { margin: 8px 0 0; }

.panel-foot .step-note { margin: 8px 0 0; }


/* ---- timeline band ------------------------------------------------------------------------ */
#timeline-strip {
  flex: 0 0 auto;
  height: var(--strip-h, 200px);
  min-height: 60px;
  position: relative;
  overflow: hidden;
  background: #0a0c0f;
  border-top: 1px solid var(--pv-line);
  /* Lanes fill the cell that is left over; the scrollbars take one edge each and the corner
     where they meet stays empty, exactly as a scrolling pane behaves. */
  display: grid;
  grid-template-columns: 1fr var(--tl-sb, 14px);
  grid-template-rows: 1fr var(--tl-sb, 14px);
}
#timeline-canvas-area {
  grid-area: 1 / 1;
  position: relative;
  overflow: hidden;
  min-width: 0;
  min-height: 0;
}
#timeline-canvas-area canvas { display: block; width: 100%; height: 100%; }

/* The Vampir metric shows this same band as the main picture instead of as a strip under the
   scene. Only its placement changes: everything inside it, and every pointer handler bound to
   it, measures #timeline-canvas-area's box and so follows wherever the band is put. */
#timeline-strip.is-stage,
#timeline-strip.is-half-left,
#timeline-strip.is-half-right {
  position: absolute;
  top: 0;
  bottom: 0;
  /* Both are set in the band rule and would over-constrain the box here: with top, bottom and
     a height all specified, height wins and bottom is ignored, leaving a 60px sliver. */
  height: auto;
  min-height: 0;
  /* Above the scene it covers, below the panels that must stay reachable over it. */
  z-index: 1;
  border-top: 0;
}
#timeline-strip.is-stage      { left: 0;   right: 0; }
#timeline-strip.is-half-left  { left: 0;   right: 50%; }
#timeline-strip.is-half-right { left: 50%; right: 0; }

.tl-scroll {
  position: relative;
  /* Lighter than the lanes behind it, so the gutter reads as chrome rather than as empty
     trace. The thumb then only has to separate itself from the gutter, not from black. */
  background: #161b22;
  touch-action: none;
}
#timeline-vscroll {
  grid-area: 1 / 2;
  border-left: 1px solid var(--pv-line-soft);
}
#timeline-hscroll {
  grid-area: 2 / 1;
  border-top: 1px solid var(--pv-line-soft);
}
.tl-thumb {
  position: absolute;
  background: var(--pv-ink-faint);
  border-radius: 6px;
  transition: background 0.12s;
}
#timeline-vscroll .tl-thumb { left: 2px; right: 2px; top: 0; height: 100%; }
#timeline-hscroll .tl-thumb { top: 2px; bottom: 2px; left: 0; width: 100%; }
.tl-scroll:not(.is-full):hover .tl-thumb { background: var(--pv-ink-mute); }
.tl-thumb.is-dragging,
.tl-thumb:active { background: var(--pv-accent); }
/* Nothing to pan: the window already covers everything, so say so rather than offer a
   thumb that cannot move. */
.tl-scroll.is-full { cursor: default; }
.tl-scroll.is-full .tl-thumb { background: var(--pv-line); }
#timeline-vscroll:not(.is-full) { cursor: ns-resize; }
#timeline-hscroll:not(.is-full) { cursor: ew-resize; }

#timeline-splitter {
  flex: 0 0 7px;
  cursor: ns-resize;
  background: var(--pv-line-soft);
  position: relative;
}
#timeline-splitter::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 46px; height: 3px; transform: translate(-50%, -50%);
  border-radius: 2px; background: var(--pv-line);
}
#timeline-splitter:hover { background: var(--pv-accent-dim); }
#timeline-splitter:hover::after { background: var(--pv-accent); }
#timeline-splitter.is-dragging { background: var(--pv-accent-dim); }
