/* Editor export heading mirror. */
.editor-export-modal h3 {
    font-size: 17px !important;
    font-weight: 600 !important;
    color: var(--text-primary);
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 16px !important;
}

/* TLS-A2: HTTPS cert install wizard tabs.
   Reuses the visual language of .video-tabstrip / .guide-tabstrip
   so the OS picker feels native to the rest of the app. */
.tls-os-tabs {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
    border-bottom: 1px solid var(--border);
    margin-bottom: 10px;
}
.tls-os-tab {
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--text-muted);
    padding: 6px 12px;
    cursor: pointer;
    font-size: 12px;
    transition: color 120ms ease, border-color 120ms ease;
}
.tls-os-tab:hover { color: var(--text-primary); }
.tls-os-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
    font-weight: 600;
}
.tls-os-steps {
    font-size: 12px;
    color: var(--text-primary);
}
.tls-os-steps code {
    background: rgba(255,255,255,0.05);
    padding: 1px 4px;
    border-radius: 3px;
    font-size: 11px;
}

/* RDPA-4: Rudimentary polar alignment sub-pane styles. */
.polar-tabstrip {
    display: flex;
    gap: 4px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 12px;
}
.polar-tab {
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--text-muted);
    padding: 8px 14px;
    cursor: pointer;
    font-size: 13px;
    transition: color 120ms ease, border-color 120ms ease;
}
.polar-tab:hover { color: var(--text-primary); }
.polar-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
    font-weight: 600;
}
.rudimentary-pane {
    padding-top: 4px;
}
.rudimentary-search-results {
    position: relative;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: 4px;
    margin-top: 4px;
    max-height: 240px;
    overflow-y: auto;
    z-index: 50;
}
.rudimentary-search-row {
    padding: 6px 10px;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 2px;
    border-bottom: 1px solid var(--border);
}
.rudimentary-search-row:last-child { border-bottom: none; }
.rudimentary-search-row:hover { background: rgba(255,255,255,0.05); }
.rudimentary-result {
    background: rgba(255,255,255,0.03);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 10px 14px;
    margin-top: 8px;
}
.rudimentary-sparkline {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 32px;
}
.rudimentary-spark-bar {
    display: inline-block;
    width: 8px;
    min-height: 2px;
    border-radius: 1px;
}
.rudimentary-skymap-wrap {
    margin-top: 10px;
}
.rudimentary-skymap {
    width: 100%;
    height: 280px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: #000;
}

/* Slew & Center capture tune popup inside the sky map overlay actions.
   Uses <details> so it stays out of the way until expanded. */
.slew-center-tune {
    background: rgba(0,0,0,0.4);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 12px;
}
.slew-center-tune summary {
    cursor: pointer;
    color: var(--text-muted);
    user-select: none;
}
.slew-center-tune summary:hover { color: var(--text-primary); }
.slew-center-tune[open] summary { color: var(--text-primary); margin-bottom: 4px; }

/* ----- Checkbox + radio normalisation -----
   The browser-default checkbox is a tiny 13px Windows 95 thing that
   sits visually adrift from every other control. This brings them
   into the same family as .btn / .input-sm: same border, same radius,
   same hover / focus colour, same bg-input fill. Drawn purely with
   CSS (no images) so dark / night mode picks up var() changes for
   free.

   Escape hatch: add class="checkbox-native" on the input to opt out
   (useful inside iframes / third-party widgets that depend on the
   default size). */
input[type="checkbox"]:not(.checkbox-native),
input[type="radio"]:not(.checkbox-native) {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    width: 18px;
    height: 18px;
    min-width: 18px;
    min-height: 18px;
    margin: 0 6px 0 0;
    padding: 0;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    position: relative;
    vertical-align: middle;
    transition: background var(--transition), border-color var(--transition);
    flex-shrink: 0;
}

/* Radios stay round; checkboxes inherit the .input-sm radius. */
input[type="radio"]:not(.checkbox-native) {
    border-radius: 50%;
}

input[type="checkbox"]:not(.checkbox-native):hover,
input[type="radio"]:not(.checkbox-native):hover {
    border-color: var(--accent);
}

input[type="checkbox"]:not(.checkbox-native):focus-visible,
input[type="radio"]:not(.checkbox-native):focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

input[type="checkbox"]:not(.checkbox-native):checked,
input[type="radio"]:not(.checkbox-native):checked {
    background: var(--accent);
    border-color: var(--accent);
}

/* Checkmark drawn as a rotated border-bottom + border-right rect.
   Two-pixel strokes so it stays readable at 18px. */
input[type="checkbox"]:not(.checkbox-native):checked::after {
    content: '';
    position: absolute;
    left: 5px;
    top: 1px;
    width: 5px;
    height: 10px;
    border: solid #fff;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

/* Radio bullet — solid filled circle centred in the ring. */
input[type="radio"]:not(.checkbox-native):checked::after {
    content: '';
    position: absolute;
    left: 4px;
    top: 4px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #fff;
}

input[type="checkbox"]:not(.checkbox-native):disabled,
input[type="radio"]:not(.checkbox-native):disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* Labels wrapping a checkbox were laid out with display:block by the
   browser default — switching the input to inline-block above leaves
   stray flex/grid items wrapping awkwardly. Force inline-flex on the
   nearby <label class="checkbox-label"> (and any vanilla label that
   contains a checkbox) so the label + text stay on one line and
   align vertically with each other. */
label:has(> input[type="checkbox"]:not(.checkbox-native)),
label:has(> input[type="radio"]:not(.checkbox-native)),
.checkbox-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    user-select: none;
}

/* Wheel-picker inline edit: number input that replaces the centre
   item on double-click. Matches the .input-sm look so a wheel that
   just popped its editor looks like any other text input in the panel. */
.wheel-picker-edit {
    background: var(--bg-input);
    border: 1px solid var(--accent);
    border-radius: var(--radius);
    color: var(--text-primary);
    font-size: 18px;
    padding: 4px 8px;
    outline: none;
    /* Hide the spinner arrows — at 85% width they crowd the value;
       the wheel itself is still available for click-to-step UX. */
    -moz-appearance: textfield;
}
.wheel-picker-edit::-webkit-outer-spin-button,
.wheel-picker-edit::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* Subtle "double-click to type" hint on the centre item. cursor:text
   nudges the operator that the centre is editable; the underline
   that some browsers add for double-click selection is suppressed
   inside the picker itself (already done via user-select earlier). */
.wheel-picker-item--center {
    cursor: ns-resize;   /* drag axis */
}
.wheel-picker-item--center:hover {
    text-decoration: underline dotted rgba(255,255,255,0.4);
    text-underline-offset: 4px;
}

/* ----- PHD2-style native guiding view ----- */
.phd2-view { display:flex; flex-direction:column; gap:8px; margin-top:8px; }
/* Responsive graph: viewport-relative height with a floor so the graph
   + camera frame + bottom bar all fit on screen together instead of the
   fixed 200px pushing the frame below the fold on short displays. */
.phd2-graph { position:relative; background:#0a0a0c; border:1px solid #222; border-radius:6px;
    height:clamp(160px, 24vh, 320px); }
.phd2-graph-canvas { width:100%; height:100%; display:block; }
.phd2-graph-hud { position:absolute; top:6px; left:8px; right:8px; display:flex;
    justify-content:space-between; pointer-events:none; font-size:11px; }
.phd2-rms { display:flex; gap:12px; }
.phd2-rms i { font-style:normal; opacity:0.8; }
.phd2-scale { display:flex; gap:4px; align-items:center; pointer-events:auto; }
.phd2-scale-btn { background:#1a1a1f; color:#aaa; border:1px solid #333; border-radius:3px;
    font-size:10px; padding:1px 6px; cursor:pointer; }
.phd2-scale-btn.active { background:#2962ff; color:#fff; border-color:#2962ff; }
.phd2-grid { display:grid; grid-template-columns:1fr 220px; gap:8px; }
@media (max-width:760px){ .phd2-grid { grid-template-columns:1fr; } }
.phd2-cam { position:relative; background:#000; border:1px solid #222; border-radius:6px;
    min-height:min(260px, 32vh); overflow:hidden; display:flex; align-items:center; justify-content:center; }
/* Zoom/pan wrapper: scaled at the centre so the frame + overlay move as one.
   line-height:0 collapses it to the image box; overflow on .phd2-cam clips the
   zoomed-in content. */
.phd2-cam-view { position:relative; line-height:0; transform-origin:center center;
    touch-action:none; will-change:transform; }
/* Smooth (bilinear) upscale of the guide preview JPEG: it is rendered small
   server-side, so nearest-neighbour made the stars look blocky/posterized.
   ASIAIR does the same — interpolate for a clean guide image. */
.phd2-cam-img { max-width:100%; max-height:min(420px, 44vh); display:block; image-rendering:auto; cursor:crosshair; }
.phd2-zoom-ctl { position:absolute; top:6px; left:6px; z-index:3; display:flex;
    align-items:center; gap:4px; background:rgba(0,0,0,0.45); border-radius:6px;
    padding:2px 4px; }
.phd2-zoom-ctl .btn { min-width:24px; }
.phd2-zoom-val { font-size:11px; color:#cfd6e4; min-width:30px; text-align:center; }
.phd2-cam-overlay { position:absolute; left:0; top:0; pointer-events:none; }
.phd2-cam-empty { position:absolute; font-size:12px; }
/* ----- ASIAIR-style floating guiding overlay (read-only, draggable) ----- */
.guide-overlay {
    position: fixed;
    z-index: 900;              /* above panels, below modals (1000) and toasts */
    display: flex;
    flex-direction: column;
    background: rgba(10, 12, 18, 0.72);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 8px;
    box-shadow: 0 6px 22px rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    overflow: hidden;
    user-select: none;
    touch-action: none;        /* pointer drag/resize, don't scroll the page */
}
.guide-overlay-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 8px;
    cursor: move;
    background: rgba(255, 255, 255, 0.05);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    font-size: 11px;
    flex: 0 0 auto;
}
.guide-overlay-title { font-weight: 600; letter-spacing: 0.02em; color: #cfd6e4; }
.guide-overlay-state { color: #ffb74d; font-size: 10px; }
.guide-overlay-state.is-guiding { color: #66bb6a; }
.guide-overlay-close {
    margin-left: auto;
    background: transparent;
    border: none;
    color: #99a; cursor: pointer;
    font-size: 12px; line-height: 1;
    padding: 2px 4px; border-radius: 3px;
}
.guide-overlay-close:hover { color: #fff; background: rgba(255, 255, 255, 0.1); }
.guide-overlay-graph { position: relative; flex: 1 1 auto; min-height: 40px; background: #0a0a0c; }
.guide-overlay-graph canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* Shown instead of a bare blank canvas when there is no step history yet
   (e.g. right after a browser refresh, which resets the client-side buffer). */
.guide-overlay-empty {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: 10px; color: #667; pointer-events: none;
}
.guide-overlay-stats {
    display: flex; flex-wrap: wrap; gap: 10px;
    padding: 3px 8px;
    font-size: 10px; color: #cfd6e4;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    flex: 0 0 auto;
}
.guide-overlay-stats i { font-style: normal; opacity: 0.85; }
.guide-overlay-stats b { font-weight: 600; }
.guide-overlay-dither { margin-left: auto; opacity: 0.8; }
/* Bottom-right resize grip (two diagonal ticks). */
.guide-overlay-resize {
    position: absolute; right: 0; bottom: 0;
    width: 16px; height: 16px;
    cursor: nwse-resize;
    background:
        linear-gradient(135deg, transparent 0 50%, rgba(255,255,255,0.35) 50% 60%, transparent 60% 72%, rgba(255,255,255,0.35) 72% 82%, transparent 82%);
}

/* Property Control Panels: SCADA-style floating cards (drag/resize mirror the
   guider overlay; same z-band, below modals/toasts). */
.rig-control-panel {
    position: fixed; z-index: 900;
    background: var(--bg-primary); border: 1px solid var(--border);
    border-radius: 8px; box-shadow: 0 6px 24px rgba(0,0,0,0.5);
    color: var(--text-primary); display: flex; flex-direction: column;
    overflow: hidden; user-select: none; touch-action: none;
    min-width: 180px; min-height: 90px;
}
.rig-cp-head {
    display: flex; align-items: center; gap: 8px; padding: 6px 10px;
    cursor: move; background: var(--bg-secondary); border-bottom: 1px solid var(--border);
}
.rig-cp-title { flex: 1; font-size: 12px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rig-cp-close { background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 13px; line-height: 1; }
.rig-cp-body { flex: 1; overflow: auto; padding: 4px 0; display: flex; flex-direction: column; }
.rig-cp-empty { font-size: 11px; color: var(--text-muted); padding: 6px 12px; }
/* Every widget is one standardised row: label (+ device sub-label) on the left,
   control right-aligned. No per-kind box (the old `rig-cp-{kind}` class collided
   with the .rig-cp-toggle button and boxed toggle rows). */
.rig-cp-row {
    display: grid; grid-template-columns: 1fr auto; align-items: center; column-gap: 12px;
    min-height: 38px; padding: 5px 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}
.rig-cp-row:last-child { border-bottom: none; }
.rig-cp-lab { min-width: 0; display: flex; flex-direction: column; line-height: 1.2; }
.rig-cp-lab .n { font-size: 13px; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rig-cp-lab .s { font-size: 10.5px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rig-cp-ctl { justify-self: end; display: flex; align-items: center; gap: 8px; }
.rig-cp-val { font-size: 13px; font-weight: 650; font-variant-numeric: tabular-nums; color: var(--text-primary); }
.rig-cp-val.empty { color: var(--text-muted); font-weight: 500; }
.rig-cp-slide { display: flex; align-items: center; gap: 8px; }
.rig-cp-slide input[type=range] { width: 118px; accent-color: var(--accent); }
.rig-cp-num { width: 92px; text-align: right; background: #0f1524; border: 1px solid var(--border); color: var(--text-primary); border-radius: 6px; padding: 5px 8px; font-size: 13px; }
.rig-cp-toggle {
    min-width: 52px; height: 24px; border-radius: 12px;
    border: 1px solid var(--border); background: #0f1524; color: var(--text-secondary);
    cursor: pointer; font-size: 11px;
}
.rig-cp-toggle.on { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
.rig-cp-btn {
    min-width: 60px; height: 26px; border-radius: 6px;
    border: 1px solid var(--border); background: #22304d; color: #cfe0ff; cursor: pointer; font-size: 12px;
}
.rig-cp-resize {
    position: absolute; right: 0; bottom: 0; width: 16px; height: 16px; cursor: nwse-resize;
    background:
        linear-gradient(135deg, transparent 0 50%, rgba(255,255,255,0.35) 50% 60%, transparent 60% 72%, rgba(255,255,255,0.35) 72% 82%, transparent 82%);
}

/* Docked rails: stack control panels along an edge, content-height. */
.rig-cp-rail { position: fixed; z-index: 900; display: flex; gap: 8px; overflow: auto; padding: 8px; }
.rig-cp-rail-left   { left: 0; top: 0; bottom: 0; flex-direction: column; width: 286px; align-items: stretch; }
.rig-cp-rail-right  { right: 0; top: 0; bottom: 0; flex-direction: column; width: 286px; align-items: stretch; }
.rig-cp-rail-top    { top: 0; left: 0; right: 0; flex-direction: row; max-height: 42vh; }
.rig-cp-rail-bottom { bottom: 0; left: 0; right: 0; flex-direction: row; max-height: 42vh; }
.rig-control-panel.docked {
    position: static; height: auto !important; flex: 0 0 auto; width: 100%;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
}
.rig-cp-rail-top .rig-control-panel.docked,
.rig-cp-rail-bottom .rig-control-panel.docked { width: 250px; }
.rig-control-panel.docked .rig-cp-body { flex: none; max-height: 320px; }
.rig-control-panel.docked .rig-cp-resize { display: none; }
/* Dock hint: highlight the edge a dragged panel will snap to. */
.rig-cp-dockhint { position: fixed; z-index: 899; pointer-events: none;
    background: rgba(var(--accent-rgb), 0.16); border: 2px dashed var(--accent); border-radius: 6px; }
.rig-cp-dockhint.rig-cp-rail-left   { left: 0; top: 0; bottom: 0; width: 286px; }
.rig-cp-dockhint.rig-cp-rail-right  { right: 0; top: 0; bottom: 0; width: 286px; }
.rig-cp-dockhint.rig-cp-rail-top    { top: 0; left: 0; right: 0; height: 130px; }
.rig-cp-dockhint.rig-cp-rail-bottom { bottom: 0; left: 0; right: 0; height: 130px; }

/* Control Panels editor (RIGS sub-tab). Fills the tab's remaining height: the
   sub-tab is a flex column and the two cards stretch to fill it, each card's list
   scrolling inside, instead of the shared card's fixed ~400px with dead space. */
.ctrl-panels-editor { padding: 8px 16px 16px; display: flex; flex-direction: column; flex: 1; min-height: 0; }
.ctrl-editor-grid {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 560px));
    grid-auto-rows: 1fr; gap: 16px; flex: 1; min-height: 0;
    align-items: stretch; justify-content: start;
}
/* Override the shared card's fixed height AND max-width (so the card fills its
   column instead of leaving dead space beside it) + supply our own padding
   (these cards don't lead with an <h3>, whose rules normally provide it). */
.ctrl-editor-grid > .settings-section {
    height: auto !important; min-height: 0; max-width: none; margin: 0 !important;
    padding: 14px 16px; display: flex; flex-direction: column;
}
.ctrl-catalog { flex: 1; min-height: 80px; max-height: none; overflow: auto; display: flex; flex-direction: column; gap: 3px; margin-top: 4px; }
.ctrl-catalog-row { display: flex; align-items: center; gap: 8px; padding: 4px 6px; border: 1px solid var(--border); border-radius: 4px; }
/* Edited-panel form + widget list */
.ctrl-field { display: flex; flex-direction: column; align-items: flex-start; gap: 5px; font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; margin-bottom: 12px; }
.ctrl-field input { text-transform: none; letter-spacing: normal; color: var(--text-primary); }
.ctrl-ed-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.ctrl-check { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-secondary); }
.ctrl-sub-h { margin: 0 0 8px; font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.ctrl-wlist { border: 1px solid var(--border); border-radius: 8px; overflow: auto; flex: 1; min-height: 80px; }
.ctrl-wrow { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 10px; padding: 8px 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); }
.ctrl-wrow:last-child { border-bottom: none; }
.ctrl-wname { font-size: 13px; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ctrl-wgroup { font-size: 10.5px; color: var(--text-muted); margin-left: 4px; }
.ctrl-chip { font-size: 10.5px; color: var(--text-muted); border: 1px solid var(--border); border-radius: 10px; padding: 1px 9px; }

.cal-review-backdrop { position:fixed; inset:0; background:rgba(0,0,0,0.6); z-index:1000;
    display:flex; align-items:center; justify-content:center; }
.cal-review { background:#0d0f15; border:1px solid #333; border-radius:8px; width:min(720px,92vw);
    max-height:90vh; overflow:auto; box-shadow:0 8px 40px rgba(0,0,0,0.6); }
.cal-review-head { display:flex; justify-content:space-between; align-items:center;
    padding:10px 14px; border-bottom:1px solid #222; font-weight:600; }
.cal-review-body { display:flex; gap:14px; padding:14px; flex-wrap:wrap; }
.cal-review-plot { width:240px; height:240px; flex:0 0 240px; background:#000;
    border:1px solid #222; border-radius:6px; }
.cal-review-tablewrap { flex:1 1 360px; min-width:300px; }
.cal-review-section { font-size:11px; color:#888; text-transform:uppercase; margin-bottom:4px; }
.cal-review-table { width:100%; border-collapse:collapse; font-size:12px; }
.cal-review-table td { border:1px solid #222; padding:4px 8px; }
.cal-review-table td:nth-child(odd) { color:#9aa; width:22%; }
.cal-restored-tag { font-size:10px; color:#69f0ae; border:1px solid #2e6; border-radius:4px;
    padding:1px 6px; margin-left:8px; vertical-align:middle; text-transform:uppercase; }
.cal-corr-grid { display:grid; grid-template-columns:1fr 1fr 1fr; gap:10px 8px; margin-top:8px;
    align-items:end; }
.cal-corr-grid .gb-field { display:flex; flex-direction:column; gap:5px; font-size:10px;
    color:#8a93a6; text-transform:uppercase; letter-spacing:.04em; line-height:1.3; }
.cal-corr-grid .gb-field input { width:100%; background:#11151c; color:#e6e9ef;
    border:1px solid #2a3140; border-radius:5px; padding:6px 7px; font-size:13px;
    outline:none; transition:border-color .12s; text-transform:none; }
.cal-corr-grid .gb-field input:focus { border-color:#2962ff; }
.phd2-cal-banner { position:absolute; left:50%; top:10px; transform:translateX(-50%);
    background:rgba(20,22,30,0.85); color:#ffd54f; border:1px solid var(--success);
    border-radius:6px; padding:4px 12px; font-size:12px; font-family:monospace;
    white-space:nowrap; pointer-events:none; z-index:5; }
/* Dither / settle banner over the guide-cam view (ASIAIR-style). Amber for
   an active dither, blue for a plain post-start settle. Pulses to draw the
   eye while guiding is intentionally chasing the star. */
.phd2-dither-banner { position:absolute; left:50%; top:10px; transform:translateX(-50%);
    background:rgba(180,120,10,0.92); color:#fff; border:1px solid #ffd54f;
    border-radius:6px; padding:4px 12px; font-size:12px; font-weight:600;
    white-space:nowrap; pointer-events:none; z-index:6;
    animation: panic-pulse 1.6s ease-in-out infinite; }
.phd2-settle-banner { background:rgba(40,90,160,0.92); border-color:#64b5f6; }

/* RA/Dec aggressiveness sliders in the GUIDE sidebar. */
/* Collapsible focuser group in the capture side panels. Replaces a fieldset
   + legend: the summary is the header, and it keeps the live position on
   screen while the controls are folded away. */
.focus-group {
    border: 1px solid var(--border);
    border-radius: 8px;
    margin: 8px 0 0;
    padding: 0 10px 2px;
    min-width: 0;
}
.focus-group[open] { padding-bottom: 10px; }
.focus-group-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 0;
    cursor: pointer;
    list-style: none;
    user-select: none;
}
.focus-group-head::-webkit-details-marker { display: none; }
/* Caret on the left, rotating on open, so the header reads as a control. */
.focus-group-head::before {
    /* The escape here was written through a shell that turned \25 into
       a raw 0x15 byte, so the caret rendered as a tofu box next to the
       "Focus motor" label instead of a triangle. */
    content: "\25B8";
    color: var(--text-muted);
    transition: transform 0.15s;
    flex: 0 0 auto;
}
.focus-group[open] .focus-group-head::before { transform: rotate(90deg); }
.focus-group-title { font-size: 12px; color: var(--text-muted); flex: 0 0 auto; }
.focus-group-pos {
    margin-left: auto;
    font-size: 18px;
    color: var(--accent);
    font-variant-numeric: tabular-nums;
    line-height: 1;
}
.focus-group .focus-readout-warn { font-size: 11px; flex: 0 0 auto; }

.guide-aggr { margin-bottom:10px; display:flex; flex-direction:column; gap:8px; }
.guide-aggr-row { display:flex; flex-direction:column; gap:2px; }
.guide-aggr-row label { font-size:11px; color:#bbb; display:flex; justify-content:space-between; }
.guide-aggr-row input[type=range] { width:100%; }

.phd2-rightcol { display:flex; flex-direction:column; gap:8px; }
.phd2-bullseye, .phd2-profile { background:#0a0a0c; border:1px solid #222; border-radius:6px; padding:6px; }
.phd2-panel-title { font-size:11px; color:#888; margin-bottom:4px; }
.phd2-sq-canvas { width:100%; aspect-ratio:1/1; display:block; }
.phd2-starzoom { width:100%; height:120px; display:block;
    background:#000; border:1px solid #222; border-radius:4px; image-rendering:pixelated; }
.phd2-prof-canvas { width:100%; height:90px; display:block; }
.phd2-statusbar { display:flex; gap:16px; flex-wrap:wrap; font-size:11px; color:#bbb;
    background:#0a0a0c; border:1px solid #222; border-radius:6px; padding:5px 10px; font-family:monospace; }

/* Guiding config block in the GUIDE tab (backend picker + native settings) */
.guide-config-block { background:#0a0a0c; border:1px solid #222; border-radius:6px;
    padding:8px 10px; margin-bottom:8px; }

/* GUIDE tab: fixed-height column (no panel scroll), pane fills, bar pinned. */
.tab-panel-guide { display:flex; flex-direction:column; min-height:0; }
.guide-shell { display:flex; flex-direction:column; flex:1; min-height:0; }
.guide-pane { display:flex; flex-direction:row; gap:12px; align-items:stretch;
    flex:1; min-height:0; position:relative; }
.guide-main { flex:1; min-width:0; overflow-y:auto; }
/* When the parameters panel is present it floats over the right edge of the
   pane (same model as the LIVE/PREVIEW sidebars); the main column reserves
   room for it so its content stays clear, and the reserve shrinks to just the
   retract handle when collapsed. */
.guide-pane.guide-has-side > .guide-main { margin-right:calc(var(--guide-side-width, 336px) + 12px);
    transition:margin-right 200ms ease; }
.guide-pane.guide-has-side.guide-controls-collapsed > .guide-main { margin-right:36px; }
.guide-side { position:absolute; right:0; top:0; bottom:0; width:var(--guide-side-width, 336px); z-index:4;
    display:flex; flex-direction:column; gap:8px;
    /* padding-left reserves room for the full-height retract handle */
    padding:10px 12px 10px 44px; overflow:hidden;
    background:rgba(10,10,12,0.94); backdrop-filter:blur(10px);
    -webkit-backdrop-filter:blur(10px); border:1px solid #222;
    border-radius:6px; transition:transform 200ms ease; }
/* Collapsed: slide off to the right leaving only the 28px handle visible. */
.guide-side.guide-side--collapsed { transform:translateX(calc(100% - 28px)); }
/* Section header. Generous top margin gives each functional group clear
   breathing room within its tab (no divider lines — the tabs already group
   things; lines just made it look boxed/cramped). */
.guide-side-title { font-size:12px; color:#888; margin:16px 0 10px;
    text-transform:uppercase; letter-spacing:.04em; }
/* Small muted helper text inside the guiding panel. Without this the generic
   .hint has no scoped rule here and falls back to the ~16px body size. */
.guide-side .hint { font-size:11px; line-height:1.45; color:#8a93a6; margin-top:6px; }
.guide-side .hint.text-warn { color:var(--danger, #e05252); }
/* Status / Settings / Calibration tabs reuse the app's .guide-tabstrip; the
   3 native tabs stretch evenly across the narrow panel. */
.guide-side-tabstrip { margin-top:0; }
.guide-side-tabstrip .guide-tab { flex:1; text-align:center; padding:7px 6px; }


/* Status card: turn the plain key/value list into a tidy carded readout with
   row separators + tabular numerals, so it doesn't read as raw text. */
.guide-side .guide-status-card { padding:4px 12px; gap:0; max-width:none;
    background:rgba(255,255,255,0.025); border:1px solid #20242c; border-radius:10px; }
.guide-side .guide-status-card .info-row { padding:8px 0; font-size:13px;
    border-bottom:1px solid rgba(255,255,255,0.06); }
.guide-side .guide-status-card .info-row:last-child { border-bottom:none; }
.guide-side .guide-status-card .info-row span { color:#8a93a6; }
.guide-side .guide-status-card .info-row strong { color:var(--text-primary, #e6e9ef);
    font-variant-numeric:tabular-nums; }

/* Functional groups inside the Settings / Calibration tabs — same carded
   look as the Status readout, so each function (aggressiveness, guiding
   parameters, meridian flip, mount calibration, dark library, calibration &
   correction) reads as its own tidy block. */
.guide-side .guide-group { background:rgba(255,255,255,0.025); border:1px solid #20242c;
    border-radius:10px; padding:10px 12px; margin-bottom:12px; }
.guide-side .guide-group:last-child { margin-bottom:0; }
.guide-side .guide-group > .guide-side-title:first-child { margin-top:0; }

/* Alert callout (replaces the plain red text row). */
.guide-alert { display:flex; align-items:flex-start; gap:8px; margin-top:10px;
    padding:9px 11px; border-radius:8px; font-size:12.5px; line-height:1.4;
    /* Severity-specific colours come from the .guide-alert-{info|warn|error}
       modifier; default to the warn (amber) palette if none is applied. */
    --ga-color: var(--warning, #e0a23a);
    background:color-mix(in srgb, var(--ga-color) 13%, transparent);
    border:1px solid color-mix(in srgb, var(--ga-color) 38%, transparent); }
.guide-alert-info  { --ga-color: var(--accent, #4fc3f7); }
.guide-alert-warn  { --ga-color: var(--warning, #e0a23a); }
.guide-alert-error { --ga-color: var(--danger, #e05252); }
.guide-alert .guide-alert-icon { color:var(--ga-color); font-size:14px; line-height:1.3; }
.guide-alert strong { flex:1; color:var(--text-primary, #f0f0f0); font-weight:600; }
.guide-alert .guide-alert-dismiss { flex:0 0 auto; }
.guide-backend-radios { display:inline-flex; align-items:center; gap:10px;
    margin-left:12px; font-size:12px; }
.guide-backend-radios label { display:inline-flex; align-items:center; gap:4px; cursor:pointer; }
/* Single-row control bar pinned to the bottom of the GUIDE panel.
   Slimmed to capture/guide actions (dither knobs live in the side
   panel's Dithering section now): labels sit inline with their inputs
   and the whole row is centred (field request). */
.guide-bottombar { flex:0 0 auto; display:flex; flex-wrap:wrap; align-items:center;
    justify-content:flex-start; gap:8px; padding:8px 10px; margin-top:8px;
    border-top:1px solid #222; background:#0c0c10; border-radius:6px; }
.guide-bottombar .gb-field { display:flex; flex-direction:row; align-items:center;
    font-size:10px; color:#8a93a6; gap:6px; text-transform:uppercase;
    letter-spacing:.04em; }
.guide-bottombar .gb-field input { width:64px; background:#11151c; color:#e6e9ef;
    border:1px solid #2a3140; border-radius:5px; padding:5px 7px; font-size:13px;
    outline:none; transition:border-color .12s; }
.guide-bottombar .gb-field input:focus { border-color:#2962ff; }
.guide-bottombar .gb-field select { width:auto; min-width:64px; background:#11151c;
    color:#e6e9ef; border:1px solid #2a3140; border-radius:5px; padding:5px 7px;
    font-size:13px; outline:none; transition:border-color .12s; cursor:pointer; }
.guide-bottombar .gb-field select:focus { border-color:#2962ff; }
.guide-bottombar .gb-check { display:flex; align-items:center; gap:5px; font-size:12px;
    color:#cdd3de; cursor:pointer; }
.guide-bottombar .gb-sep { width:1px; align-self:stretch; background:#222; margin:0 4px; }
/* Clear History pinned to the chart's bottom-right corner (both the
   native canvas graph and the PHD2 Chart.js panel host one). */
.guide-clearhist { position:absolute; right:8px; bottom:6px; z-index:4;
    opacity:0.85; }
.guide-clearhist:hover { opacity:1; }
@media (max-width:900px){
    /* Keep the parameters panel as a collapsible right-edge OVERLAY instead of
       stacking it below the graph. On a phone the graph area is precious, so an
       overlay the operator can retract to the 28px handle beats a panel that
       pushes the graph off-screen. Cap the width so it never exceeds the
       viewport, and reserve only the handle (the expanded panel floats over the
       graph; collapse it to see the graph full-width). */
    .guide-side {
        width: min(var(--guide-side-width, 336px), 88vw);
        overflow-y: auto;
    }
    .guide-pane.guide-has-side > .guide-main,
    .guide-pane.guide-has-side.guide-controls-collapsed > .guide-main {
        margin-right: 36px;
    }
}

/* ───────────────────────── PLAN mode ───────────────────────── */
/* The panel is a fixed-height flex column (header / split / run bar) and
   does NOT scroll: .plan-main does. The run bar used to be sticky inside a
   scrolling panel, bled over the panel padding with a negative bottom
   margin, and a sticky box is held by its MARGIN box, so that margin pushed
   its border box past the scrollport and clipped the buttons. As an
   ordinary last flex child it cannot leave the panel at all. */
.tab-panel-plan { padding: 12px 12px 0; overflow: hidden; }

/* Header and banner keep their height: they are flex children of a
   fixed-height column now, and without this they compress before
   .plan-main does. */
.tab-panel-plan > .panel-header { flex: 0 0 auto; }

/* Two columns: the plan editor scrolls, the last captured frame does not. */
.plan-split { display: flex; flex: 1 1 auto; min-height: 0; gap: 12px; }
.plan-main  { flex: 1 1 auto; min-width: 0; overflow-y: auto; padding-bottom: 12px; }
.plan-preview {
    /* Resizable via the .col-splitter to its left; persisted. */
    flex: 0 0 var(--plan-preview-w, 360px);
    min-height: 0;
    min-width: 0;
    border: 1px solid var(--border, #2a2f3a);
    border-radius: var(--radius);
}
/* Below this the editor needs every pixel it can get; the frame is one
   tab away in AUTORUN. */
@media (max-width: 1100px) {
    .plan-preview, .plan-split > .col-splitter { display: none; }
}
.plan-toolbar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
.plan-select { flex: 1; min-width: 160px; padding: 6px 8px; }
.plan-empty { color: var(--text-muted, #9aa4b2); padding: 24px 8px; text-align: center; }
.plan-body { display: flex; flex-direction: column; gap: 12px; }
.plan-name { font-size: 12px; font-weight: 600; padding: 8px 10px; width: 100%; box-sizing: border-box; }

.plan-settings { padding: 12px; display: flex; flex-direction: column; gap: 12px; }
.plan-set-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; }
.plan-set-grid label, .plan-detail-grid label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--text-muted, #9aa4b2); }
.plan-set-grid select, .plan-set-grid input { padding: 6px 8px; }
.plan-set-toggles { display: flex; flex-wrap: wrap; gap: 12px 18px; }
.plan-set-end { border-top: 1px solid var(--border, #2a2f3a); padding-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.plan-set-end-title { font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted, #9aa4b2); }
.chk { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; }
.chk-danger { color: #f87171; }

.plan-targets { display: flex; flex-direction: column; gap: 8px; }
.plan-target-card { border: 1px solid var(--border, #2a2f3a); border-radius: 8px; background: rgba(255,255,255,0.02); }
.plan-target-card.is-open { border-color: var(--accent, #3b82f6); }
.plan-target-card.is-disabled { opacity: 0.5; }
.plan-target-head { display: flex; align-items: center; gap: 10px; padding: 8px 10px; }
.plan-target-thumb {
    width: 40px; height: 40px; flex: 0 0 40px;
    object-fit: cover; border-radius: 4px; cursor: pointer;
    background: var(--bg-elevated); border: 1px solid var(--border);
}
.plan-viz-thumb {
    width: 34px; height: 34px;
    object-fit: cover; border-radius: 4px; display: block;
    background: var(--bg-elevated); border: 1px solid var(--border);
}
.plan-target-id { flex: 1; display: flex; flex-direction: column; cursor: pointer; min-width: 0; }
.plan-target-name { font-weight: 600; }
.plan-target-coords { font-size: 11px; color: var(--text-muted, #9aa4b2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.plan-target-actions { display: flex; gap: 2px; }
.plan-target-detail { padding: 10px; border-top: 1px solid var(--border, #2a2f3a); display: flex; flex-direction: column; gap: 12px; }
.plan-detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }
.plan-detail-grid input { padding: 6px 8px; width: 100%; box-sizing: border-box; }

.plan-frames-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted, #9aa4b2); }
.plan-frames-tools { display: flex; gap: 6px; }
.plan-frame-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; padding: 6px 0; border-top: 1px dashed var(--border, #2a2f3a); }
.plan-frame-row label { display: flex; flex-direction: column; gap: 2px; font-size: 11px; color: var(--text-muted, #9aa4b2); }
.plan-frame-row input { padding: 4px 6px; width: 5.5em; }

.plan-add-row { display: flex; gap: 8px; flex-wrap: wrap; }
.plan-catalog { border: 1px solid var(--border, #2a2f3a); border-radius: 8px; padding: 10px; }
.plan-catalog > input { width: 100%; box-sizing: border-box; padding: 7px 9px; }
.plan-cat-results { max-height: 220px; overflow-y: auto; margin-top: 8px; }
.plan-cat-item { display: flex; justify-content: space-between; gap: 10px; padding: 7px 8px; border-radius: 6px; cursor: pointer; }
.plan-cat-item:hover { background: rgba(255,255,255,0.06); }
.plan-cat-item .muted { color: var(--text-muted, #9aa4b2); font-size: 11px; white-space: nowrap; }

/* Fixed bottom run bar: pinned to the bottom of the scrolling plan
   panel. Start/Stop on the left; two progress bars (current target +
   whole plan) fill the remaining width. Negative margins bleed it to
   the panel edges so it reads as a full-width footer. */
.plan-runbar {
    /* Last flex child of the panel, so it always sits at the foot of the
       panel and never scrolls away. The negative SIDE margins bleed it to
       the panel edges so it reads as a full-width footer. */
    flex: 0 0 auto;
    /* wrap so a narrow phone stacks the buttons instead of pushing the
       last one out of the panel */
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    margin: 0 -12px; padding: 10px 12px;
    border-top: 1px solid var(--border, #2a2f3a);
    background: var(--bg-secondary, #161a22);
}
/* Start/Stop: same metrics as the rest of the UI's .btn, with a green
   (start) / red (stop) accent instead of the old oversized pill. */
.plan-run-btn {
    flex: 0 0 auto;
    padding: 6px 18px;
    font-size: 13px; font-weight: 600;
    border-radius: var(--radius); border: 1px solid #16a34a;
    cursor: pointer; background: #16a34a; color: #fff;
    transition: background var(--transition), border-color var(--transition);
}
.plan-run-btn:hover { background: #15803d; border-color: #15803d; }
.plan-run-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.plan-run-btn.running { background: #dc2626; border-color: #dc2626; }
.plan-run-btn.running:hover { background: #b91c1c; border-color: #b91c1c; }
.plan-runbar-bars { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.plan-pbar { display: flex; flex-direction: column; gap: 3px; }
.plan-pbar-head { display: flex; justify-content: space-between; gap: 8px; font-size: 11px; color: var(--text-muted, #9aa4b2); }
.plan-pbar-head span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plan-pbar-head span:last-child { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.plan-pbar-track { height: 9px; border-radius: 999px; background: var(--bg-tertiary, #0f1218); overflow: hidden; }
.plan-pbar-fill { height: 100%; border-radius: 999px; transition: width .3s ease; }
.plan-pbar-fill.item { background: var(--accent); }
.plan-pbar-fill.total { background: #16a34a; }

.plan-frame-banner {
    position: fixed; left: 50%; transform: translateX(-50%);
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    z-index: 9000; display: flex; gap: 10px; align-items: center;
    background: rgba(20, 24, 34, 0.95); border: 1px solid var(--accent, #3b82f6);
    border-radius: 999px; padding: 8px 16px; font-size: 13px;
    box-shadow: 0 6px 20px rgba(0,0,0,0.5);
}

/* Generic card + modal used by the PLAN panel (no prior definition). */
.plan-body .card,
.card { border: 1px solid var(--border, #2a2f3a); border-radius: 8px; background: rgba(255,255,255,0.02); }
.modal-overlay {
    position: fixed; inset: 0; z-index: 9600; display: flex;
    align-items: center; justify-content: center; padding: 20px;
    background: rgba(0,0,0,0.55);
    backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
    animation: modal-fade 0.18s ease-out;
}
@keyframes modal-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-pop {
    from { opacity: 0; transform: translateY(8px) scale(0.97); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}
.modal-card {
    position: relative; max-width: 440px; width: 100%;
    background: linear-gradient(180deg, color-mix(in srgb, var(--panel-bg, #161a22) 92%, #fff 8%), var(--panel-bg, #161a22));
    border: 1px solid var(--border, #2a2f3a);
    border-radius: 14px; padding: 20px 22px 18px;
    box-shadow: 0 18px 60px rgba(0,0,0,0.62), 0 2px 8px rgba(0,0,0,0.4);
    overflow: hidden;
    animation: modal-pop 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
/* Accent strip across the top — neutral (accent) by default, red for
   destructive confirmations (.modal-card.danger). */
.modal-card::before {
    content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px;
    background: var(--accent, #4f8cff);
}
.modal-card.danger::before { background: var(--danger, #e5484d); }
.modal-head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.modal-icon {
    flex: 0 0 auto; width: 38px; height: 38px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center; font-size: 19px;
    background: color-mix(in srgb, var(--accent, #4f8cff) 16%, transparent);
    color: var(--accent, #4f8cff);
}
.modal-card.danger .modal-icon {
    background: color-mix(in srgb, var(--danger, #e5484d) 16%, transparent);
    color: var(--danger, #e5484d);
}
.modal-head h3, .modal-card h3 { margin: 0; font-size: 16px; font-weight: 650; }
.modal-card p { margin: 0 0 18px; font-size: 13px; line-height: 1.55; color: var(--text-muted, #9aa4b2); }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; }
/* "Report a problem" buttons in the Help/About FAQ. */
.report-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }

/* Theme the PLAN form controls to match the rest of the app (the dark
   input chrome used in Settings). Without this, native selects/inputs
   render with the OS combobox look, which clashes with night mode. */
.tab-panel-plan input[type="text"],
.tab-panel-plan input[type="number"],
.tab-panel-plan input[type="time"],
.tab-panel-plan select,
.modal-card input,
.modal-card select {
    background: var(--bg-input);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 7px 9px;
    box-sizing: border-box;
    outline: none;
    color-scheme: dark;
    transition: border-color var(--transition);
}
.tab-panel-plan input:focus,
.tab-panel-plan select:focus,
.modal-card input:focus,
.modal-card select:focus { border-color: var(--accent); }
.tab-panel-plan input[type="checkbox"] {
    width: auto; padding: 0; accent-color: var(--accent); cursor: pointer;
}
/* Custom SVG chevron so the closed select matches the themed text fields
   (mirrors .settings-section select). */
.tab-panel-plan select {
    appearance: none; -webkit-appearance: none; -moz-appearance: none;
    cursor: pointer; padding-right: 30px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M2 4l4 4 4-4' fill='none' stroke='%23a8b3bf' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat: no-repeat; background-position: right 10px center;
}
.tab-panel-plan select option { background: var(--bg-secondary); color: var(--text-primary); }

/* PLAN: per-target schedule mode + elevation chart */
.plan-sched { display: flex; flex-direction: column; gap: 8px; }
.plan-sched-toggle { display: flex; gap: 6px; }
.plan-sched-note { font-size: 11px; line-height: 1.4; }
.plan-sched-note em { font-style: normal; color: var(--text-primary, #e5e7eb); }
.plan-maint { display: flex; flex-direction: column; gap: 4px; }
.plan-maint-title { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; }
.plan-maint-row { display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; align-items: center; }
.plan-maint-row label { display: inline-flex; align-items: center; gap: 6px; }
.plan-maint-row input { width: 4em; }
.plan-altchart-wrap { display: flex; flex-direction: column; gap: 6px; }
.plan-altchart-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; font-size: 11px; flex-wrap: wrap; }
.plan-altchart-head .muted { color: var(--text-muted, #9aa4b2); }
.plan-window-times { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; }
.plan-alt-msg { padding: 16px; text-align: center; font-size: 12px; }
.plan-altchart {
    width: 100%; height: 150px; display: block;
    background: var(--bg-input); border: 1px solid var(--border); border-radius: var(--radius);
    touch-action: none;
}
.plan-alt-night { fill: rgba(120, 160, 220, 0.06); }
.plan-alt-tick { stroke: rgba(255,255,255,0.10); stroke-width: 1; vector-effect: non-scaling-stroke; }
.plan-alt-guide { stroke: rgba(255,255,255,0.18); stroke-width: 1; stroke-dasharray: 6 6; }
.plan-alt-sel { fill: rgba(34, 197, 94, 0.14); }
.plan-alt-curve { fill: none; stroke: #f0b21a; stroke-width: 3; vector-effect: non-scaling-stroke; }
.plan-alt-handle { cursor: ew-resize; touch-action: none; }
.plan-alt-handle-line { stroke: #22c55e; stroke-width: 4; vector-effect: non-scaling-stroke; }
.plan-alt-handle-knob { fill: #22c55e; }
.plan-alt-handle-hit { fill: transparent; cursor: ew-resize; }
.plan-altchart-axis { position: relative; height: 14px; margin-top: 2px; }
.plan-axis-tick {
    position: absolute; transform: translateX(-50%);
    font-size: 10px; color: var(--text-muted, #9aa4b2); white-space: nowrap;
}
.plan-window-fields { display: flex; gap: 14px; }
.plan-window-fields label { display: flex; flex-direction: column; gap: 4px; font-size: 11px; color: var(--text-muted, #9aa4b2); }

/* PLANVIZ: whole-plan visualization modal. */
.plan-viz-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.6); z-index: 1000;
    display: flex; align-items: center; justify-content: center; padding: 20px; }
.plan-viz { background: #0d0f15; border: 1px solid #333; border-radius: 8px;
    width: min(980px, 96vw); max-height: 92vh; display: flex; flex-direction: column; overflow: hidden; }
.plan-viz-head { display: flex; justify-content: space-between; align-items: center;
    padding: 12px 14px; border-bottom: 1px solid #222; font-weight: 600; flex: 0 0 auto; }
.plan-viz-body { padding: 14px; overflow-y: auto; }
.plan-viz-summary { display: flex; flex-wrap: wrap; gap: 18px; font-size: 13px; }
.plan-viz-summary .muted { color: var(--text-muted, #9aa4b2); }
.plan-viz-altchart { width: 100%; height: 220px; display: block;
    background: var(--bg-input); border: 1px solid var(--border); border-radius: var(--radius); }
.plan-viz-marker { stroke: #e5e7eb; stroke-width: 1.5; stroke-dasharray: 4 4; vector-effect: non-scaling-stroke; }
.plan-viz-gantt svg { display: block; background: var(--bg-input);
    border: 1px solid var(--border); border-radius: var(--radius); }
.plan-viz-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.plan-viz-table th { text-align: left; color: #888; font-weight: 600; border-bottom: 1px solid #222; padding: 5px 8px; }
.plan-viz-table td { border-bottom: 1px solid #1a1a1a; padding: 5px 8px; }
.plan-viz-swatch { display: inline-block; width: 14px; height: 14px; border-radius: 3px; vertical-align: middle; }
.plan-viz-legend { display: flex; align-items: center; gap: 8px; font-size: 12px; }
.plan-viz-hatch { display: inline-block; width: 24px; height: 14px; border-radius: 3px;
    border: 1px solid var(--border, #2a2f3a);
    background-color: rgba(120, 160, 220, 0.20);
    background-image: repeating-linear-gradient(45deg,
        rgba(255,255,255,0.55) 0 1.6px, transparent 1.6px 6px); }

/* ===== Dialog / background-task modal backdrops =====================
   Many modals run a task in the background (plate solve, batch stack,
   export, calibration review, plan preview, confirmations) while the
   operator wants to keep an eye on the top + bottom status bars. For
   those modals, don't black out the whole screen: inset the backdrop
   between the two bars (which are opaque and sit flush at the viewport
   edges, so they stay fully visible AND clickable), and replace the
   dark fill with a faint tint + blur so the work area is only lightly
   blurred, not darkened. The dialog cards are short/centred, so they
   sit in the middle band and never cover a bar. Full-screen viewers /
   editors / terminal / login / lock keep their own immersive backdrop
   (intentionally not listed here). */
.modal-overlay,
.confirm-modal-overlay,
.siril-modal,
.plan-viz-backdrop,
.cal-review-backdrop,
.editor-export-backdrop {
    top: var(--statusbar-height);
    bottom: var(--activitybar-height);
    left: 0;
    right: 0;
    background: rgba(8, 11, 18, 0.10);
    backdrop-filter: blur(5px);
    -webkit-backdrop-filter: blur(5px);
}

/* GUIDE frame brightness/contrast sliders. Floating bottom-center over the
   guide camera image; affects only the <img> via a CSS filter (the star
   overlay canvas is a separate element and stays crisp/unfiltered). */
.guide-bc {
    position: absolute;
    bottom: 6px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    z-index: 4;
    font-size: 12px;
    color: var(--text-secondary);
}
.guide-bc input[type="range"] { width: 84px; }

/* SN-6: Image Blend — hosted in the FILES editor's modal chrome
   (.files-editor-modal/-panel). The blend-body is the editor-workspace
   equivalent: zoomable viewer + resizable side panel with large sliders. */
.blend-body { flex:1 1 auto; display:flex; min-height:0; margin-top:8px; }

/* Zoom/pan viewer */
.blend-viewer { flex:1 1 auto; position:relative; overflow:hidden; background:#000;
    min-width:0; cursor:grab; user-select:none; }
.blend-viewer.dragging { cursor:grabbing; }
.blend-viewer img { position:absolute; top:50%; left:50%;
    transform-origin:center center; will-change:transform; max-width:none; max-height:none; }
.blend-viewer-empty { position:absolute; inset:0; display:flex; align-items:center;
    justify-content:center; color:var(--text-secondary); font-size:13px; }
/* RGB histogram of the blended preview, pinned bottom-left of the viewer. */
.blend-hist { position:absolute; left:14px; bottom:14px; z-index:2;
    width:260px; height:72px; background:rgba(0,0,0,.55);
    border:1px solid var(--border); border-radius:8px; padding:0; }

/* Floating pill at the bottom-centre of the viewer; buttons use the app's
   standard .btn .btn-sm style (same as the editor's zoom control). */
.blend-zoom-ctl { position:absolute; left:50%; bottom:14px; transform:translateX(-50%);
    display:flex; align-items:center; gap:6px; background:rgba(0,0,0,.6);
    border:1px solid var(--border); border-radius:8px; padding:5px 8px; z-index:2; }
.blend-zoom-ctl .btn { font-variant-numeric:tabular-nums; }

/* Draggable divider */
.blend-resizer { flex:0 0 6px; cursor:col-resize; background:var(--border); }
.blend-resizer:hover { background:var(--accent); }

/* Side panel */
.blend-side { flex:0 0 auto; display:flex; flex-direction:column; min-height:0;
    border-left:1px solid var(--border); background:var(--bg-secondary, #11161e); }
.blend-side-scroll { flex:1 1 auto; overflow-y:auto; padding:12px;
    display:flex; flex-direction:column; gap:12px; }
.blend-actions { flex:0 0 auto; display:flex; gap:8px; justify-content:flex-end;
    padding:10px 12px; border-top:1px solid var(--border); }

/* Per-layer adjustment histogram (drag black/mid/white handles). */
.blend-phist-wrap { margin-bottom:10px; }
.blend-phist { width:100%; height:84px; display:block; background:#0a0d12;
    border:1px solid var(--border); border-radius:6px; cursor:ew-resize; touch-action:none; }
.blend-phist-stats { display:flex; justify-content:space-between; gap:8px;
    font-size:11px; color:var(--text-secondary); font-variant-numeric:tabular-nums;
    margin-top:4px; }

.blend-assign { display:flex; align-items:center; gap:10px; margin:8px 0 12px;
    padding:8px 10px; border:1px solid var(--border); border-radius:8px;
    background:var(--bg-input); }
.blend-assign-rows { flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:4px; }
.blend-assign-rows > div { display:flex; align-items:baseline; gap:8px; min-width:0; }
.blend-assign-tag { flex:0 0 96px; font-size:11px; font-weight:600; color:var(--accent);
    text-transform:uppercase; letter-spacing:.03em; }
.blend-assign-name { flex:1 1 auto; min-width:0; font-size:12px; color:var(--text-primary);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

.blend-group { border:1px solid var(--border); border-radius:8px; padding:12px; }
.blend-group-title { font-weight:600; font-size:12px; color:var(--accent);
    text-transform:uppercase; letter-spacing:.04em; margin-bottom:10px; }
.blend-row { display:flex; align-items:center; gap:10px; margin:12px 0; font-size:13px; }
.blend-row > span { flex:0 0 84px; color:var(--text-secondary); }
.blend-row select.input-sm { flex:1; height:32px; }
.blend-row output { flex:0 0 54px; text-align:right; font-variant-numeric:tabular-nums;
    color:var(--text-primary); }
.blend-group .btn.btn-sm { margin-top:6px; margin-right:6px; }

/* Large, easy-to-grab sliders (scoped to the side panel). */
.blend-row input[type="range"] { flex:1 1 auto; min-width:0; -webkit-appearance:none;
    appearance:none; height:8px; border-radius:4px; background:var(--border); outline:none; }
.blend-row input[type="range"]::-webkit-slider-thumb { -webkit-appearance:none; appearance:none;
    width:20px; height:20px; border-radius:50%; background:var(--accent);
    border:2px solid var(--bg-primary,#0d1117); cursor:pointer; }
.blend-row input[type="range"]::-moz-range-thumb { width:20px; height:20px; border-radius:50%;
    background:var(--accent); border:2px solid var(--bg-primary,#0d1117); cursor:pointer; }
/* app.js wraps every range in .range-with-controls ([-] slider [+]); it only
   inherits INLINE flex, and our blend sliders size via CSS, so the wrapper
   collapses to the steppers. Make it grow to fill the row. */
.blend-row .range-with-controls { flex:1 1 auto; min-width:0; }

@media (max-width: 820px) {
    .blend-body { flex-direction:column; }
    .blend-resizer { display:none; }
    .blend-side { width:auto !important; max-height:48vh; border-left:none;
        border-top:1px solid var(--border); }
}

/* ── Mosaic planner modal polish ─────────────────────────────────── */
.mosaic-summary {
    display: flex; align-items: center; gap: 18px;
    margin: 14px 0; padding: 14px;
    border: 1px solid var(--border, #2a2f3a); border-radius: 12px;
    background: rgba(255,255,255,0.025);
}
.mosaic-grid-preview {
    display: grid; gap: 3px; flex: 0 0 auto;
    width: 120px; height: 120px;
}
.mosaic-cell {
    display: flex; align-items: center; justify-content: center;
    border-radius: 4px; font-size: 11px; font-weight: 650;
    color: var(--accent, #4f8cff);
    background: color-mix(in srgb, var(--accent, #4f8cff) 16%, transparent);
    border: 1px solid color-mix(in srgb, var(--accent, #4f8cff) 35%, transparent);
}
.mosaic-stats { display: flex; flex-wrap: wrap; gap: 18px 22px; align-items: baseline; flex: 1; }
.mosaic-stat { display: flex; flex-direction: column; line-height: 1.15; }
.mosaic-stat-value { font-size: 22px; font-weight: 700; color: var(--text, #e8edf4); }
.mosaic-stat-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--text-muted, #9aa4b2); }
.mosaic-stats-note { flex-basis: 100%; margin: 2px 0 0; font-size: 11px; color: var(--text-muted, #9aa4b2); }
.mosaic-actions {
    display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; margin-top: 14px;
}

/* Mosaic planner form: three aligned columns, each row an inline
   label-left field (matching the app's Settings rows) with the input
   filling the remaining column width. Replaces the old label-above
   .field stack that looked cramped / disorganised. */
/* Close (X) button, top-right of the floating planner. */
.mosaic-frame { position: relative; }
.mosaic-close {
    position: absolute; top: 10px; right: 12px;
    width: 30px; height: 30px; line-height: 28px;
    padding: 0; border-radius: 6px;
    background: rgba(255,255,255,0.06);
    border: 1px solid var(--border, rgba(255,255,255,0.12));
    color: var(--text-muted, #94a3b8); font-size: 15px; cursor: pointer;
}
.mosaic-close:hover { background: rgba(255,255,255,0.14); color: #fff; }

.mosaic-form {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px 18px;
    margin-bottom: 16px;
}
.mosaic-form .mfield {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
}
.mosaic-form .mfield > span {
    flex: 0 0 auto;
    font-size: 13px;
    color: var(--text-muted, #94a3b8);
    white-space: nowrap;
}
.mosaic-form .mfield > input[type="number"],
.mosaic-form .mfield > input[type="text"] {
    flex: 1 1 auto;
    min-width: 0;          /* allow the input to shrink inside the grid cell */
    width: 100%;
}
.mosaic-form .mfield-check > input[type="checkbox"] {
    flex: 0 0 auto;
}
@media (max-width: 540px) {
    .mosaic-form { grid-template-columns: 1fr; }   /* phone: single column */
}

/* Floating (non-blocking) planner panel: no backdrop, anchored to one side so
   the SKY map + live grid overlay stay visible and interactive behind it. */
.mosaic-modal {
    position: fixed; inset: 0; z-index: 1100;
    pointer-events: none;                 /* clicks pass through to the SKY map */
    display: flex; align-items: center; justify-content: flex-end;
    padding: 24px;
}
.mosaic-modal .mosaic-frame {
    pointer-events: auto;                 /* the panel itself stays interactive */
    width: 100%; max-width: 600px;
    max-height: calc(100vh - 48px); overflow-y: auto;
    box-shadow: 0 24px 70px rgba(0,0,0,0.6), 0 2px 10px rgba(0,0,0,0.4);
}
@media (max-width: 720px) {
    /* On a phone the map is small; centre the panel and let it take the width. */
    .mosaic-modal { justify-content: center; padding: 12px; }
    .mosaic-modal .mosaic-frame { max-width: 100%; }
    .mosaic-summary { flex-direction: column; align-items: stretch; }
    .mosaic-grid-preview { width: 100%; height: 96px; }
}

/* ---- STORAGE-1: capture-disk suggestion (HOME) ---------------------
   Sits between the status cards and Get Started: visible on arrival, easy to
   dismiss, and never in the way of anything. Amber rather than red, because
   this is advice about a future problem, not a fault. */
.home-storage { margin: 18px 0; }
.storage-card {
    display: flex;
    align-items: center;
    gap: 16px;
    /* Room to breathe. The card sits between the status tiles and Get
       Started, and at 12px it read as a squeezed strip rather than a
       card. row-gap covers the wrapped layout on a narrow panel, where
       the actions drop under the text. */
    padding: 16px 20px;
    row-gap: 14px;
    /* Near-opaque, not a tint. HOME sits on a photographic sky background, and
       an 8% amber wash left the description sitting on stars: the text was
       there and unreadable, which is worse than not showing it. The panel
       colour carries just enough amber to still read as a warning. */
    background: color-mix(in srgb, var(--panel-bg, #161a22) 94%, #d98c00 6%);
    border: 1px solid rgba(217, 140, 0, 0.45);
    border-left: 3px solid var(--warn, #d98c00);
    border-radius: 10px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
    flex-wrap: wrap;
}
.storage-icon { font-size: 22px; line-height: 1; align-self: flex-start; margin-top: 2px; }
.storage-text { flex: 1 1 320px; min-width: 240px; }
.storage-text strong { display: block; font-size: 14px; }
/* --text-secondary, not --text-muted: muted is tuned for a flat panel and
   comes out too faint here even against the opaque background. */
.storage-text p {
    margin: 4px 0 0;
    font-size: 12.5px;
    color: var(--text-secondary, #b9c2cf);
    line-height: 1.5;
}
.storage-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    flex-wrap: wrap;
}
/* Disk names are long even by dropdown standards, so this one starts wider
   than the global select floor. The cap is the global one. */
.storage-actions select.input-sm { min-width: 260px; }
.storage-move { display: flex; align-items: center; gap: 6px; font-size: 12px; }
.storage-err { margin: 8px 2px 0; font-size: 12px; color: var(--danger, #e66); }

/* INDIAUTO: the note shown only when the equipment dialog opened by itself.
   Informational blue, not the amber the storage card uses: nothing is wrong
   here, the host is simply offering to do the setup. */
.indi-auto-note {
    font-size: 13px;
    margin: 0 0 12px;
    padding: 10px 12px;
    background: rgba(56, 139, 253, 0.10);
    border: 1px solid rgba(56, 139, 253, 0.30);
    border-left: 3px solid var(--accent, #388bfd);
    border-radius: 8px;
}

/* ───────────────────── SASPRO-C2: frame grading ─────────────────────
   Result table for a grading run. Rows are ranked best first; the keep
   flag comes from the server's selection rule, and moving a threshold
   re-ranks server-side rather than re-measuring anything. */
.grade-modal {
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: min(880px, 94vw);
    max-height: 86vh;
    padding: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-secondary);
}
.grade-head {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 15px;
    font-weight: 600;
}
.grade-head .muted { font-weight: 400; font-size: 12px; }
.grade-head .btn { margin-left: auto; }

.grade-progress { display: flex; align-items: center; gap: 10px; font-size: 12px; }
.grade-progress-track {
    flex: 1 1 auto;
    height: 8px;
    border-radius: 999px;
    background: var(--bg-tertiary, #0f1218);
    overflow: hidden;
}
.grade-progress-fill {
    height: 100%;
    background: var(--accent);
    transition: width .25s ease;
}

.grade-error {
    padding: 8px 10px;
    border: 1px solid var(--error, #dc2626);
    border-left-width: 4px;
    border-radius: 6px;
    background: rgba(220, 38, 38, 0.12);
    font-size: 12.5px;
}

.grade-thresholds,
.grade-blink {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    font-size: 12.5px;
}
.grade-thresholds label { display: flex; align-items: center; gap: 5px; }
.grade-thresholds .input-sm { width: 6em; }
.grade-thresholds .btn { margin-left: auto; }

/* The table is the tall part: it scrolls, the controls above stay put. */
.grade-table-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; }
.grade-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
}
.grade-table th,
.grade-table td {
    padding: 5px 8px;
    text-align: right;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
.grade-table th:nth-child(-n+2),
.grade-table td:nth-child(-n+2) { text-align: left; }
.grade-table th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--bg-secondary);
    color: var(--text-secondary);
    font-weight: 600;
}
.grade-table tbody tr { cursor: pointer; }
.grade-table tbody tr:hover { background: rgba(127, 127, 127, .12); }
.grade-name { max-width: 34ch; overflow: hidden; text-overflow: ellipsis; }

/* Kept vs dropped has to read at a glance while scrolling a hundred rows,
   so it is a row tint plus the tick, not the tick alone. */
.grade-table tr.grade-drop { color: var(--text-muted, #9aa4b2); }
.grade-table tr.grade-keep td:first-child { color: var(--success, #16a34a); font-weight: 700; }
.grade-table tr.grade-current { outline: 1px solid var(--accent); outline-offset: -1px; }

/* Fixed-size box: consecutive frames must land at the same scale and in the
   same place, or flipping between them compares framing instead of quality. */
.grade-blink-pane {
    flex: 0 0 auto;
    height: min(38vh, 320px);
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: #000;
    overflow: hidden;
}
.grade-blink-pane img { max-width: 100%; max-height: 100%; object-fit: contain; }

.grade-empty { padding: 18px 4px; text-align: center; }

/* ─────────────────────── SASPRO-D: editor masks ─────────────────────── */
.editor-mask-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin: 6px 0;
    font-size: 12px;
}
.editor-mask-actions label { display: flex; align-items: center; gap: 5px; }
.editor-mask-brush {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid var(--border);
}
.editor-mask-brush .muted { font-size: 11.5px; line-height: 1.35; }

