/* ===== Project Detail — 2226 Lab Notebook ===== */

/* Full-page layout: header -> main -> footer, no scroll on body */
html, body {
    overflow: hidden;
    height: 100vh;
    margin: 0;
}

body {
    display: flex;
    flex-direction: column;
}

main {
    flex: 1;
    min-height: 0;
    padding: 2px 0 0 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

header {
    flex-shrink: 0;
}

footer {
    display: none;
}

/* Full-width containers for project detail page */
header .container,
footer .container {
    max-width: none;
    padding: 0 16px;
}

/* When nav-meta is present, don't let nav-left hog all space */
header .container .nav-left {
    flex: 0 1 auto;
}

main > .container {
    max-width: none;
    margin: 0;
    padding: 0 16px;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* Tab content fills remaining space */
.tab-content.active {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.tab-content .section {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

#stages-wrapper {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* ── Project metadata strip (below header, above tabs) ── */
.project-meta-strip {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 4px 0;
    border-bottom: 1px solid var(--border-subtle);
    font-size: 12px;
    color: var(--text-secondary);
    flex-shrink: 0;
}

.meta-strip-desc {
    flex: 1;
    min-width: 0;
}

.meta-strip-desc .description {
    margin: 0;
    font-size: 12px;
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
    padding: 3px 6px;
    margin: -3px -6px;
    border-radius: var(--radius-sm);
}

.meta-strip-desc .description:hover {
    color: var(--text);
}

.meta-strip-right {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-shrink: 0;
}

.meta-strip-item {
    display: flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;
}

.meta-strip-item svg {
    flex-shrink: 0;
    opacity: 0.5;
}

.meta-strip-dash {
    color: var(--text-tertiary);
    margin: 0 1px;
}

.meta-strip-muted {
    color: var(--text-tertiary);
}

.meta-strip-item .editable-field {
    display: inline;
}

.meta-strip-item .clickable {
    padding: 2px 4px;
    margin: -2px -4px;
    border-radius: var(--radius-sm);
}

.meta-strip-item .tag {
    font-size: 11px;
    padding: 1px 6px;
}

.meta-strip-item .tags {
    display: flex;
    gap: 3px;
    align-items: center;
}

/* Compact tabs row — minimal vertical space */
.project-tabs-compact {
    display: flex;
    gap: 0;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--border);
    padding: 0;
    flex-shrink: 0;
}

.project-tabs-compact .tab-btn {
    padding: 4px 14px;
    font-size: 12px;
    gap: 0;
}

.project-tabs-compact .tab-btn svg {
    display: none;
}

/* ── Info tab ── */
.info-kv-grid {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 8px 16px;
    align-items: center;
    padding: 12px 0;
    border-bottom: 1px solid var(--border-subtle);
    font-size: 13px;
    max-width: 500px;
}

.info-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-tertiary);
}

.info-chip {
    font-size: 11px;
    padding: 1px 7px;
    background: var(--bg-secondary);
    border-radius: 10px;
    color: var(--text-secondary);
}

.info-description-area {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-top: 12px;
    flex: 1;
    min-height: 0;
}

.info-description-box {
    flex: 1;
    min-height: 200px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius);
    padding: 12px 16px;
    background: var(--bg);
}

/* Markdown rendered content */
.md-render {
    font-size: 14px;
    line-height: 1.7;
    color: var(--text-secondary);
    word-wrap: break-word;
}

.md-render.clickable {
    cursor: pointer;
    border-radius: var(--radius);
}

.md-render.clickable:hover {
    color: var(--text);
    background: var(--bg-secondary);
    margin: -12px -16px;
    padding: 12px 16px;
}

.md-render h1, .md-render h2, .md-render h3 {
    color: var(--text);
    margin: 16px 0 8px;
    line-height: 1.3;
}

.md-render h1 { font-size: 20px; }
.md-render h2 { font-size: 17px; }
.md-render h3 { font-size: 15px; }

.md-render h1:first-child, .md-render h2:first-child, .md-render h3:first-child {
    margin-top: 0;
}

.md-render p { margin: 8px 0; }
.md-render p:first-child { margin-top: 0; }
.md-render p:last-child { margin-bottom: 0; }

.md-render ul, .md-render ol {
    padding-left: 20px;
    margin: 8px 0;
}

.md-render code {
    font-size: 13px;
    background: var(--bg-secondary);
    padding: 1px 5px;
    border-radius: 3px;
}

.md-render pre {
    background: var(--bg-secondary);
    padding: 10px 14px;
    border-radius: var(--radius);
    overflow-x: auto;
    margin: 8px 0;
}

.md-render pre code {
    padding: 0;
    background: none;
}

.md-render a {
    color: var(--primary);
    text-decoration: none;
}

.md-render a:hover {
    text-decoration: underline;
}

.md-render blockquote {
    border-left: 3px solid var(--border);
    padding-left: 12px;
    margin: 8px 0;
    color: var(--text-tertiary);
}

/* Description edit textarea */
.desc-edit-textarea {
    width: 100%;
    height: calc(100vh - 450px);
    min-height: 120px;
    max-height: 50vh;
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    font-size: 13px !important;
    line-height: 1.5;
    resize: vertical;
    box-sizing: border-box;
    overflow-y: auto;
    padding: 8px 10px !important;
}

/* Keep edit actions always visible */
.info-description-box .edit-form {
    display: flex;
    flex-direction: column;
}

.info-description-box .edit-actions {
    flex-shrink: 0;
    padding-top: 8px;
    position: sticky;
    bottom: 0;
    background: var(--bg);
}

.btn-danger {
    background: transparent;
    color: var(--text-secondary);
    border: 1px solid var(--border);
    cursor: pointer;
    border-radius: var(--radius);
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 12px;
}

.btn-danger:hover {
    color: var(--danger, #ef4444);
    border-color: var(--danger, #ef4444);
    background: rgba(239, 68, 68, 0.05);
}

/* ── Unified single-row header (kept for fallback) ── */
.page-header-unified {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 4px 0 0 0;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
    min-height: 0;
}

.page-header-unified .header-left {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 1;
    min-width: 0;
    overflow: hidden;
}

.page-header-unified .header-desc {
    flex-shrink: 1;
    min-width: 0;
    max-width: 300px;
}

.page-header-unified .header-desc .description {
    margin: 0;
    font-size: 12px;
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 2px 6px;
    margin: -2px -6px;
}

.page-header-unified .header-meta-inline {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    color: var(--text-secondary);
    flex-wrap: nowrap;
    white-space: nowrap;
    overflow: hidden;
}

.page-header-unified .header-meta-inline .meta-item {
    display: flex;
    align-items: center;
    gap: 3px;
}

.page-header-unified .header-meta-inline .meta-item svg {
    flex-shrink: 0;
    opacity: 0.5;
}

.page-header-unified .header-meta-inline .meta-sep {
    color: var(--text-tertiary);
    margin: 0 1px;
}

.page-header-unified .header-meta-inline .meta-divider {
    width: 1px;
    height: 12px;
    background: var(--border);
    flex-shrink: 0;
}

.page-header-unified .header-meta-inline .tag {
    font-size: 10px;
    padding: 0px 5px;
}

.page-header-unified .header-meta-inline .tags {
    display: flex;
    gap: 3px;
    align-items: center;
}

.page-header-unified .header-meta-inline .editable-field {
    display: inline;
}

.page-header-unified .header-meta-inline .clickable {
    padding: 1px 4px;
    margin: -1px -4px;
}

.page-header-unified .header-tabs {
    display: flex;
    gap: 0;
    flex-shrink: 0;
    align-self: stretch;
}

.page-header-unified .header-tabs .tab-btn {
    padding: 6px 14px;
    font-size: 13px;
    border-bottom-width: 2px;
}

/* Icon-only danger button (delete) */
.btn-icon-danger {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: none;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    transition: all 0.15s;
}

.btn-icon-danger:hover {
    background: color-mix(in srgb, var(--danger, #ef4444) 13%, transparent);
    color: var(--danger, #ef4444);
}

.header-meta-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: nowrap;
    font-size: 13px;
    color: var(--text-secondary);
    overflow: hidden;
}

.header-meta-toolbar .meta-item {
    display: flex;
    align-items: center;
    gap: 5px;
}

.header-meta-toolbar .meta-item svg {
    flex-shrink: 0;
    opacity: 0.6;
}

.header-meta-toolbar .meta-sep {
    color: var(--text-tertiary);
    margin: 0 2px;
}

.header-meta-toolbar .meta-divider {
    width: 1px;
    height: 14px;
    background: var(--border);
    flex-shrink: 0;
}

/* Share management */
.share-manage-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border: none;
    background: none;
    cursor: pointer;
    color: var(--text-tertiary);
    border-radius: 4px;
    transition: all 0.15s;
    margin-left: 2px;
}

.share-manage-btn:hover {
    background: var(--bg-secondary);
    color: var(--text);
}

.share-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 8px;
    border-radius: 6px;
    margin-bottom: 2px;
}

.share-row:hover {
    background: var(--bg-secondary);
}

.share-name {
    font-size: 13px;
    font-weight: 500;
}

.share-remove-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border: none;
    background: none;
    cursor: pointer;
    color: var(--text-tertiary);
    border-radius: 4px;
    transition: all 0.15s;
}

.share-remove-btn:hover {
    background: rgba(239, 68, 68, 0.1);
    color: var(--danger, #ef4444);
}

.header-meta-toolbar .tag {
    font-size: 12px;
    padding: 1px 8px;
}

.header-meta-toolbar .tags {
    display: flex;
    gap: 4px;
    align-items: center;
}

.header-meta-toolbar .no-tags {
    font-size: 12px;
    color: var(--text-tertiary);
}

.header-meta-toolbar .editable-field {
    display: inline;
}

.header-meta-toolbar .edit-hint {
    font-size: 11px;
}

/* Editable fields */
.editable-field {
    position: relative;
}

.clickable {
    cursor: pointer;
    transition: background 0.2s;
    padding: 4px 8px;
    margin: -4px -8px;
    border-radius: var(--radius);
}

.clickable:hover {
    background: var(--bg-secondary);
}

.edit-hint {
    display: none;
    font-size: 12px;
    color: var(--text-secondary);
    font-weight: 400;
    margin-left: 8px;
}

.clickable:hover .edit-hint {
    display: inline;
}

.edit-form {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.edit-form input, .edit-form textarea {
    font-size: 16px;
    padding: 8px 12px;
}

.edit-actions {
    display: flex;
    gap: 8px;
}

.btn-sm {
    padding: 6px 12px;
    font-size: 13px;
}

.project-meta {
    display: flex;
    gap: 24px;
    margin-top: 16px;
    color: var(--text-secondary);
    font-size: 14px;
}

.project-meta-item {
    display: flex;
    align-items: center;
    gap: 6px;
}

.tags {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.tag {
    background: var(--bg-secondary);
    padding: 4px 10px;
    border-radius: var(--radius-sm);
    font-size: 12px;
    color: var(--text-secondary);
}

.no-tags {
    color: var(--text-secondary);
    font-style: italic;
}

.status-select {
    padding: 6px 12px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    font-size: 13px;
    background: var(--bg);
    cursor: pointer;
}

.badge-started { color: var(--status-queued); }
.badge-in-progress { color: var(--status-active); }
.badge-completed { color: var(--status-complete); }
.badge-bacterial { color: #3d3d9e; }
.badge-fungal { color: #8b4513; }

.type-checkbox {
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    font-size: 13px;
}

.type-checkbox input {
    width: 16px;
    height: 16px;
    cursor: pointer;
}

.section {
    margin-bottom: 48px;
}
#tab-workflow .section {
    margin-bottom: 0;
}

.section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
}

.section-title {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.upload-area {
    background: var(--bg-secondary);
    border: 2px dashed var(--border);
    border-radius: var(--radius);
    padding: 48px;
    text-align: center;
    margin-bottom: 32px;
}

.upload-area p {
    color: var(--text-secondary);
    font-size: 14px;
    margin-bottom: 16px;
}

.file-list {
    display: flex;
    flex-direction: column;
    gap: 1px;
    background: var(--border);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
}

.file-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 20px;
    background: var(--bg);
}

.file-info {
    display: flex;
    align-items: center;
    gap: 12px;
}

.file-icon {
    width: 32px;
    height: 32px;
    color: var(--text-secondary);
}

.file-details {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.file-name {
    font-weight: 500;
    font-size: 15px;
}

.file-size {
    color: var(--text-secondary);
    font-size: 13px;
}

.file-actions {
    display: flex;
    gap: 8px;
}

/* Compact file item for folder view */
.file-item.compact {
    padding: 8px 12px;
    border-radius: var(--radius);
    margin-bottom: 4px;
    background: var(--bg);
    border: 1px solid var(--border);
}

.file-item.compact .file-info {
    gap: 8px;
}

.file-item.compact .file-details {
    flex-direction: row;
    gap: 8px;
    align-items: center;
}

.file-item.compact .file-name {
    font-size: 13px;
}

.file-item.compact .file-size {
    font-size: 12px;
}

.file-item.compact .file-actions {
    gap: 4px;
}

.file-item.compact .btn-sm {
    padding: 4px 8px;
    font-size: 12px;
}

/* Stage folder header */
.stage-folder-header {
    user-select: none;
}

.stage-folder-header:hover {
    background: var(--bg) !important;
}

.stage-folder-header.collapsed .folder-chevron {
    transform: rotate(0deg);
}

.stage-folder-header:not(.collapsed) .folder-chevron {
    transform: rotate(90deg);
}

.folder-contents {
    overflow: hidden;
    transition: max-height 0.2s ease-out;
}

.stage-folder-header.collapsed + .folder-contents {
    display: none;
}

.empty-state {
    text-align: center;
    padding: 60px 20px;
    color: var(--text-secondary);
    background: var(--bg-secondary);
    border-radius: var(--radius);
}

/* ===== Upload Dropzone ===== */
.upload-dropzone {
    background: var(--bg-secondary);
    border: 2px dashed var(--border);
    border-radius: var(--radius-lg);
    padding: 24px;
    margin-bottom: 16px;
    transition: all 0.2s;
}

.upload-dropzone:hover,
.upload-dropzone.drag-over {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.dropzone-content {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    color: var(--text-secondary);
}

.dropzone-content svg {
    flex-shrink: 0;
}

.dropzone-text {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
}

.upload-dropzone .upload-progress {
    margin-top: 16px;
}

.upload-dropzone .progress-bar {
    height: 6px;
    background: var(--border);
    border-radius: 3px;
    overflow: hidden;
}

.upload-dropzone .progress-bar-fill {
    height: 100%;
    background: var(--accent);
    transition: width 0.3s;
}

.upload-dropzone .upload-status {
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 8px;
    text-align: center;
}

/* ===== OneDrive-style File Browser ===== */
.files-browser {
    background: var(--bg);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    overflow: hidden;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.storage-content.active {
    display: block;
    overflow-y: auto;
    flex: 1;
    min-height: 0;
    /* Fade-out shadow at bottom when scrollable */
    background:
        linear-gradient(var(--bg) 30%, transparent),
        linear-gradient(transparent, var(--bg) 70%) 0 100%,
        radial-gradient(farthest-side at 50% 0, rgba(0,0,0,0.12), transparent),
        radial-gradient(farthest-side at 50% 100%, rgba(0,0,0,0.12), transparent) 0 100%;
    background-repeat: no-repeat;
    background-size: 100% 40px, 100% 40px, 100% 8px, 100% 8px;
    background-attachment: local, local, scroll, scroll;
}

.storage-tabs {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--border);
    background: var(--bg-secondary);
}

.storage-tab {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 20px;
    border: none;
    background: none;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-secondary);
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: all 0.15s;
}

.storage-tab:hover {
    color: var(--text);
    background: var(--bg-secondary);
}

.storage-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
    background: var(--bg);
}

.storage-tab svg {
    opacity: 0.7;
}

.storage-tab.active svg {
    opacity: 1;
    stroke: var(--accent);
}

.storage-count {
    background: var(--border);
    color: var(--text-secondary);
    font-size: 12px;
    font-weight: 600;
    padding: 2px 6px;
    border-radius: 10px;
}

.storage-tab.active .storage-count {
    background: var(--accent);
    color: white;
}

.storage-content {
    display: none;
}

.cache-notice {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    background: rgba(217, 119, 6, 0.06);
    color: var(--status-queued);
    font-size: 13px;
    border-bottom: 1px solid var(--border);
}

.file-search-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border-bottom: 1px solid var(--border);
    background: var(--bg);
    flex-shrink: 0;
}

.file-search-bar svg {
    color: var(--text-tertiary);
    flex-shrink: 0;
}

.file-search-input {
    border: none;
    background: none;
    font-size: 13px;
    color: var(--text);
    outline: none;
    width: 100%;
}

.file-search-input::placeholder {
    color: var(--text-tertiary);
}

.file-name-clickable {
    cursor: pointer;
}

.file-name-clickable:hover {
    color: var(--accent);
    text-decoration: underline;
}

.file-table {
    width: 100%;
}

.file-table-header {
    display: grid;
    grid-template-columns: 1fr 140px 100px 100px;
    padding: 10px 16px;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border);
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.file-table .folder-row,
.file-table .file-row {
    display: grid;
    grid-template-columns: 1fr 140px 100px 100px;
    align-items: center;
    padding: 10px 16px;
    border-bottom: 1px solid var(--border-subtle);
    cursor: pointer;
    transition: background 0.1s;
}

.file-table .folder-row:hover,
.file-table .file-row:hover {
    background: var(--bg-secondary);
}

.file-table .file-row:hover .col-actions {
    opacity: 1;
}

.col-name {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    color: var(--text);
    min-width: 0;
}

.folder-icon {
    flex-shrink: 0;
}

.file-type-icon {
    flex-shrink: 0;
}

.folder-name,
.file-name-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.folder-name {
    font-weight: 500;
}

.folder-chevron {
    flex-shrink: 0;
    margin-left: 4px;
    transition: transform 0.2s;
    color: var(--text-tertiary);
}

.file-table .folder-row.collapsed .folder-chevron {
    transform: rotate(-90deg);
}

.col-modified,
.col-size {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-tertiary);
    display: flex;
    align-items: center;
}

.col-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    opacity: 0;
    transition: opacity 0.15s;
}

.action-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: none;
    background: none;
    cursor: pointer;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    transition: all 0.15s;
}

.action-btn:hover {
    background: var(--bg-secondary);
    color: var(--text);
}

.action-btn.action-delete:hover {
    background: rgba(220, 38, 38, 0.06);
    color: var(--status-failed);
}

.folder-children {
    background: var(--bg-secondary);
}

.file-table .folder-children .file-row {
    padding-left: 52px;
}

.file-table .folder-row.collapsed + .folder-children {
    display: none;
}

.empty-files {
    text-align: center;
    padding: 60px 20px;
    color: var(--text-tertiary);
}

.empty-files h4 {
    margin: 16px 0 8px;
    color: var(--text-secondary);
    font-weight: 500;
}

.empty-files p {
    margin: 0;
    font-size: 14px;
}

/* Modal — .modal-overlay/.modal/.modal-actions shell now lives in base.css
   (emitted by the modal()/modal_actions() macros in partials/modal_macro.html).
   Page-specific overrides only: */

/* Shift stage editor left when AI Planner panel is open */
body.ai-panel-open .modal-overlay {
    padding-right: 400px;
}

.modal h2 {
    font-size: 24px;
    font-weight: 600;
    margin-bottom: 8px;
}

.modal > p {
    color: var(--text-secondary);
    font-size: 14px;
    margin-bottom: 24px;
}

.invite-result {
    margin-top: 16px;
    padding: 16px;
    background: var(--bg-secondary);
    border-radius: var(--radius-lg);
}

.invite-result label {
    font-size: 12px;
    margin-bottom: 6px;
}

.invite-result input {
    font-size: 14px;
    background: var(--bg);
}

/* Checkbox */
.checkbox-label {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    font-size: 15px;
}

.checkbox-label input {
    width: 18px;
    height: 18px;
}

/* Uppy overrides */
.uppy-Dashboard-inner {
    background: var(--bg) !important;
    border: 1px solid var(--border) !important;
}

.uppy-Dashboard-AddFiles {
    border: none !important;
}

/* Compact upload / drop zone */
.compact-upload {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 20px;
    background: var(--bg-secondary);
    border: 2px dashed var(--border);
    border-radius: var(--radius);
    margin-bottom: 32px;
    transition: border-color 0.2s, background 0.2s;
}

.compact-upload.drag-over {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.compact-upload label {
    color: var(--text-secondary);
    font-size: 14px;
}

.compact-upload input[type="file"] {
    display: none;
}

.upload-progress {
    flex: 1;
    display: none;
}

.upload-progress.active {
    display: block;
}

.progress-bar {
    height: 6px;
    background: var(--border);
    border-radius: 3px;
    overflow: hidden;
}

.progress-bar-fill {
    height: 100%;
    background: var(--accent);
    transition: width 0.3s;
}

.upload-status {
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 4px;
}

/* Preview modal */
.preview-modal {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.8);
    z-index: 300;
    padding: 40px;
}

.preview-modal.active {
    display: flex;
    flex-direction: column;
}

.preview-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
}

.preview-header h3 {
    color: white;
    font-size: 16px;
    font-weight: 500;
}

.preview-close {
    background: none;
    border: none;
    color: white;
    font-size: 24px;
    cursor: pointer;
    padding: 8px;
}

.preview-content {
    flex: 1;
    background: var(--bg);
    border-radius: var(--radius);
    overflow: auto;
}

.preview-content iframe {
    width: 100%;
    height: 100%;
    border: none;
}

.preview-content pre {
    padding: 20px;
    margin: 0;
    font-family: var(--font-mono);
    font-size: 13px;
    line-height: 1.5;
    white-space: pre-wrap;
    word-wrap: break-word;
}

.preview-content .csv-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

.preview-content .csv-table th,
.preview-content .csv-table td {
    padding: 8px 12px;
    border: 1px solid var(--border);
    text-align: left;
}

.preview-content .csv-table th {
    background: var(--bg-secondary);
    font-weight: 600;
}

.preview-content .notebook-cell {
    border-bottom: 1px solid var(--border);
    padding: 16px;
}

.preview-content .notebook-cell.markdown {
    background: var(--bg);
}

.preview-content .notebook-cell.code {
    background: var(--bg-secondary);
}

.preview-content .notebook-cell pre {
    padding: 12px;
    background: #282c34;
    color: #abb2bf;
    border-radius: var(--radius);
}

.preview-content .cell-output {
    margin-top: 8px;
    padding: 8px 12px;
    background: var(--bg-secondary);
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: 12px;
}

.btn-preview {
    cursor: pointer;
}

.btn-preview:hover {
    background: var(--bg-secondary);
    color: var(--accent);
}

/* ===== Stages ===== */
.stages-section {
    margin-top: 0;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.stages-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
}

.stages-header h3 {
    font-size: 16px;
    font-weight: 600;
}

.stages-pipeline {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.stage-card {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 16px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    position: relative;
    transition: opacity 0.2s;
}

/* Stage card status indicators (no opacity dimming — keep nodes readable) */
.stage-card[data-status="completed"] { border-left: 2px solid var(--status-complete); }
.stage-card[data-status="pending"] { border-style: dashed; }
.stage-card[data-status="running"] { border-left: 2px solid var(--status-active); }
.stage-card[data-status="failed"] { border-left: 2px solid var(--status-failed); }

/* Class-based stage card states */
.stage-card.stage-running {
    border-left: 2px solid var(--status-active);
}

.stage-card.stage-complete {
    border-left: 2px solid var(--status-complete);
}

.stage-card.stage-failed {
    border-left: 2px solid var(--status-failed);
}

.stage-order {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--bg-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 13px;
    flex-shrink: 0;
}

.stage-content {
    flex: 1;
}

.stage-header {
    display: flex;
    gap: 8px;
    margin-bottom: 8px;
}

.stage-content h4 {
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 4px;
}

.stage-desc {
    font-size: 13px;
    color: var(--text-secondary);
    margin-bottom: 8px;
}

/* Stage type badges — monospace text, no background */
/* Typography unification (app-shell review §4.6): the type-tag and status
   pill used to be set in --font-mono, sitting directly next to the sans-serif
   stage/window title (DAG node cards, window titlebars) — two competing type
   systems in one line, and a misapplied signal (monospace means "copy this
   verbatim as code/data" — an enum word like PYTHON or a status word like
   completed is neither). Both now share --font-sans with the title, one
   step down a 1.25 type scale (14px title → ~11px tag/pill). */
.stage-type-badge {
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--text-secondary);
    padding: 2px 0;
}

.badge-manual { color: var(--text-secondary); }
.badge-rdp { color: var(--text-secondary); }
.badge-python { color: var(--text-secondary); }
.badge-r { color: var(--text-secondary); }
.badge-cleanup { color: var(--text-secondary); }

/* Stage status badges — no background */
.stage-status-badge {
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 600;
    padding: 2px 0;
}

.status-pending { color: var(--text-tertiary); }
.status-queued { color: var(--status-queued); }
.status-running { color: var(--status-active); }
.status-complete { color: var(--status-complete); }
.status-completed { color: var(--status-complete); }
.status-partial { color: var(--status-queued); }
.status-failed { color: var(--status-failed); }
.status-cancelling { color: var(--status-queued); }
.status-cancelled { color: var(--text-tertiary); }

/* review §3.2 — "Completed" must not stay clean green when the stage's own
   log recorded errors. amber, not clean green — reuses --status-queued
   (already the app's amber token, see .status-queued/.status-partial above)
   rather than inventing a new color for the same "needs attention" meaning. */
.stage-status-badge.has-log-errors,
.stage-status-badge.status-completed.has-log-errors {
    color: var(--status-queued);
}

.stage-files {
    display: flex;
    gap: 12px;
    margin-bottom: 8px;
}

.file-count {
    font-size: 12px;
    color: var(--text-secondary);
}

/* Compact file badges with hover dropdown */
.stage-files-compact {
    position: relative;
    margin-top: 8px;
}

.files-badges {
    display: flex;
    gap: 8px;
}

.file-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 12px;
    background: var(--bg-secondary);
    color: var(--text-secondary);
    cursor: default;
}

.files-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: 4px;
    min-width: 260px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
    z-index: 100;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-4px);
    transition: all 0.15s ease;
    max-height: 200px;
    overflow-y: auto;
    overflow-x: hidden;
}

.stage-files-compact:hover .files-dropdown {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.files-section {
    padding: 6px 0;
}

.files-section:not(:last-child) {
    border-bottom: 1px solid var(--border);
}

.files-section-label {
    padding: 2px 8px 3px;
    font-size: 11px;
    font-weight: 500;
    color: var(--text-secondary);
}

.files-dropdown .file-item {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    font-size: 12px;
    color: var(--text);
    text-decoration: none;
}

.files-dropdown .file-item:hover {
    background: var(--bg-secondary);
}

.files-dropdown .file-item:hover {
    color: var(--accent);
}

.files-dropdown .file-icon {
    flex-shrink: 0;
    opacity: 0.5;
    width: 10px;
    height: 10px;
}

.files-dropdown .file-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12px;
    font-weight: 400;
}

.stage-actions {
    display: flex;
    gap: 8px;
}

.btn-icon {
    width: 32px;
    height: 32px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--bg);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
}

.btn-icon:hover {
    background: var(--bg-secondary);
    color: var(--text);
}

/* Finding #1 (08.17.26-notebook-ux-polish) -- see stage_detail.html's "Open
   in new window" button. Scoped to this one instance via an added modifier
   class so the many other fixed-32x32 .btn-icon uses elsewhere (Delete,
   Run, Cancel, ...) are untouched. */
.btn-icon-labeled {
    width: auto;
    padding: 0 12px 0 9px;
    gap: 6px;
}
.btn-icon-label {
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
}

.btn-icon.btn-run {
    color: var(--accent);
    border-color: var(--accent);
}

.btn-icon.btn-run:hover {
    background: var(--accent);
    color: white;
}

.btn-icon.btn-delete:hover {
    background: rgba(220, 38, 38, 0.06);
    border-color: var(--status-failed);
    color: var(--status-failed);
}

.btn-icon.btn-cancel {
    color: var(--status-queued);
    border-color: var(--status-queued);
}

.btn-icon.btn-cancel:hover {
    background: var(--status-queued);
    color: white;
}

.btn-icon.btn-cancel:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.stage-connector {
    display: flex;
    justify-content: center;
    padding: 4px 0;
    color: var(--border);
}

.empty-stages {
    text-align: center;
    padding: 40px;
    color: var(--text-secondary);
    background: var(--bg-secondary);
    border-radius: var(--radius);
}

.modal-large {
    max-width: 800px;
}

/* Inline editable fields */
.editable-title, .editable-description {
    cursor: text;
    padding: 2px 6px;
    margin: -2px -6px;
    border-radius: var(--radius-sm);
    transition: background 0.15s, outline 0.15s;
    outline: 2px solid transparent;
}

.editable-title:hover, .editable-description:hover {
    background: var(--bg-secondary);
}

.editable-title:focus, .editable-description:focus {
    background: var(--bg);
    outline: 2px solid var(--accent);
}

.editable-description {
    min-height: 1.5em;
    color: var(--text-secondary);
}

.editable-description:empty::before {
    content: attr(data-placeholder);
    color: var(--text-muted, #888);
    font-style: italic;
}

.btn-cancel-header {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    font-size: 12px;
    border-radius: 6px;
    border: 1px solid var(--status-queued);
    background: transparent;
    color: var(--status-queued);
    cursor: pointer;
    margin-left: auto;
    margin-right: 8px;
    transition: background 0.15s, color 0.15s;
}
.btn-cancel-header:hover {
    background: var(--status-queued);
    color: white;
}

.stage-detail-content {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    overflow-x: hidden;
}

/* Larger modal for stage details with code editor */
#stage-detail-modal .modal {
    max-width: 900px;
    width: 90vw;
    max-height: 85vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

#stage-detail-modal .modal-header {
    flex-shrink: 0;
}

/* Monaco editor - sized via flex in code-workspace */
.monaco-editor-container {
    min-height: 200px;
}

/* Fullscreen editor mode */
.script-section.fullscreen,
.code-workspace.fullscreen {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2000;
    background: var(--bg);
    padding: 20px;
    display: flex;
    flex-direction: column;
}

.script-section.fullscreen .monaco-editor-container,
.code-workspace.fullscreen .monaco-editor-container {
    flex: 1;
    height: auto !important;
    min-height: 0;
}

.script-section.fullscreen h4,
.code-workspace.fullscreen .code-toolbar {
    margin-bottom: 0;
}

.stage-info {
    margin-bottom: 20px;
}

.stage-timestamps {
    display: flex;
    gap: 16px;
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 8px;
}

.stage-files-section h4 {
    font-size: 14px;
    margin: 16px 0 8px;
}

.file-list-compact {
    list-style: none;
    padding: 0;
    margin: 0;
}

.file-list-compact li {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
}

.file-list-compact li:last-child {
    border-bottom: none;
}

.file-list-compact .file-name {
    flex: 1;
    font-size: 13px;
}

.file-list-compact .file-size {
    font-size: 12px;
    color: var(--text-secondary);
}

.no-files {
    font-size: 13px;
    color: var(--text-secondary);
    font-style: italic;
}

.script-section {
    margin-top: 20px;
}

.script-editor {
    width: 100%;
    font-family: var(--font-mono);
    font-size: 13px;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: #1e1e1e;
    color: #d4d4d4;
    resize: vertical;
}

.logs-section {
    margin-top: 20px;
}

.logs-container {
    background: #1e1e1e;
    color: #d4d4d4;
    padding: 12px;
    border-radius: var(--radius);
    font-family: var(--font-mono);
    font-size: 12px;
    flex: 1;
    min-height: 150px;
    overflow-y: auto;
}

.logs-container pre {
    margin: 0;
    white-space: pre-wrap;
}

.no-logs {
    color: var(--text-tertiary);
    font-style: italic;
}

/* review §3.2 — ERROR/WARN log lines get a left-border accent + tinted
   background (GitHub Actions ##[error] convention), not full-line red —
   full-line color is harder to read at length and the .logs-container is
   a fixed-dark terminal panel regardless of app theme, so these are literal
   colors tuned for that background rather than the light/dark --status-*
   tokens (see app/shared_templates.py:render_log_lines). */
.log-line {
    white-space: pre-wrap;
    word-wrap: break-word;
    line-height: 1.5;
    padding: 0 0 0 8px;
    border-left: 3px solid transparent;
}

.log-line-error {
    border-left-color: #f85149;
    background: rgba(248, 81, 73, 0.12);
    color: #ffb4ab;
}

.log-line-warn {
    border-left-color: #d29922;
    background: rgba(210, 153, 34, 0.12);
    color: #f0c674;
}

/* H1 (code review, 2026-07-01) — shown once at the top of the Logs tab when
   a severity type was suppressed as noise (see shared_templates.py _is_noisy)
   instead of being flagged line-by-line. Neutral, not alarm-colored — this
   is reassurance ("we checked, it's not real"), not a warning itself. */
.log-line-noise-notice {
    border-left-color: var(--border);
    background: var(--bg-secondary);
    color: var(--text-secondary);
    font-style: italic;
    margin-bottom: 4px;
}

/* H1 re-review (code review, 2026-07-01, Heng Li) — a collapsed marker
   replacing an entire run of noisy-classified lines (see
   shared_templates.py render_html) instead of one <div> per suppressed
   line; a 43,000-line pathological log collapses to a handful of these
   instead of 43,000 DOM nodes. Centered, muted — reads as a fold marker,
   not content. */
.log-line-collapsed {
    text-align: center;
    color: var(--text-tertiary);
    font-style: italic;
    padding: 2px 8px;
}

.logs-severity-count {
    font-family: var(--font-mono);
    font-weight: 500;
    padding: 2px 8px;
    border-radius: var(--radius-sm);
}

.logs-severity-error {
    color: var(--status-failed);
    background: rgba(220, 38, 38, 0.1);
}

.logs-severity-warn {
    color: var(--status-queued);
    background: rgba(217, 119, 6, 0.1);
}

.error-message {
    margin-top: 8px;
    padding: 12px;
    background: rgba(220, 38, 38, 0.04);
    border: 1px solid var(--status-failed);
    border-radius: var(--radius);
    color: var(--status-failed);
    font-size: 13px;
}

.loading {
    text-align: center;
    padding: 20px;
    color: var(--text-secondary);
}

.ownership-info {
    display: flex;
    gap: 24px;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
    font-size: 13px;
    color: var(--text-secondary);
}

.ownership-info-item {
    display: flex;
    align-items: center;
    gap: 6px;
}

.ownership-info-item svg {
    flex-shrink: 0;
}

/* File assignment styles */
.available-files-list .file-list-compact li {
    transition: background 0.2s;
}

.available-files-list .file-list-compact li:hover {
    background: var(--bg);
}

.no-files-item {
    background: transparent !important;
}

/* Spinner animation */
@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}
.spin {
    animation: spin 1s linear infinite;
}

/* Pulse animation for queued */
@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}
.pulse {
    animation: pulse 1.5s ease-in-out infinite;
}

/* Breathe animation reference (defined in base.css) */
.breathe {
    animation: breathe 2s ease-in-out infinite;
}

/* Toast animations */
@keyframes slideIn {
    from { transform: translateX(100%); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}
@keyframes slideOut {
    from { transform: translateX(0); opacity: 1; }
    to { transform: translateX(100%); opacity: 0; }
}

/* Progress bar for running stages */
.stage-progress {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
}

.progress-bar-mini {
    flex: 1;
    height: 4px;
    background: var(--border);
    border-radius: 2px;
    overflow: hidden;
    max-width: 150px;
}

.progress-bar-fill-mini {
    height: 100%;
    background: var(--accent);
    border-radius: 2px;
    transition: width 0.3s;
}

.progress-bar-fill-mini.indeterminate {
    width: 30%;
    animation: indeterminate 1.5s ease-in-out infinite;
}

@keyframes indeterminate {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(400%); }
}

/* Compact card progress bar — thin bottom edge */
.compact-progress-bar {
    height: 2px;
    background: var(--border);
    border-radius: 0 0 var(--radius) var(--radius);
    overflow: hidden;
    margin: 6px -10px -8px -10px; /* flush with card edges */
}
.compact-progress-fill {
    height: 100%;
    background: var(--accent);
    transition: width 0.3s;
}
.compact-progress-fill.indeterminate {
    width: 30%;
    animation: indeterminate 1.5s ease-in-out infinite;
}

.progress-text {
    font-size: 12px;
    color: var(--text-secondary);
}

#cy-pipeline {
    width: 100%;
    min-height: 300px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-secondary);
}

/* Project Tabs */
.project-tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--border);
    padding-bottom: 0;
    flex-shrink: 0;
}
.tab-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    transition: all 0.2s;
}
.tab-btn:hover {
    color: var(--text);
    background: var(--bg-secondary);
}
.tab-btn.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
.tab-btn svg {
    opacity: 0.7;
}
.tab-btn.active svg {
    opacity: 1;
}
.tab-content {
    display: none;
}
.tab-content.active {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}
/* Non-workflow tabs scroll internally since html/body overflow is hidden */
#tab-history.active {
    overflow-y: auto;
}
/* Files tab uses flex layout — scrolling happens inside .storage-content */
#tab-files.active {
    overflow: hidden;
}
#tab-files .upload-dropzone {
    flex-shrink: 0;
}

/* ── Floating stage windows ──
   Single, canonical home for all window chrome. The live rules formerly lived
   in an inline <style> in partials/stages_list.html (which loaded after this
   sheet via HTMX and won on same-specificity); they have been merged here so
   there is one home and no load-order ambiguity. IDE/macOS chrome polish +
   viewer-scoped non-select are layered on at the bottom of this block.
   (08.02.26: dropped a stale duplicate `#stage-windows-container` rule that
   used to sit just above this one — pre-dated the "merged" comment, dead
   since this later rule always won the cascade at equal specificity; kept
   only for archaeology in git blame, not behavior.) */
#stage-windows-container {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 1000;
}
.stage-window {
    position: absolute;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.3);
    display: flex;
    flex-direction: column;
    pointer-events: auto;
    min-width: 500px;
    min-height: 400px;
    transition: box-shadow 0.15s ease, filter 0.15s ease, opacity 0.15s ease;
    /* Every window gets a programmatic .focus() on open/click-to-front (for
       the Tab focus-trap) — that triggered the browser's default blue focus
       ring on the window body, which the app-shell review flagged as
       "reads like a form-validation ring, not a window-focus cue" (§4.1).
       The deliberate focus signal here is shadow depth + the recede rule
       below; suppress the accidental default so it can't compete with that. */
    outline: none;
}
/* Real keyboard (Tab) navigation still gets a visible ring — :focus-visible
   does not fire for the programmatic .focus() calls above in current
   browsers, so mouse/click users never see this. */
.stage-window:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}
.stage-window.focused {
    /* Focused windows rise via shadow depth only — no colored accent
       border, no glow. Unfocused windows recede (handled by the recede
       rule below). This is the "real focus/blur transition, subtle shadow
       depth" the corrected design brief (2026-07-02) asks for: restrained
       and original, not a copy of any one OS's chrome. */
    box-shadow: 0 12px 48px rgba(0,0,0,0.4);
}
.stage-window-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 16px;
    /* Flat surface — no gradient, no inset highlight. design-system.md
       pillar 4 ("No Chrome... hierarchy through spacing and type weight").
       The gradient + inset highlight here, and the traffic-light dots
       below, were a literal macOS titlebar copy from 07.01.26-app-shell-
       ui-polish; corrected 2026-07-02 (owner: "when I said take
       inspiration in mac os didn't mean to copy colors and buttons") — the
       brief asked for macOS's smoothness, not its exact chrome. See
       "Stage Window Chrome" in docs/design-system.md for the standing
       convention this now follows. */
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border);
    cursor: move;
    /* No user-select:none here (click-trap fix, app-shell review §3.1/§3.8) —
       the title/type-badge/status-pill text stays selectable. _swStartDrag()
       in stage-windows.js defers preventDefault() until a real drag is
       confirmed, so a stationary triple-click still selects text natively. */
    flex-shrink: 0;
    border-radius: 8px 8px 0 0;
    gap: 8px;
}
.stage-window-header .sw-title-area {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    min-width: 0;
    overflow: hidden;
}
.stage-window-header .sw-title {
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Window controls (design correction 2026-07-02, replacing the traffic-
   light cluster + Arrange flyout from 07.01.26-app-shell-ui-polish). One
   right-aligned row, one shared icon-button language (.sw-action-btn — the
   SAME ghost/rectangular control already used elsewhere, e.g. the code-
   editor toolbar's Help/Fullscreen buttons — see stage-detail.css), two
   function groups separated by a plain divider. Tile Left/Right are now
   direct single-click buttons, not a menu (owner, item 2: "this is
   additional click for what??" — Center was dropped as a top-level action,
   it wasn't the complaint and a 6th icon added back the clutter the
   traffic-light redesign was trying to remove; still reachable
   programmatically via tileStageWindow('center', id) if a later pass
   wants it back). */
.stage-window-header .sw-actions {
    display: flex;
    gap: 2px;
    align-items: center;
    flex-shrink: 0;
    padding-left: 8px;
    margin-left: 4px;
    border-left: 1px solid var(--border);
}
.sw-action-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 4px);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition: all 0.15s;
    padding: 0;
    flex-shrink: 0;
}
.sw-action-btn:hover {
    background: var(--bg);
    border-color: var(--border);
    color: var(--text);
}
.sw-action-btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}
/* Finding #1 (08.17.26-notebook-ux-polish): Tile Left/Right + Maximize get a
   persistent text label alongside their icon (not just the native hover
   tooltip every .sw-action-btn already had) -- see the comment above the
   header.innerHTML build in stage-windows.js for which 3 of the 5 titlebar
   controls get this and why Minimize/Close don't. Square icon collapses to
   an auto-width icon+label pill; window min-width (500px, above) still
   leaves the title area (flex:1, min-width:0, ellipsis) room to shrink into
   at the floor. */
.sw-action-btn-labeled {
    width: auto;
    padding: 0 8px 0 6px;
    gap: 5px;
}
.sw-action-label {
    font-size: 11px;
    font-weight: 500;
    white-space: nowrap;
}
/* Close reuses the app's one existing danger-hover convention
   (.btn-icon.btn-delete:hover, this same file) instead of a dedicated red
   dot — one reserved "danger" meaning, not a second, unrelated red. */
.sw-action-btn.sw-close:hover {
    background: rgba(220, 38, 38, 0.06);
    border-color: var(--status-failed);
    color: var(--status-failed);
}
.sw-action-sep {
    width: 1px;
    height: 16px;
    background: var(--border);
    margin: 0 2px;
    flex-shrink: 0;
}
/* Recede non-focused windows: clearer focus without a backdrop/scrim.
   Strengthened (app-shell review §4.1) — the dimming was previously confined
   to the ~40px titlebar strip alone, which both reviewers independently
   reported as "pixel-identical" between focused/unfocused windows, since
   the (undimmed) body is what actually fills most of the screen. The whole
   window now recedes together — opacity only (not filter), so this doesn't
   create a new containing block for any fixed-position popup content inside
   (Monaco autocomplete, the AI side panel, snapshot selector) the way
   `transform`/`filter` on this element would. */
.stage-window:not(.focused) {
    box-shadow: 0 4px 16px rgba(0,0,0,0.22);
    opacity: 0.92;
}
.stage-window:not(.focused) .stage-window-header {
    filter: saturate(0.6);
    opacity: 0.85;
}
.stage-window-body {
    flex: 1;
    overflow-y: auto;
    padding: 16px;
    display: flex;
    flex-direction: column;
}
/* When edit tab (code editor) is active, don't scroll the body —
   let Monaco fill the available space via flex */
.stage-window-body:has(.stage-tab-edit.active) {
    overflow-y: hidden;
}
/* Header and tabs stay at top when scrolling within window body */
.stage-window-body .wf-detail-header,
.stage-window-body .stage-tabs {
    position: sticky;
    top: -16px;
    background: var(--bg);
    z-index: 2;
}
.stage-window-body .stage-tabs {
    top: 20px;
}
/* Ensure no horizontal scroll on stage window content */
.stage-window-body .stage-tabs {
    margin: 0 -16px;
    padding: 8px 16px 0;
}
/* Non-edit tabs get their own scroll */
.stage-window-body .stage-tab-content:not(.stage-tab-edit) {
    overflow-y: auto;
}
/* Config-only edit tabs (no Monaco editor) scroll in stage windows too */
.stage-window-body .stage-tab-edit-config {
    overflow-y: auto;
}
/* Monaco editor sizing within floating window */
.stage-window-body .code-workspace:not(.code-workspace-notebook) {
    flex: 1;
    min-height: 0;
}
.stage-window-body .monaco-editor-container {
    min-height: 200px;
    flex: 1;
}
/* Logs container — fill available height in stage window */
.stage-window-body .logs-container {
    flex: 1;
    max-height: none;
    min-height: 150px;
}
/* Actions bar at bottom of detail */
.wf-actions {
    display: flex;
    gap: 8px;
    padding: 12px 0;
    border-top: 1px solid var(--border);
    margin-top: 16px;
}
.stage-window-resize {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 16px;
    height: 16px;
    cursor: se-resize;
    background: linear-gradient(135deg, transparent 50%, var(--border) 50%);
    border-radius: 0 0 8px 0;
}
.stage-window-resize:hover {
    background: linear-gradient(135deg, transparent 50%, var(--accent) 50%);
}
/* Inner-edge tile-resize handle (item P2.3) — a thin grabbable bar on the edge
   of a side-tiled window that faces the DAG. Dragging it rebalances the split. */
.stage-window-tile-resize {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 8px;
    cursor: ew-resize;
    z-index: 5;
    background: transparent;
}
.stage-window-tile-resize[data-edge="left"]  { left: -4px; }
.stage-window-tile-resize[data-edge="right"] { right: -4px; }
.stage-window-tile-resize::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 3px;
    height: 42px;
    border-radius: 3px;
    background: var(--border);
    transition: background 0.15s;
}
.stage-window-tile-resize:hover::before {
    background: var(--accent);
}
/* Minimized state */
.stage-window.sw-minimized {
    display: none !important;
}

/* Viewer-only: stage-window body text is non-selectable to discourage casual
   scraping of a read-only demo, but real content (code, logs, tables, inputs)
   stays copyable. Scoped to body.sciflow-viewer so owner mode is untouched.
   iframes are separate documents and unaffected. */
body.sciflow-viewer .stage-window-body {
    user-select: none;
    -webkit-user-select: none;
}
body.sciflow-viewer .stage-window-body :is(pre, code, textarea, input, table, .logs-container, .CodeMonaco) {
    user-select: text;
    -webkit-user-select: text;
}

/* ── Viewer read-only integrity (item A) ──
   The windowed DAG view re-injects .stage-detail-content WITHOUT the
   #stage-detail-modal wrapper, so the modal-scoped viewer <style> block in
   stage_detail.html does not reach it. Re-assert the owner-control hides
   globally under body.sciflow-viewer so the Run/Configure tab is inert in the
   public viewer: no Run button, no AI panels, no inline editing. (The
   queue-override dropdown this comment used to also hide here was deleted
   entirely, 07.27.26-tier-fact-single-source — replaced by a read-only
   tier badge with nothing to hide.) Owner mode (no .sciflow-viewer on
   body) is untouched. */
body.sciflow-viewer .stage-window-body .run-btn,
body.sciflow-viewer .stage-window-body .config-run-action,
body.sciflow-viewer .stage-window-body .btn-run,
body.sciflow-viewer .stage-window-body .btn-cancel,
body.sciflow-viewer .stage-window-body .btn-cancel-header,
body.sciflow-viewer .stage-window-body .ai-toggle-btn,
body.sciflow-viewer .stage-window-body .ai-side-panel,
body.sciflow-viewer .stage-window-body .dep-edit-btn,
body.sciflow-viewer .stage-window-body .code-toolbar .toolbar-actions .btn,
body.sciflow-viewer .stage-window-body .code-toolbar .toolbar-actions .toolbar-select,
body.sciflow-viewer .stage-window-body .stage-files-section .btn,
body.sciflow-viewer .stage-window-body .file-list-compact .btn-icon.btn-delete {
    display: none !important;
}
/* Config / edit-tab inputs become inert (read-only params display). */
body.sciflow-viewer .stage-window-body .stage-tab-edit input,
body.sciflow-viewer .stage-window-body .stage-tab-edit select,
body.sciflow-viewer .stage-window-body .stage-tab-edit textarea {
    pointer-events: none !important;
    opacity: 0.7 !important;
    background: var(--bg-secondary) !important;
}
/* Inline-editable title/description become inert text in the viewer. */
body.sciflow-viewer .stage-window-body [contenteditable] {
    -webkit-user-modify: read-only !important;
    user-modify: read-only !important;
    pointer-events: none !important;
}

/* Run-history navigation is owner-only. The public viewer always shows the
   latest (published) run; exposing the < Run #N > nav or the per-node
   snapshot selector lets a visitor page back to older/scaffolding runs whose
   outputs may contradict the published result (e.g. a stale freebayes run
   under a GATK demo). Hide both in the viewer. Caught by the science gate on
   the short-read demo, 2026-06-01. */
body.sciflow-viewer .run-navigation-bar,
body.sciflow-viewer .dag-snapshot-selector,
body.sciflow-viewer .stage-window-body .run-navigation-bar {
    display: none !important;
}

/* Item 2 (3D): suppress Mol* interactive load/download/export controls in the
   viewer so the read-only demo can't trigger uploads or trajectory loads.
   The figure / rendered structure itself stays visible. */
body.sciflow-viewer .stage-window-body .msp-viewport-controls,
body.sciflow-viewer .stage-window-body .msp-layout-controls {
    display: none !important;
}

/* Item D: hide the run-history selector (clock + Execution dropdown) in the
   public viewer — switching executions is an owner affordance. */
body.sciflow-viewer .dag-run-selector { display: none !important; }

/* Item E: breathing room top/bottom for embedded result reports so HTML that
   ends flush on a table or sentence isn't jammed against the iframe edge. */
body.sciflow-viewer .stage-window-body iframe { padding: 5px 0; }

/* Minimized-window dock (design correction 2026-07-02, second pass on
   app-shell review §4.2). The 07.01.26 tinted-strip treatment used
   --bg-secondary against the toolbar's own --bg — a ~2% lightness
   difference that reads as near-identical to the plain Run All/Pause
   buttons next to it at this size (confirmed live: after minimizing 3
   stages the "WINDOWS" strip still blended into the surrounding toolbar
   chrome). This pass reuses the accent-tinted "distinct, live control
   region" language already established one row over in this same toolbar
   (.dag-layout-btn.active below) instead of inventing a new treatment —
   restrained, not a new color, and gives the strip real contrast.
   #sw-taskbar-group is the single show/hide unit (_swRebuildTaskbar). */
.sw-taskbar-group {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px 10px 3px 6px;
    margin: 0 2px;
    border-radius: var(--radius, 6px);
    background: var(--accent-soft);
    border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
}
.sw-taskbar-sep {
    width: 1px;
    height: 20px;
    background: var(--border-subtle);
}
.sw-taskbar-label {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--accent);
    flex-shrink: 0;
    white-space: nowrap;
}
.sw-taskbar {
    display: flex;
    gap: 4px;
    align-items: center;
}
.sw-taskbar-tile {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    height: 26px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 4px);
    background: var(--bg);
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 11px;
    font-weight: 500;
    max-width: 140px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    transition: all 0.15s;
}
.sw-taskbar-tile .sw-tile-icon {
    flex-shrink: 0;
    opacity: 0.7;
}
.sw-taskbar-tile:hover {
    border-color: var(--accent);
    color: var(--text);
}
/* Focused tile stays on the neutral --bg (not accent-soft) so it still
   pops against the now-accent-tinted group background instead of
   disappearing into it. */
.sw-taskbar-tile.sw-tile-focused {
    border-color: var(--accent);
    color: var(--accent);
    font-weight: 600;
}
.sw-taskbar-tile.sw-tile-focused .sw-tile-icon {
    opacity: 1;
}
.sw-taskbar-tile.sw-tile-minimized {
    opacity: 0.65;
    border-style: dashed;
}
.sw-taskbar-tile .sw-tile-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border: none;
    background: transparent;
    color: var(--text-tertiary);
    cursor: pointer;
    padding: 0;
    border-radius: 2px;
    flex-shrink: 0;
}
.sw-taskbar-tile .sw-tile-close:hover {
    background: var(--danger, #ef4444);
    color: white;
}

/* Workflow styles */
.workflow-tabs {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--border);
}
.workflow-tab {
    padding: 10px 20px;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    font-size: 14px;
    color: var(--text-secondary);
    transition: all 0.2s;
}
.workflow-tab:hover {
    color: var(--text);
}
.workflow-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
.saved-workflow-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    margin-bottom: 8px;
    transition: all 0.2s;
}
.saved-workflow-item:hover {
    border-color: var(--accent);
    background: var(--bg-secondary);
}
.saved-workflow-info h4 {
    margin: 0 0 4px 0;
    font-size: 14px;
}
.saved-workflow-info p {
    margin: 0;
    font-size: 12px;
    color: var(--text-secondary);
}
.saved-workflow-meta {
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 4px;
}
.empty-saved-workflows {
    text-align: center;
    padding: 32px;
    color: var(--text-secondary);
}

/* Code tab Monaco editor */
.code-file-btn.active { background: var(--primary); color: white; }


/* ===== Mobile Responsiveness (≤640px) ===== */

@media (max-width: 640px) {
    /* Stage windows: fullscreen on mobile */
    .stage-window {
        position: fixed !important;
        inset: 0 !important;
        width: 100% !important;
        height: 100% !important;
        min-width: 0;
        min-height: 0;
        border-radius: 0;
        z-index: 1001 !important;
    }

    .stage-window-header {
        border-radius: 0;
    }

    /* Hide tile/minimize/maximize controls — windows are fullscreen on
       mobile, so there's nothing to tile/minimize/maximize into. Close
       stays (still the only way off a fullscreen window). Class names
       updated for the 2026-07-02 design-correction chrome (was the
       traffic-light + arrange-flyout classes from 07.01.26-app-shell-ui-
       polish); also had a live duplicate of this whole mobile block in
       stages_list.html, an inline <style> HTMX loads and caches
       separately — the exact "two stylesheets silently drift apart"
       failure the 2026-05-31 review fixed once for this same component.
       Removed the duplicate there; this file is the single home, as the
       comment above the window-chrome block states. */
    .sw-tile-left,
    .sw-tile-right,
    .sw-minimize,
    .sw-maximize,
    .sw-action-sep {
        display: none;
    }

    /* Hide the minimized-window dock — one window at a time, fullscreen */
    .sw-taskbar-group {
        display: none !important;
    }

    /* Stage window resize handle — not needed fullscreen */
    .stage-window-resize {
        display: none;
    }

    /* Tighter header padding */
    header .container,
    footer .container {
        padding: 0 10px;
    }

    main > .container {
        padding: 0 8px;
    }
}

/* ── DAG legend overlay ──────────────────────────────────────────────
   Positioned relative to the DAG panel. The panel rule in
   partials/stages_list.html sets no `position`, so we establish a
   positioning context here without touching that file. */
#wf-dag-panel {
    position: relative;
    transition: flex-basis .2s ease, max-width .2s ease, margin-left .2s ease;
}
/* Tile-aware DAG reflow: a tiled stage window floats in the fixed
   #stage-windows-container OVER the panel; these classes shrink the DAG into
   the half the window does NOT cover so graph + window sit side-by-side. */
#wf-dag-panel.dag-shift-left {   /* window tiled RIGHT → DAG occupies left half */
    flex: 0 0 50%;
    max-width: 50%;
}
#wf-dag-panel.dag-shift-right {  /* window tiled LEFT  → DAG occupies right half */
    flex: 0 0 50%;
    max-width: 50%;
    margin-left: 50%;
}
/* When tiled, the canvas's "infinite-canvas" pad is 60vw (viewport-relative).
   In a half-width panel that pad (120vw total) far exceeds the panel, forcing
   .stages-dag to overflow its 50% parent — the centering math then places the
   graph in the clipped-off region and it lands off-screen. Re-anchor the
   horizontal pad to the PANEL width (50% each side, % padding resolves against
   the flex item's own used width) so the scroll viewport matches the panel and
   the fit/center math lands the graph inside the visible half. Vertical pad
   (full-width-safe) is untouched; un-tiled behavior is unchanged. */
#wf-dag-panel.dag-shift-left .stages-dag,
#wf-dag-panel.dag-shift-right .stages-dag {
    padding-left: 50%;
    padding-right: 50%;
}

.dag-legend {
    position: absolute;
    left: 8px;
    bottom: 8px;
    z-index: 20;
    pointer-events: none;
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 6px 8px;
    font-size: 11px;
    line-height: 1.2;
    color: var(--text-secondary);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 1px 4px rgba(0,0,0,0.15);
    opacity: 0.45;
    transition: opacity 0.15s ease;
}

.dag-legend:hover {
    opacity: 1;
    pointer-events: auto;
}

.dag-legend-row {
    display: flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

.dag-legend-swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 2px;
    flex-shrink: 0;
}

.dag-legend-edge {
    margin-top: 2px;
    padding-top: 4px;
    border-top: 1px solid var(--border);
}

.dag-legend-arrow {
    display: inline-block;
    width: 10px;
    text-align: center;
    color: var(--text-secondary);
    font-weight: 600;
    flex-shrink: 0;
}

/* ── Public read-only viewer UI ── */

/* Quiet header links shown to anonymous viewers (Sign In / What is SciFlow?). */
.nav-quiet-link {
    color: var(--text-secondary);
    font-size: 0.85rem;
    text-decoration: none;
    padding: 4px 8px;
    border-radius: var(--radius-sm);
    transition: color 0.15s, background 0.15s;
}
.nav-quiet-link:hover {
    color: var(--text);
    background: var(--bg-secondary);
}

/* Persistent provenance banner. Lives in the shell (above .project-tabs), so it
   survives the overflow:hidden layout and HTMX tab swaps. */
.view-readonly-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
    width: 100%;
    box-sizing: border-box;
    padding: 9px 16px;
    margin-bottom: 10px;
    background: var(--accent-soft);
    border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
    border-radius: var(--radius);
    color: var(--text);
    font-size: 12.5px;
    line-height: 1.4;
}
.view-readonly-banner .vrb-icon {
    flex-shrink: 0;
    color: var(--accent);
    display: flex;
    align-items: center;
}
.view-readonly-banner .vrb-text {
    flex: 1;
    min-width: 0;
}
.view-readonly-banner .vrb-text strong {
    font-weight: 600;
}
.view-readonly-banner .vrb-name {
    font-weight: 600;
    color: var(--accent);
}
.view-readonly-banner .vrb-wayfinding {
    color: var(--text-secondary);
}
.view-readonly-banner .vrb-help {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
    color: var(--accent);
    font-size: 12px;
    padding: 3px 9px;
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.view-readonly-banner .vrb-help:hover {
    background: var(--accent);
    color: #fff;
}

/* First-visit welcome overlay. Light non-blocking scrim + centered card. */
.view-welcome-scrim {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(15, 23, 42, 0.45);
    padding: 24px;
    animation: vw-fade-in 0.18s ease;
}
.view-welcome-scrim[hidden] { display: none; }
@keyframes vw-fade-in { from { opacity: 0; } to { opacity: 1; } }
.view-welcome-card {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: 0 24px 64px rgba(0,0,0,0.35);
    max-width: 460px;
    width: 100%;
    padding: 26px 28px 22px;
    color: var(--text);
}
.view-welcome-card h2 {
    margin: 0 0 10px;
    font-size: 18px;
    line-height: 1.3;
}
.view-welcome-card .vw-body {
    margin: 0 0 16px;
    font-size: 13.5px;
    line-height: 1.5;
    color: var(--text-secondary);
}
.view-welcome-card .vw-pointers {
    list-style: none;
    margin: 0 0 16px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.view-welcome-card .vw-pointers li {
    font-size: 13px;
    line-height: 1.45;
}
.view-welcome-card .vw-pointers strong {
    color: var(--text);
    font-weight: 600;
}
.view-welcome-card .vw-pointers span {
    color: var(--text-secondary);
}
.view-welcome-card .vw-closer {
    margin: 0 0 18px;
    font-size: 13px;
    color: var(--text);
}
.view-welcome-card .vw-dismiss {
    width: 100%;
    background: var(--accent);
    color: #fff;
    border: none;
    border-radius: var(--radius);
    padding: 10px 16px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s;
}
.view-welcome-card .vw-dismiss:hover {
    background: color-mix(in srgb, var(--accent) 88%, #000);
}
.view-welcome-card .vw-footer {
    margin: 14px 0 0;
    text-align: center;
    font-size: 11px;
    color: var(--text-tertiary);
}
/* Two-button row (item E): primary "Take a quick tour" + secondary "Explore on my own". */
.view-welcome-card .vw-actions {
    display: flex;
    gap: 10px;
}
.view-welcome-card .vw-dismiss-secondary {
    background: var(--bg-secondary);
    color: var(--text);
    border: 1px solid var(--border);
}
.view-welcome-card .vw-dismiss-secondary:hover {
    background: color-mix(in srgb, var(--bg-secondary) 85%, var(--text) 4%);
}

/* ── Guided tour (item E) ──
   Custom lightweight tour: a dim backdrop with a transparent highlight cut-out
   over the target element, plus a positioned popover. No new JS dependency. */
.view-tour-overlay {
    position: fixed;
    inset: 0;
    z-index: 2100;
    pointer-events: none;   /* clicks pass through except on the popover */
}
.view-tour-overlay[hidden] { display: none; }
/* The cut-out: a transparent box with a giant box-shadow that dims everything
   around it. Positioned absolutely by JS over the target's bounding rect. */
.view-tour-hole {
    position: absolute;
    border-radius: 8px;
    box-shadow: 0 0 0 9999px rgba(15, 23, 42, 0.55);
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    transition: top 0.2s ease, left 0.2s ease, width 0.2s ease, height 0.2s ease;
    pointer-events: none;
}
.view-tour-popover {
    position: absolute;
    pointer-events: auto;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg, 12px);
    box-shadow: 0 20px 56px rgba(0,0,0,0.35);
    width: 320px;
    max-width: calc(100vw - 32px);
    padding: 16px 18px 14px;
    color: var(--text);
    transition: top 0.2s ease, left 0.2s ease;
}
.view-tour-popover .vt-step-count {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-tertiary);
    margin-bottom: 4px;
}
.view-tour-popover h3 {
    margin: 0 0 6px;
    font-size: 15px;
    line-height: 1.3;
}
.view-tour-popover p {
    margin: 0 0 14px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-secondary);
}
.view-tour-popover .vt-controls {
    display: flex;
    align-items: center;
    gap: 8px;
}
.view-tour-popover .vt-spacer { flex: 1; }
.view-tour-popover .vt-btn {
    border: 1px solid var(--border);
    background: var(--bg-secondary);
    color: var(--text);
    border-radius: var(--radius, 8px);
    padding: 6px 14px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s, opacity 0.15s;
}
.view-tour-popover .vt-skip {
    border: none;
    background: none;
    color: var(--text-tertiary);
    padding: 6px 4px;
}
.view-tour-popover .vt-skip:hover { color: var(--text-secondary); }
.view-tour-popover .vt-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}
.view-tour-popover .vt-primary:hover {
    background: color-mix(in srgb, var(--accent) 88%, #000);
}
.view-tour-popover .vt-btn[disabled] {
    opacity: 0.4;
    cursor: default;
    pointer-events: none;
}

/* ── Read-only run provenance panel (viewer Run/Configure tab, item P2.2) ── */
.view-provenance {
    margin: 10px 0 4px;
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    background: var(--bg-secondary);
    padding: 12px 14px;
}
.view-provenance-title-row {
    display: flex;
    align-items: center;
    gap: 2px;
    cursor: pointer;
}
.view-provenance-title {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--text-tertiary);
}
.view-provenance-body {
    margin-top: 8px;
}
.view-provenance-section + .view-provenance-section {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--border-subtle);
}
.view-provenance .vp-section-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    margin-bottom: 6px;
}
.view-provenance .vp-kv {
    margin: 0;
}
.view-provenance .vp-kv-row {
    display: flex;
    gap: 10px;
    padding: 3px 0;
    font-size: 12.5px;
    align-items: baseline;
}
.view-provenance .vp-kv-row dt {
    flex: 0 0 38%;
    max-width: 38%;
    color: var(--text-secondary);
    margin: 0;
    word-break: break-word;
}
.view-provenance .vp-kv-row dd {
    flex: 1 1 auto;
    margin: 0;
    color: var(--text-primary);
    word-break: break-word;
}
.view-provenance code {
    font-size: 11.5px;
}
.view-provenance .vp-command {
    margin: 0;
    padding: 8px 10px;
    background: var(--bg);
    border: 1px solid var(--border-subtle);
    border-radius: 6px;
    font-size: 11.5px;
    white-space: pre-wrap;
    word-break: break-word;
    color: var(--text-primary);
}
