
    /* Trajectory controls content — hosted inside the unified "Trajectory"
       panel window (ui/panels/), which provides positioning and chrome.
       .panelBody is shared with the MD monitor's content. */

    .panelBody {
      padding: var(--sp-4) var(--sp-4) 14px;
      display: flex;
      flex-direction: column;
      gap: var(--sp-4);
    }

    /* .controlsRow / generic select+input styling are shared with BondLengthPanel. */
    .controlsRow {
      display: flex;
      gap: var(--sp-3);
      flex-wrap: wrap;
      justify-content: center;
    }

    select, input[type=number] {
      padding: var(--sp-1);
      border-radius: var(--radius-sm);
      background: var(--chrome-3);
      color: var(--fg-1);
      /* Was border:none, which left the field relying entirely on --chrome-3
         being distinguishable from whatever box it sits in. It wasn't, in any
         palette whose group boxes are not neutral grey. */
      border: 1px solid var(--line-2);
      box-sizing: border-box;
      text-align: center;
    }

    /* ---- Transport row: prev / play / next · scrub slider · frame counter ---- */
    .trajTransport {
      display: flex;
      align-items: center;
      gap: var(--sp-3);
    }

    .trajBtn {
      flex: 0 0 auto;
      width: 34px;
      height: 30px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      background: var(--chrome-2);
      color: var(--ink-5);
      border: 1px solid var(--chrome-3);
      border-radius: 7px;
      cursor: pointer;
      font-size: var(--fs-md);
      line-height: var(--lh-tight);
      padding: 0;
      transition: background 0.12s ease, border-color 0.12s ease;
    }
    .trajBtn:hover { background: var(--chrome-3); border-color: var(--chrome-4); }
    .trajBtn:active { background: var(--chrome-4); }
    .trajBtn:disabled { opacity: 0.4; cursor: default; }

    /* Play is the primary action: circular accent, anchoring the square
       prev/next buttons like a media deck. */
    #playPauseBtn {
      width: 36px;
      height: 36px;
      border-radius: 50%;
      background: var(--ok);
      border-color: var(--ok);
      color: var(--on-accent);
      font-size: var(--fs-lg);
      box-shadow: 0 0 0 4px rgb(var(--ok-rgb) / 0.12);
    }
    #playPauseBtn:hover { background: var(--ok); border-color: var(--ok); }
    #playPauseBtn:disabled {
      background: var(--chrome-2); border-color: var(--chrome-3); color: var(--ink-1); box-shadow: none;
    }

    .trajSlider {
      flex: 1 1 auto;
      min-width: 60px;
      height: 4px;
      -webkit-appearance: none;
      appearance: none;
      background: var(--chrome-3);
      border-radius: var(--radius-3);
      outline: none;
      cursor: pointer;
      margin: 0;
    }
    .trajSlider::-webkit-slider-thumb {
      -webkit-appearance: none;
      appearance: none;
      width: 14px;
      height: 14px;
      border-radius: 50%;
      background: var(--ok);
      border: 2px solid var(--thumb-border);
      cursor: pointer;
    }
    .trajSlider::-moz-range-thumb {
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: var(--ok);
      border: 2px solid var(--thumb-border);
      cursor: pointer;
    }

    /* Frame readout as a tape counter: accent current / muted total. */
    .trajFrameLabel {
      flex: 0 0 auto;
      min-width: 58px;
      text-align: right;
      font-size: var(--fs-md);
      font-family: var(--font-mono);
      font-variant-numeric: tabular-nums;
      letter-spacing: 0.5px;
      white-space: nowrap;
    }
    .trajFrameLabel .tfCur { color: var(--ink-5); font-weight: var(--fw-bold); }
    .trajFrameLabel .tfSep { color: var(--chrome-5); margin: 0 1px; }
    .trajFrameLabel .tfTot { color: var(--ink-1); }

    /* ---- Options row: speed + frame step ---- */
    .trajOptions {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 18px;
    }
    /* Instrument micro-labels: tracked uppercase, like a control-deck legend. */
    .trajOpt {
      display: inline-flex;
      align-items: center;
      gap: 7px;
      font-size: var(--fs-xs);
      font-weight: var(--fw-bold);
      letter-spacing: 0.9px;
      text-transform: uppercase;
      color: var(--ink-1);
    }
    .trajOpt select,
    .trajOpt input[type=number] {
      background: var(--chrome-2);
      color: var(--ink-5);
      border: 1px solid var(--chrome-3);
      border-radius: var(--radius-sm);
      padding: 3px var(--sp-2);
      font-size: var(--fs-sm);
      font-weight: var(--fw-normal);
      letter-spacing: normal;
      text-transform: none;
    }
    .trajOpt input[type=number] { width: 48px; }
    .trajOpt select:focus,
    .trajOpt input:focus { border-color: var(--ok); outline: none; }
    /* The "Recenter each step" checkbox row: clickable label, checkbox sized
       like the other controls rather than stretched by the flex row. */
    .trajOptCheck { cursor: pointer; }
    .trajOptCheck input[type=checkbox] { cursor: pointer; margin: 0; }

    /* ---- Resizable Plotly plot region (unified MD Monitor). Hidden by default
       via inline style until hasPlottableData() decides there's something to
       show (file-loaded energy, forces, or a live MD/relax feed). Legend,
       zoom/pan and PNG/data export come from Plotly's own chrome. ---- */
    #trajPlotHost {
      display: block;
      width: 100%;
    }

    .trajPlot {
      display: flex;
      flex-direction: column;
      width: 100%;
      height: 260px;
      min-height: 190px;
      min-width: 260px;
      padding: var(--sp-3);
      box-sizing: border-box;
      background: var(--chrome-1);
      border: 1px solid var(--chrome-2);
      border-radius: var(--radius-md);
      resize: vertical;
      overflow: hidden;
      position: relative;
    }

    /* ---- fullscreen (⛶), same mechanism as the analysis histograms'
       .split-item.expanded (sideDock.css) — expandSplitItem()/
       closeExpandedSplitItem() toggle this class and the shared overlay.
       !important on every geometry property: the native `resize` handle above
       sets an INLINE height on this div, and only an !important stylesheet
       rule can beat an inline style regardless of specificity — without it, a
       previously hand-dragged compact height would stick even at fullscreen. */
    .trajPlot.expanded {
      position: fixed !important;
      top: 5dvh !important;
      left: 5vw !important;
      width: 90vw !important;
      height: 90dvh !important;
      z-index: var(--z-dock-expanded) !important;
      resize: none !important;
      box-shadow: 0 0 24px var(--overlay) !important;
    }

    .trajPlot.expanded .split-item-close-btn {
      display: block;
    }

    /* Slim toolbar above the chart; the light/dark toggle (always shown) and
       the "Compute step stats" action (only when there's data to crunch) both
       read as part of the plot chrome, matching the EOS plot cards' 🌓 button. */
    .trajPlotToolbar {
      flex: 0 0 auto;
      display: flex;
      justify-content: flex-end;
      align-items: center;
      gap: var(--sp-2);
      min-height: 0;
      margin-bottom: 2px;
    }
    .trajPlotThemeBtn {
      background: var(--chrome-2);
      color: var(--ink-4);
      border: 1px solid var(--chrome-3);
      border-radius: var(--radius-sm);
      padding: 3px var(--sp-3);
      font-size: var(--fs-base);
      line-height: var(--lh-tight);
      cursor: pointer;
      transition: background 0.12s ease, border-color 0.12s ease;
    }
    .trajPlotThemeBtn:hover { background: var(--chrome-3); border-color: var(--chrome-4); }
    .trajPlotComputeBtn {
      background: var(--chrome-2);
      color: var(--ink-4);
      border: 1px solid var(--chrome-3);
      border-radius: var(--radius-sm);
      padding: var(--sp-1) var(--sp-3-5);
      font-size: var(--fs-sm);
      cursor: pointer;
      transition: background 0.12s ease, border-color 0.12s ease;
    }
    .trajPlotComputeBtn:hover { background: var(--chrome-3); border-color: var(--chrome-4); }

    .trajPlotChart {
      flex: 1 1 auto;
      width: 100%;
      min-height: 0;
    }

    .trajPlotStats {
      flex: 0 0 auto;
      text-align: center;
      margin-top: var(--sp-2);
      font-size: var(--fs-sm);
      font-family: var(--font-mono);
      color: var(--ink-3);
    }

    /* ---- Side-docked (either edge): the pane owns the height, not the plot.
       Free-floating or main-docked, .trajPlot's fixed 260px is what makes the
       chart a sensible size. Inside the dock that's wrong: the pane already
       has a definite height the user drags, so a fixed-height chart either
       leaves dead space or (docked to the bottom, where the pane is short and
       wide) overflows and forces the body to scroll. Chain flex down
       .cv-panel-body > #TrajControlPanel > .panelBody > #trajPlotHost so the
       chart takes the full width and whatever height is left; Plotly's own
       ResizeObserver (TrajectoryPlot.js) re-lays it out from there.
       min-height:0 at every level — flex items default to min-height:auto and
       refuse to shrink below their content otherwise. ---- */
    .cv-panel.cv-side-docked[data-panel-id="trajectory"] > .cv-panel-body > #TrajControlPanel,
    .cv-panel.cv-side-docked[data-panel-id="trajectory"] .panelBody,
    .cv-panel.cv-side-docked[data-panel-id="trajectory"] #trajPlotHost {
      flex: 1 1 auto;
      min-height: 0;
      display: flex;
      flex-direction: column;
    }

    .cv-panel.cv-side-docked[data-panel-id="trajectory"] #trajPlotHost > .trajPlot {
      flex: 1 1 auto;
      height: auto;
      /* Below this the axes stop being readable; the body scrolls instead. */
      min-height: 140px;
      /* The pane's own drag handle is the height control here. */
      resize: none;
    }
