{# Implements: REQ-p00006-A, REQ-d00010-A, REQ-d00010-G #}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Trace Edit - Requirements Editor</title>
    <style>
/* =====================================================================
   CSS STYLES - Trace Edit
   ===================================================================== */

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

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    font-size: 14px;
    line-height: 1.5;
    color: #333;
    background: #f8f9fa;
    overflow: hidden;
    height: 100vh;
    display: flex;
    flex-direction: column;
}

/* ---------------------------------------------------------------------
   Header
   --------------------------------------------------------------------- */

.header {
    background: white;
    border-bottom: 1px solid #e9ecef;
    padding: 10px 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    flex-shrink: 0;
    z-index: 100;
}

.header-left {
    display: flex;
    align-items: center;
    gap: 16px;
}

.header-title {
    font-size: 1.25rem;
    font-weight: 600;
    color: #212529;
}

.header-stats {
    display: flex;
    gap: 6px;
    align-items: center;
    flex-wrap: wrap;
}

.stat-badge {
    padding: 3px 10px;
    border-radius: 4px;
    font-size: 0.8rem;
    font-weight: 600;
    user-select: none;
}

.stat-badge.prd { background: #212529; color: white; }
.stat-badge.ops { background: #fd7e14; color: white; }
.stat-badge.dev { background: #20c997; color: white; }

.header-center {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 12px;
    min-width: 300px;
}

.search-box {
    position: relative;
    width: 100%;
    max-width: 400px;
}

.search-box input {
    width: 100%;
    padding: 7px 12px 7px 32px;
    border: 1px solid #dee2e6;
    border-radius: 6px;
    font-size: 0.875rem;
    background: #f8f9fa;
    transition: border-color 0.15s, background 0.15s;
}

.search-box input:focus {
    outline: none;
    border-color: #0d6efd;
    background: white;
    box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.1);
}

.search-box::before {
    content: "\1F50D";
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.8rem;
    opacity: 0.5;
}

.search-results {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: white;
    border: 1px solid #dee2e6;
    border-radius: 0 0 6px 6px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
    max-height: 320px;
    overflow-y: auto;
    z-index: 200;
    display: none;
}

.search-results.visible {
    display: block;
}

.search-result-item {
    padding: 8px 12px;
    cursor: pointer;
    border-bottom: 1px solid #f1f3f4;
    display: flex;
    align-items: center;
    gap: 8px;
}

.search-result-item:hover {
    background: #f0f4ff;
}

.search-result-id {
    font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
    font-size: 0.8rem;
    color: #0d6efd;
    flex-shrink: 0;
}

.search-result-title {
    font-size: 0.8rem;
    color: #495057;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.search-result-level {
    font-size: 0.7rem;
    font-weight: 600;
    padding: 1px 6px;
    border-radius: 3px;
    flex-shrink: 0;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Edit Mode Toggle */
.edit-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 2px solid #dee2e6;
    border-radius: 6px;
    background: white;
    cursor: pointer;
    font-size: 0.85rem;
    font-weight: 500;
    color: #495057;
    transition: all 0.2s;
    user-select: none;
}

.edit-toggle:hover {
    border-color: #adb5bd;
}

.edit-toggle.active {
    border-color: #0d6efd;
    background: #e7f1ff;
    color: #0d6efd;
}

.edit-toggle-indicator {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #adb5bd;
    transition: background 0.2s;
}

.edit-toggle.active .edit-toggle-indicator {
    background: #0d6efd;
}

/* Save/Revert/Undo Buttons */
.btn {
    padding: 6px 14px;
    border: 1px solid #dee2e6;
    background: white;
    border-radius: 5px;
    cursor: pointer;
    font-size: 0.8rem;
    color: #495057;
    transition: background 0.15s, border-color 0.15s;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.btn:hover {
    background: #f8f9fa;
}

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

.btn-primary {
    background: #0d6efd;
    color: white;
    border-color: #0d6efd;
}

.btn-primary:hover {
    background: #0b5ed7;
}

.btn-warning {
    background: #ffc107;
    color: #212529;
    border-color: #ffc107;
}

.btn-warning:hover {
    background: #e0a800;
}

.btn-danger {
    color: #dc3545;
    border-color: #dc3545;
}

.btn-danger:hover {
    background: #dc3545;
    color: white;
}

.unsaved-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    background: #dc3545;
    color: white;
    border-radius: 10px;
    font-size: 0.7rem;
    font-weight: 700;
}

.unsaved-badge.hidden {
    display: none;
}

/* Toast Notifications */
.toast-container {
    position: fixed;
    top: 60px;
    right: 20px;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.toast {
    padding: 10px 16px;
    border-radius: 6px;
    font-size: 0.85rem;
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    animation: toast-in 0.3s ease;
    max-width: 400px;
}

.toast.success {
    background: #d1e7dd;
    color: #0f5132;
    border: 1px solid #badbcc;
}

.toast.error {
    background: #f8d7da;
    color: #842029;
    border: 1px solid #f5c2c7;
}

.toast.info {
    background: #cff4fc;
    color: #055160;
    border: 1px solid #b6effb;
}

@keyframes toast-in {
    from { opacity: 0; transform: translateX(20px); }
    to   { opacity: 1; transform: translateX(0); }
}

/* ---------------------------------------------------------------------
   3-Panel Layout
   --------------------------------------------------------------------- */

.layout {
    display: flex;
    flex: 1;
    overflow: hidden;
    min-height: 0;
}

/* --- Nav Panel (Left) --- */

.nav-panel {
    width: 280px;
    min-width: 200px;
    max-width: 400px;
    background: white;
    border-right: 1px solid #e9ecef;
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    overflow: hidden;
}

.nav-tabs {
    display: flex;
    border-bottom: 1px solid #e9ecef;
    flex-shrink: 0;
}

.nav-tab {
    flex: 1;
    padding: 10px 4px;
    border: none;
    background: none;
    cursor: pointer;
    font-size: 0.75rem;
    font-weight: 600;
    color: #6c757d;
    border-bottom: 2px solid transparent;
    transition: all 0.15s;
    text-align: center;
    white-space: nowrap;
}

.nav-tab:hover {
    color: #495057;
    background: #f8f9fa;
}

.nav-tab.active {
    color: #0d6efd;
    border-bottom-color: #0d6efd;
}

.nav-tree-container {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 4px 0;
}

.nav-tree-row {
    display: flex;
    align-items: center;
    padding: 4px 8px;
    cursor: pointer;
    font-size: 0.8rem;
    color: #495057;
    border-left: 3px solid transparent;
    transition: background 0.1s, border-color 0.1s;
    user-select: none;
    gap: 4px;
}

.nav-tree-row:hover {
    background: #f0f4ff;
}

.nav-tree-row.selected {
    background: #e7f1ff;
    border-left-color: #0d6efd;
}

.nav-tree-row.hidden {
    display: none;
}

.nav-tree-indent {
    display: inline-block;
    width: 16px;
    flex-shrink: 0;
}

.nav-tree-toggle {
    width: 16px;
    height: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 8px;
    color: #adb5bd;
    cursor: pointer;
    border: none;
    background: none;
}

.nav-tree-toggle:hover {
    color: #495057;
}

.nav-tree-toggle.leaf {
    visibility: hidden;
}

.nav-tree-id {
    font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
    font-size: 0.75rem;
    color: #0d6efd;
    flex-shrink: 0;
}

.nav-tree-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: #6c757d;
    font-size: 0.75rem;
}

.nav-tree-level {
    font-size: 0.6rem;
    font-weight: 700;
    padding: 1px 4px;
    border-radius: 2px;
    flex-shrink: 0;
}

.nav-tree-level.prd { background: #212529; color: white; }
.nav-tree-level.ops { background: #fd7e14; color: white; }
.nav-tree-level.dev { background: #20c997; color: white; }

/* --- Vertical Dividers --- */

.divider {
    width: 4px;
    background: #e9ecef;
    cursor: col-resize;
    flex-shrink: 0;
    transition: background 0.15s;
    position: relative;
}

.divider:hover,
.divider.dragging {
    background: #0d6efd;
}

.divider::after {
    content: '\00B7\00B7\00B7';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) rotate(90deg);
    color: #adb5bd;
    font-size: 8px;
    letter-spacing: 2px;
    pointer-events: none;
}

/* --- Card Stack (Center) --- */

.card-stack-panel {
    flex: 1;
    min-width: 350px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: #f8f9fa;
}

.card-stack-header {
    padding: 8px 16px;
    background: white;
    border-bottom: 1px solid #e9ecef;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-shrink: 0;
    font-size: 0.85rem;
    color: #6c757d;
}

.card-stack-body {
    flex: 1;
    overflow-y: auto;
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.card-stack-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
    color: #adb5bd;
    gap: 8px;
    padding: 40px;
    text-align: center;
}

.card-stack-empty-icon {
    font-size: 2.5rem;
    opacity: 0.5;
}

/* --- Requirement Card --- */

.req-card {
    background: white;
    border: 1px solid #e9ecef;
    border-radius: 8px;
    transition: box-shadow 0.2s, border-color 0.2s;
}

.req-card:hover {
    box-shadow: 0 2px 8px rgba(0,0,0,0.06);
}

.req-card.focused {
    border-color: #0d6efd;
    box-shadow: 0 0 0 2px rgba(13,110,253,0.15);
}

.req-card-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    background: #f8f9fa;
    border-bottom: 1px solid #e9ecef;
    cursor: pointer;
    user-select: none;
}

.req-card-header:hover {
    background: #e9ecef;
}

.req-card-expand {
    font-size: 8px;
    color: #adb5bd;
    transition: transform 0.15s;
    flex-shrink: 0;
}

.req-card.collapsed .req-card-expand {
    transform: rotate(-90deg);
}

.req-card-id {
    font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
    font-size: 0.85rem;
    font-weight: 600;
    color: #0d6efd;
    flex-shrink: 0;
}

.req-card-title-display {
    flex: 1;
    font-size: 0.9rem;
    font-weight: 500;
    color: #212529;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.req-card-close {
    border: none;
    background: none;
    cursor: pointer;
    font-size: 1.1rem;
    color: #adb5bd;
    padding: 0 4px;
    line-height: 1;
    transition: color 0.15s;
    flex-shrink: 0;
}

.req-card-close:hover {
    color: #dc3545;
}

.req-card-body {
    padding: 14px;
}

.req-card.collapsed .req-card-body {
    display: none;
}

/* Card Sections */
.card-section {
    margin-bottom: 12px;
}

.card-section:last-child {
    margin-bottom: 0;
}

.card-section-label {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: #6c757d;
    margin-bottom: 4px;
}

.card-meta {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    align-items: center;
}

.card-meta-item {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 0.8rem;
}

.card-meta-key {
    color: #6c757d;
    font-weight: 500;
}

.card-meta-value {
    color: #212529;
}

/* Status Badge (in cards) */
.status-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
}

.status-badge.draft { background: #cfe2ff; color: #084298; }
.status-badge.active { background: #d1e7dd; color: #0f5132; }
.status-badge.deprecated { background: #f8d7da; color: #842029; }
.status-badge.proposed { background: #fff3cd; color: #664d03; }

/* Parent Links */
.card-parents {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.card-parent-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    background: #f0f4ff;
    border: 1px solid #b6d4fe;
    border-radius: 12px;
    font-size: 0.75rem;
    color: #0d6efd;
    cursor: pointer;
    transition: background 0.15s;
    text-decoration: none;
}

.card-parent-link:hover {
    background: #d0e2ff;
}

.card-parent-kind {
    font-size: 0.65rem;
    color: #6c757d;
    font-weight: 600;
    text-transform: uppercase;
}

/* Assertion List */
.card-assertions {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.card-assertion {
    display: flex;
    gap: 8px;
    padding: 6px 8px;
    border-radius: 4px;
    background: #f8f9fa;
    border: 1px solid transparent;
    transition: background 0.15s, border-color 0.15s;
}

.card-assertion-label {
    font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
    font-size: 0.75rem;
    font-weight: 700;
    color: #0d6efd;
    background: #e7f1ff;
    padding: 2px 6px;
    border-radius: 3px;
    flex-shrink: 0;
    height: fit-content;
}

.card-assertion-text {
    font-size: 0.8rem;
    color: #495057;
    line-height: 1.5;
}

/* Children List */
.card-children {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.card-child-link {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 8px;
    background: #f8f9fa;
    border: 1px solid #e9ecef;
    border-radius: 12px;
    font-size: 0.7rem;
    color: #495057;
    cursor: pointer;
    transition: background 0.15s;
    text-decoration: none;
}

.card-child-link:hover {
    background: #e9ecef;
    color: #0d6efd;
}

.card-child-edge-kind {
    font-size: 0.6rem;
    color: #adb5bd;
    font-weight: 600;
}

/* Add Assertion Button */
.card-add-assertion-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    background: transparent;
    border: 1px dashed #dee2e6;
    border-radius: 4px;
    cursor: pointer;
    font-size: 0.75rem;
    color: #6c757d;
    transition: all 0.15s;
    margin-top: 4px;
}

.card-add-assertion-btn:hover {
    border-color: #0d6efd;
    color: #0d6efd;
    background: #f0f4ff;
}

/* Edit Mode: hidden by default, shown when body.edit-mode */
.edit-only {
    display: none;
}

body.edit-mode .edit-only {
    display: inline-flex;
}

body.edit-mode .edit-only-block {
    display: block;
}

/* --- Edit Mode Visual Indicators --- */

/* Editable fields at rest in edit mode */
body.edit-mode .editable-field {
    background: rgba(59, 130, 246, 0.06);
    border-radius: 3px;
    padding: 1px 4px;
    transition: background 0.15s, box-shadow 0.15s;
    cursor: text;
}

body.edit-mode .editable-field:hover {
    background: rgba(59, 130, 246, 0.12);
}

body.edit-mode .editable-field:focus {
    background: white;
    box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.3);
    outline: none;
}

/* Changed/unsaved field */
body.edit-mode .editable-field.dirty {
    background: rgba(245, 158, 11, 0.12);
    position: relative;
}

body.edit-mode .editable-field.dirty::after {
    content: '';
    position: absolute;
    top: 2px;
    right: 2px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #f59e0b;
}

/* Status select in edit mode */
body.edit-mode .status-select {
    padding: 2px 6px;
    border: 1px solid rgba(59, 130, 246, 0.3);
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 600;
    background: rgba(59, 130, 246, 0.06);
    cursor: pointer;
    transition: border-color 0.15s;
}

body.edit-mode .status-select option {
    background: white;
    color: #212529;
    padding: 4px 8px;
}

body.edit-mode .status-select:focus {
    border-color: #0d6efd;
    outline: none;
    box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.15);
}

body.edit-mode .status-select.dirty {
    background: rgba(245, 158, 11, 0.12);
    border-color: #f59e0b;
}

/* Status select hidden by default, shown in edit mode */
.status-select-wrapper {
    display: none;
}

body.edit-mode .status-select-wrapper {
    display: inline-flex;
}

body.edit-mode .status-badge-wrapper {
    display: none;
}

/* --- File Viewer Panel (Right) --- */

.file-viewer-panel {
    width: 0;
    min-width: 0;
    display: none;
    flex-direction: column;
    background: white;
    border-left: 1px solid #e9ecef;
    overflow: hidden;
}

.file-viewer-panel.open {
    display: flex;
    width: 40%;
    min-width: 300px;
    max-width: 60%;
}

.file-viewer-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: #f8f9fa;
    border-bottom: 1px solid #e9ecef;
    flex-shrink: 0;
}

.file-viewer-path {
    flex: 1;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.8rem;
    color: #495057;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.file-viewer-close-btn {
    border: none;
    background: none;
    cursor: pointer;
    font-size: 1.2rem;
    color: #6c757d;
    line-height: 1;
    padding: 2px 6px;
    border-radius: 3px;
    transition: color 0.15s, background 0.15s;
}

.file-viewer-close-btn:hover {
    color: #dc3545;
    background: #f8d7da;
}

.fv-status {
    font-size: 0.7rem;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 10px;
    white-space: nowrap;
    flex-shrink: 0;
}

.fv-status.on-disk {
    background: #d1fae5;
    color: #065f46;
}

.fv-status.has-mutations {
    background: #fef3c7;
    color: #92400e;
}

.file-viewer-body {
    flex: 1;
    overflow-y: auto;
    overflow-x: auto;
    padding: 0;
}

.file-viewer-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: #adb5bd;
    font-size: 0.85rem;
}

/* Source line display (matches trace_view pattern) */
.source-lines {
    display: table;
    width: 100%;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 13px;
    line-height: 1.5;
}

.source-line {
    display: table-row;
}

.source-line:hover {
    background: #f0f4ff;
}

.source-line.highlighted {
    background: #fff3cd;
}

.line-num {
    display: table-cell;
    width: 1px;
    min-width: 40px;
    padding: 0 12px 0 8px;
    text-align: right;
    color: #adb5bd;
    user-select: none;
    white-space: nowrap;
    vertical-align: top;
    border-right: 1px solid #e9ecef;
    background: #f8f9fa;
}

.line-content {
    display: table-cell;
    padding: 0 12px;
    white-space: pre-wrap;
    word-wrap: break-word;
    tab-size: 4;
}

/* ---------------------------------------------------------------------
   Dark Theme
   --------------------------------------------------------------------- */

@media (prefers-color-scheme: dark) {
    body {
        color: #e9ecef;
        background: #1a1d21;
    }

    .header {
        background: #212529;
        border-bottom-color: #343a40;
    }

    .header-title { color: #f8f9fa; }

    .search-box input {
        background: #2b3035;
        border-color: #495057;
        color: #e9ecef;
    }

    .search-box input:focus {
        background: #343a40;
        border-color: #0d6efd;
    }

    .search-results {
        background: #2b3035;
        border-color: #495057;
    }

    .search-result-item {
        border-bottom-color: #343a40;
    }

    .search-result-item:hover {
        background: #343a40;
    }

    .search-result-title { color: #adb5bd; }

    .nav-panel {
        background: #212529;
        border-right-color: #343a40;
    }

    .nav-tabs {
        border-bottom-color: #343a40;
    }

    .nav-tab { color: #adb5bd; }
    .nav-tab:hover { color: #e9ecef; background: #2b3035; }
    .nav-tab.active { color: #6ea8fe; border-bottom-color: #6ea8fe; }

    .nav-tree-row { color: #adb5bd; }
    .nav-tree-row:hover { background: #2b3035; }
    .nav-tree-row.selected { background: #1a2d42; border-left-color: #6ea8fe; }
    .nav-tree-id { color: #6ea8fe; }
    .nav-tree-title { color: #868e96; }

    .divider { background: #343a40; }
    .divider:hover, .divider.dragging { background: #6ea8fe; }

    .card-stack-panel { background: #1a1d21; }
    .card-stack-header {
        background: #212529;
        border-bottom-color: #343a40;
        color: #adb5bd;
    }

    .req-card {
        background: #212529;
        border-color: #343a40;
    }

    .req-card.focused {
        border-color: #6ea8fe;
        box-shadow: 0 0 0 2px rgba(110,168,254,0.15);
    }

    .req-card-header {
        background: #2b3035;
        border-bottom-color: #343a40;
    }

    .req-card-header:hover { background: #343a40; }
    .req-card-id { color: #6ea8fe; }
    .req-card-title-display { color: #e9ecef; }

    .card-meta-key { color: #adb5bd; }
    .card-meta-value { color: #e9ecef; }

    .card-assertion {
        background: #2b3035;
    }

    .card-assertion-label {
        background: #1a2d42;
        color: #6ea8fe;
    }

    .card-assertion-text { color: #adb5bd; }

    .card-parent-link {
        background: #1a2d42;
        border-color: #2b5f96;
        color: #6ea8fe;
    }

    .card-parent-link:hover { background: #254a73; }

    .card-child-link {
        background: #2b3035;
        border-color: #495057;
        color: #adb5bd;
    }

    .card-child-link:hover {
        background: #343a40;
        color: #6ea8fe;
    }

    .card-add-assertion-btn {
        border-color: #495057;
        color: #adb5bd;
    }

    .card-add-assertion-btn:hover {
        border-color: #6ea8fe;
        color: #6ea8fe;
        background: #1a2d42;
    }

    .status-badge.draft { background: #1a2d42; color: #6ea8fe; }
    .status-badge.active { background: #1a3328; color: #5cb85c; }
    .status-badge.deprecated { background: #3d1f24; color: #e77681; }
    .status-badge.proposed { background: #3d3019; color: #f0c75e; }

    .btn {
        background: #2b3035;
        border-color: #495057;
        color: #adb5bd;
    }

    .btn:hover { background: #343a40; }

    .btn-primary { background: #0d6efd; color: white; border-color: #0d6efd; }
    .btn-primary:hover { background: #0b5ed7; }

    .edit-toggle {
        border-color: #495057;
        background: #2b3035;
        color: #adb5bd;
    }

    .edit-toggle.active {
        border-color: #6ea8fe;
        background: #1a2d42;
        color: #6ea8fe;
    }

    body.edit-mode .editable-field {
        background: rgba(110, 168, 254, 0.08);
    }

    body.edit-mode .editable-field:hover {
        background: rgba(110, 168, 254, 0.15);
    }

    body.edit-mode .editable-field:focus {
        background: #2b3035;
        box-shadow: 0 0 0 2px rgba(110, 168, 254, 0.3);
    }

    body.edit-mode .editable-field.dirty {
        background: rgba(240, 199, 94, 0.12);
    }

    body.edit-mode .status-select {
        background: rgba(110, 168, 254, 0.08);
        border-color: rgba(110, 168, 254, 0.3);
        color: #e9ecef;
    }

    body.edit-mode .status-select option {
        background: #2b3035;
        color: #e9ecef;
    }

    .file-viewer-panel {
        background: #212529;
        border-left-color: #343a40;
    }

    .file-viewer-header {
        background: #2b3035;
        border-bottom-color: #343a40;
    }

    .file-viewer-path { color: #adb5bd; }
    .fv-status.on-disk { background: #064e3b; color: #a7f3d0; }
    .fv-status.has-mutations { background: #78350f; color: #fde68a; }

    .line-num {
        color: #6c757d;
        border-right-color: #343a40;
        background: #2b3035;
    }

    .line-content { color: #e9ecef; }

    .source-line:hover { background: #2b3035; }
    .source-line.highlighted { background: #3d3019; }

    .toast.success { background: #1a3328; color: #5cb85c; border-color: #2d5a3e; }
    .toast.error { background: #3d1f24; color: #e77681; border-color: #5a2d33; }
    .toast.info { background: #1a3040; color: #6ea8fe; border-color: #2d4a6e; }

    .card-stack-empty { color: #6c757d; }

    .card-section-label { color: #868e96; }
}

/* ---------------------------------------------------------------------
   Responsive
   --------------------------------------------------------------------- */

@media (max-width: 768px) {
    .header { flex-direction: column; align-items: flex-start; }
    .header-center { min-width: 100%; }
    .layout { flex-direction: column; }
    .nav-panel { width: 100% !important; max-width: 100% !important; height: 40vh; border-right: none; border-bottom: 1px solid #e9ecef; }
    .file-viewer-panel { width: 100% !important; max-width: 100% !important; border-left: none; border-top: 1px solid #e9ecef; }
}

    </style>
</head>
<body>

<!-- =====================================================================
     HEADER
     ===================================================================== -->

<header class="header">
    <div class="header-left">
        <h1 class="header-title">Trace Edit</h1>
        <div class="header-stats" id="header-stats">
            <span class="stat-badge prd" id="stat-prd">PRD: --</span>
            <span class="stat-badge ops" id="stat-ops">OPS: --</span>
            <span class="stat-badge dev" id="stat-dev">DEV: --</span>
        </div>
    </div>

    <div class="header-center">
        <div class="search-box" id="search-box">
            <input type="text" id="search-input" placeholder="Search requirements..." autocomplete="off">
            <div class="search-results" id="search-results"></div>
        </div>
    </div>

    <div class="header-right">
        <button class="edit-toggle" id="edit-toggle" onclick="toggleEditMode()" title="Toggle edit mode">
            <span class="edit-toggle-indicator"></span>
            <span>Edit Mode</span>
        </button>

        <button class="btn" id="btn-undo" onclick="doUndo()" disabled title="Undo last change">
            Undo
        </button>

        <button class="btn btn-primary" id="btn-save" onclick="doSave()" disabled title="Save mutations to disk">
            Save
            <span class="unsaved-badge hidden" id="unsaved-badge">0</span>
        </button>

        <button class="btn btn-danger" id="btn-revert" onclick="doRevert()" disabled title="Revert all unsaved changes">
            Revert
        </button>
    </div>
</header>

<!-- =====================================================================
     TOAST CONTAINER
     ===================================================================== -->

<div class="toast-container" id="toast-container"></div>

<!-- =====================================================================
     3-PANEL LAYOUT
     ===================================================================== -->

<div class="layout" id="layout">

    <!-- Nav Panel (Left) -->
    <nav class="nav-panel" id="nav-panel">
        <div class="nav-tabs">
            <button class="nav-tab active" data-kind="req" onclick="switchNavTab('req')">Req</button>
            <button class="nav-tab" data-kind="code" onclick="switchNavTab('code')">Code</button>
            <button class="nav-tab" data-kind="test" onclick="switchNavTab('test')">Tests</button>
            <button class="nav-tab" data-kind="journey" onclick="switchNavTab('journey')">Journeys</button>
        </div>
        <div class="nav-tree-container" id="nav-tree-container">
            <div style="padding:20px;color:#adb5bd;text-align:center;font-size:0.85rem;">Loading tree...</div>
        </div>
    </nav>

    <!-- Divider 1 (nav | cards) -->
    <div class="divider" id="divider-left"></div>

    <!-- Card Stack (Center) -->
    <div class="card-stack-panel" id="card-stack-panel">
        <div class="card-stack-header">
            <span id="card-stack-count">No cards open</span>
            <button class="btn" onclick="closeAllCards()" style="padding:3px 8px;font-size:0.75rem;">Close All</button>
        </div>
        <div class="card-stack-body" id="card-stack-body">
            <div class="card-stack-empty" id="card-stack-empty">
                <div class="card-stack-empty-icon">&#128196;</div>
                <div>Click a requirement in the tree to open it</div>
                <div style="font-size:0.75rem;">Cards will appear here</div>
            </div>
        </div>
    </div>

    <!-- Divider 2 (cards | file viewer) -->
    <div class="divider" id="divider-right" style="display:none;"></div>

    <!-- File Viewer Panel (Right) -->
    <aside class="file-viewer-panel" id="file-viewer-panel">
        <div class="file-viewer-header">
            <span class="file-viewer-path" id="fv-path">No file selected</span>
            <span class="fv-status" id="fv-status"></span>
            <button class="file-viewer-close-btn" onclick="closeFileViewer()" title="Close">&times;</button>
        </div>
        <div class="file-viewer-body" id="fv-body">
            <div class="file-viewer-placeholder">Select a source file to view</div>
        </div>
    </aside>

</div>

<!-- =====================================================================
     JAVASCRIPT
     ===================================================================== -->

<script>
// =====================================================================
// State
// =====================================================================

const editState = {
    enabled: false,
    openCards: new Map(),       // nodeId -> {data, collapsed}
    openCardOrder: [],          // nodeId[] — most recent first
    dirtyFields: new Map(),     // fieldKey -> {endpoint, payload, original}
    mutationCount: 0,
    activeNavTab: 'req',
    treeData: [],
    collapsedTreeNodes: new Set(),
    searchDebounce: null
};

// =====================================================================
// Cookie Persistence
// =====================================================================

const COOKIE_NAME = 'elspais_trace_edit_state';
const COOKIE_DAYS = 30;

function saveState() {
    const stateToSave = {
        editEnabled: editState.enabled,
        openCardIds: editState.openCardOrder,
        activeNavTab: editState.activeNavTab,
        collapsedTreeNodes: Array.from(editState.collapsedTreeNodes),
        collapsedCards: []
    };
    // Track which cards are collapsed
    editState.openCards.forEach((info, id) => {
        if (info.collapsed) stateToSave.collapsedCards.push(id);
    });
    const expires = new Date(Date.now() + COOKIE_DAYS * 864e5).toUTCString();
    document.cookie = COOKIE_NAME + '=' + encodeURIComponent(JSON.stringify(stateToSave)) +
        '; expires=' + expires + '; path=/; SameSite=Lax';
}

function loadState() {
    const match = document.cookie.match(new RegExp('(^| )' + COOKIE_NAME + '=([^;]+)'));
    if (!match) return null;
    try {
        return JSON.parse(decodeURIComponent(match[2]));
    } catch (e) {
        return null;
    }
}

// =====================================================================
// API Helpers
// =====================================================================

async function apiFetch(url, options) {
    try {
        const resp = await fetch(url, options);
        const data = await resp.json();
        if (!resp.ok && data.error) {
            showToast(data.error, 'error');
            return null;
        }
        return data;
    } catch (err) {
        showToast('Network error: ' + err.message, 'error');
        return null;
    }
}

async function mutate(endpoint, payload) {
    const data = await apiFetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload)
    });
    if (data && data.success) {
        showToast('Change applied', 'success');
        await refreshDirtyCount();
    } else if (data) {
        showToast(data.error || 'Mutation failed', 'error');
    }
    return data;
}

// =====================================================================
// Toast Notifications
// =====================================================================

function showToast(message, type) {
    type = type || 'info';
    const container = document.getElementById('toast-container');
    const toast = document.createElement('div');
    toast.className = 'toast ' + type;
    toast.textContent = message;
    container.appendChild(toast);
    setTimeout(function() {
        toast.style.opacity = '0';
        toast.style.transition = 'opacity 0.3s';
        setTimeout(function() { toast.remove(); }, 300);
    }, 3000);
}

// =====================================================================
// Header Stats
// =====================================================================

async function loadStats() {
    const data = await apiFetch('/api/status');
    if (!data) return;
    const counts = data.counts || {};
    document.getElementById('stat-prd').textContent = 'PRD: ' + (counts.prd || 0);
    document.getElementById('stat-ops').textContent = 'OPS: ' + (counts.ops || 0);
    document.getElementById('stat-dev').textContent = 'DEV: ' + (counts.dev || 0);
}

async function refreshDirtyCount() {
    const data = await apiFetch('/api/dirty');
    if (!data) return;
    editState.mutationCount = data.mutation_count || 0;
    const badge = document.getElementById('unsaved-badge');
    const btnSave = document.getElementById('btn-save');
    const btnRevert = document.getElementById('btn-revert');
    const btnUndo = document.getElementById('btn-undo');
    if (editState.mutationCount > 0) {
        badge.textContent = editState.mutationCount;
        badge.classList.remove('hidden');
        btnSave.disabled = false;
        btnRevert.disabled = false;
        btnUndo.disabled = false;
    } else {
        badge.classList.add('hidden');
        btnSave.disabled = true;
        btnRevert.disabled = true;
        btnUndo.disabled = true;
    }
}

// =====================================================================
// Nav Tree
// =====================================================================

async function loadTreeData() {
    const data = await apiFetch('/api/tree-data');
    if (!data) return;
    editState.treeData = data;
    renderNavTree();
}

function renderNavTree() {
    const container = document.getElementById('nav-tree-container');
    const activeTab = editState.activeNavTab;
    const rows = editState.treeData;

    if (!rows || rows.length === 0) {
        container.innerHTML = '<div style="padding:20px;color:#adb5bd;text-align:center;font-size:0.85rem;">No items found</div>';
        return;
    }

    // Filter by tab
    let filteredRows;
    if (activeTab === 'req') {
        filteredRows = rows.filter(function(r) { return r.level && r.level !== ''; });
    } else {
        // For code/test/journey — we only have requirement rows from tree-data
        // Show all rows but these tabs will display a "coming soon" message
        filteredRows = rows;
    }

    if (activeTab !== 'req') {
        container.innerHTML = '<div style="padding:20px;color:#adb5bd;text-align:center;font-size:0.85rem;">' +
            activeTab.charAt(0).toUpperCase() + activeTab.slice(1) +
            ' nodes are visible in the requirement tree hierarchy.</div>';
        return;
    }

    let html = '';
    filteredRows.forEach(function(row) {
        // Determine if collapsed
        const isCollapsed = editState.collapsedTreeNodes.has(row.id);
        // Check if parent is collapsed (skip rendering)
        if (row.depth > 0 && isAncestorCollapsed(row, filteredRows)) {
            return; // don't render
        }

        const indents = [];
        for (let i = 0; i < row.depth; i++) {
            indents.push('<span class="nav-tree-indent"></span>');
        }

        const toggleClass = row.has_children
            ? (isCollapsed ? 'nav-tree-toggle' : 'nav-tree-toggle')
            : 'nav-tree-toggle leaf';
        const toggleIcon = row.has_children
            ? (isCollapsed ? '&#9654;' : '&#9660;')
            : '';

        const selectedClass = editState.openCards.has(row.id) ? ' selected' : '';
        const levelClass = row.level ? row.level.toLowerCase() : '';
        const shortId = row.id.replace('REQ-', '');

        html += '<div class="nav-tree-row' + selectedClass + '" ' +
            'data-id="' + row.id + '" ' +
            'data-parent="' + (row.parent_id || '') + '" ' +
            'data-depth="' + row.depth + '" ' +
            'onclick="openCard(\'' + row.id + '\')">' +
            indents.join('') +
            '<button class="' + toggleClass + '" onclick="event.stopPropagation(); toggleTreeNode(\'' + row.id + '\')">' +
            toggleIcon + '</button>' +
            (levelClass ? '<span class="nav-tree-level ' + levelClass + '">' + row.level + '</span>' : '') +
            '<span class="nav-tree-id">' + shortId + '</span>' +
            '<span class="nav-tree-title">' + escapeHtml(row.title || '') + '</span>' +
            '</div>';
    });

    container.innerHTML = html;
}

function isAncestorCollapsed(row, allRows) {
    if (!row.parent_id) return false;
    // Walk up the parent chain
    let parentId = row.parent_id;
    while (parentId) {
        if (editState.collapsedTreeNodes.has(parentId)) return true;
        // Find parent row
        const parentRow = allRows.find(function(r) { return r.id === parentId; });
        if (!parentRow) break;
        parentId = parentRow.parent_id;
    }
    return false;
}

function toggleTreeNode(nodeId) {
    if (editState.collapsedTreeNodes.has(nodeId)) {
        editState.collapsedTreeNodes.delete(nodeId);
    } else {
        editState.collapsedTreeNodes.add(nodeId);
    }
    renderNavTree();
    saveState();
}

function switchNavTab(kind) {
    editState.activeNavTab = kind;
    document.querySelectorAll('.nav-tab').forEach(function(tab) {
        tab.classList.toggle('active', tab.dataset.kind === kind);
    });
    renderNavTree();
    saveState();
}

// =====================================================================
// Card Stack
// =====================================================================

async function openCard(nodeId) {
    // If already open, just focus it
    if (editState.openCards.has(nodeId)) {
        focusCard(nodeId);
        return;
    }

    // Fetch requirement data
    const data = await apiFetch('/api/requirement/' + encodeURIComponent(nodeId));
    if (!data) return;

    // Store in state
    editState.openCards.set(nodeId, { data: data, collapsed: false });

    // Add to front of order
    editState.openCardOrder = editState.openCardOrder.filter(function(id) { return id !== nodeId; });
    editState.openCardOrder.unshift(nodeId);

    renderCardStack();
    focusCard(nodeId);
    updateNavSelection();
    saveState();
}

function closeCard(nodeId) {
    editState.openCards.delete(nodeId);
    editState.openCardOrder = editState.openCardOrder.filter(function(id) { return id !== nodeId; });
    renderCardStack();
    updateNavSelection();
    saveState();
}

function focusCard(nodeId) {
    // Move to front of order
    editState.openCardOrder = editState.openCardOrder.filter(function(id) { return id !== nodeId; });
    editState.openCardOrder.unshift(nodeId);

    // Remove focused class from all, add to target
    document.querySelectorAll('.req-card').forEach(function(c) { c.classList.remove('focused'); });
    const card = document.getElementById('card-' + nodeId);
    if (card) {
        card.classList.add('focused');
        card.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    }

    renderCardStack();
    saveState();
}

function toggleCardCollapse(nodeId) {
    const info = editState.openCards.get(nodeId);
    if (!info) return;
    info.collapsed = !info.collapsed;
    const card = document.getElementById('card-' + nodeId);
    if (card) {
        card.classList.toggle('collapsed', info.collapsed);
    }
    saveState();
}

function closeAllCards() {
    editState.openCards.clear();
    editState.openCardOrder = [];
    renderCardStack();
    updateNavSelection();
    saveState();
}

function renderCardStack() {
    const body = document.getElementById('card-stack-body');
    const empty = document.getElementById('card-stack-empty');
    const countEl = document.getElementById('card-stack-count');

    if (editState.openCardOrder.length === 0) {
        body.innerHTML = '';
        body.appendChild(empty);
        empty.style.display = 'flex';
        countEl.textContent = 'No cards open';
        return;
    }

    empty.style.display = 'none';
    countEl.textContent = editState.openCardOrder.length + ' card' +
        (editState.openCardOrder.length !== 1 ? 's' : '') + ' open';

    let html = '';
    editState.openCardOrder.forEach(function(nodeId) {
        const info = editState.openCards.get(nodeId);
        if (!info) return;
        html += buildCardHtml(nodeId, info.data, info.collapsed);
    });

    body.innerHTML = html;

    // Re-add empty element (hidden) for later
    body.appendChild(empty);
}

function buildCardHtml(nodeId, data, collapsed) {
    const collapsedClass = collapsed ? ' collapsed' : '';
    const focusedClass = editState.openCardOrder[0] === nodeId ? ' focused' : '';
    const shortId = nodeId.replace('REQ-', '');
    const title = escapeHtml(data.title || '');
    const level = (data.level || '').toUpperCase();
    const status = (data.status || '').toLowerCase();
    const statusDisplay = status.charAt(0).toUpperCase() + status.slice(1);
    const hash = data.hash || '';
    const sourcePath = (data.source && data.source.path) || '';
    const sourceLine = (data.source && data.source.line) || 0;

    let html = '<div class="req-card' + collapsedClass + focusedClass + '" id="card-' + nodeId + '">';

    // Header
    html += '<div class="req-card-header" onclick="toggleCardCollapse(\'' + nodeId + '\')">';
    html += '<span class="req-card-expand">&#9660;</span>';
    html += '<span class="req-card-id">' + shortId + '</span>';
    html += '<span class="req-card-title-display">' + title + '</span>';
    html += '<button class="req-card-close" onclick="event.stopPropagation(); closeCard(\'' + nodeId + '\')" title="Close card">&times;</button>';
    html += '</div>';

    // Body
    html += '<div class="req-card-body">';

    // Metadata section
    html += '<div class="card-section"><div class="card-section-label">Metadata</div>';
    html += '<div class="card-meta">';

    // Level
    html += '<div class="card-meta-item">';
    html += '<span class="card-meta-key">Level:</span>';
    html += '<span class="card-meta-value">' + level + '</span>';
    html += '</div>';

    // Status (badge or select)
    html += '<div class="card-meta-item">';
    html += '<span class="card-meta-key">Status:</span>';
    html += '<span class="status-badge-wrapper"><span class="status-badge ' + status + '">' + statusDisplay + '</span></span>';
    html += '<span class="status-select-wrapper edit-only">';
    html += '<select class="status-select" data-node-id="' + nodeId + '" data-original="' + status + '" onchange="onStatusChange(this)">';
    ['Active', 'Draft', 'Deprecated', 'Proposed'].forEach(function(s) {
        const sel = s.toLowerCase() === status ? ' selected' : '';
        html += '<option value="' + s + '"' + sel + '>' + s + '</option>';
    });
    html += '</select></span>';
    html += '</div>';

    // Hash
    html += '<div class="card-meta-item">';
    html += '<span class="card-meta-key">Hash:</span>';
    html += '<span class="card-meta-value" style="font-family:monospace;font-size:0.75rem;">' + hash + '</span>';
    html += '</div>';

    // Source
    if (sourcePath) {
        html += '<div class="card-meta-item">';
        html += '<span class="card-meta-key">Source:</span>';
        html += '<a class="card-meta-value" href="#" onclick="event.preventDefault(); showSource(\'' +
            escapeHtml(sourcePath) + '\', ' + sourceLine + ')" ' +
            'style="color:#0d6efd;cursor:pointer;font-size:0.75rem;text-decoration:none;">' +
            escapeHtml(sourcePath.split('/').pop()) + ':' + sourceLine + '</a>';
        html += '</div>';
    }

    html += '</div></div>';

    // Editable Title (edit mode only, replaces header title on blur)
    html += '<div class="card-section edit-only" style="display:none;"><div class="card-section-label">Title</div>';
    html += '<div class="editable-field" contenteditable="true" data-node-id="' + nodeId + '" ' +
        'data-field="title" data-original="' + escapeAttr(data.title || '') + '" ' +
        'onblur="onTitleBlur(this)" onkeydown="onEditableKeydown(event)">' +
        escapeHtml(data.title || '') + '</div>';
    html += '</div>';

    // Parents section
    if (data.parents && data.parents.length > 0) {
        html += '<div class="card-section"><div class="card-section-label">Implements / Refines</div>';
        html += '<div class="card-parents">';
        data.parents.forEach(function(p) {
            const edgeKind = (p.edge_kind || 'implements').toUpperCase();
            html += '<a class="card-parent-link" href="#" onclick="event.preventDefault(); openCard(\'' + p.id + '\')">';
            html += '<span class="card-parent-kind">' + edgeKind + '</span> ';
            html += p.id.replace('REQ-', '') + ' - ' + escapeHtml(p.title || '');
            html += '</a>';
        });
        html += '</div></div>';
    }

    // Assertions section
    const assertions = (data.children || []).filter(function(c) { return c.kind === 'assertion'; });
    if (assertions.length > 0) {
        html += '<div class="card-section"><div class="card-section-label">Assertions (' + assertions.length + ')</div>';
        html += '<div class="card-assertions">';
        assertions.forEach(function(a) {
            const assertionId = a.id || '';
            const label = a.label || '';
            const text = a.text || '';
            html += '<div class="card-assertion" data-assertion-id="' + assertionId + '">';
            html += '<span class="card-assertion-label">' + label + '</span>';
            html += '<span class="card-assertion-text editable-field" ' +
                'contenteditable="false" data-assertion-id="' + assertionId + '" ' +
                'data-field="assertion" data-original="' + escapeAttr(text) + '" ' +
                'onblur="onAssertionBlur(this)" onkeydown="onEditableKeydown(event)">' +
                escapeHtml(text) + '</span>';
            html += '</div>';
        });
        html += '</div>';

        // Add assertion button (edit mode only)
        html += '<button class="card-add-assertion-btn edit-only" onclick="onAddAssertion(\'' + nodeId + '\')" style="display:none;">+ Add Assertion</button>';
        html += '</div>';
    } else {
        html += '<div class="card-section"><div class="card-section-label">Assertions</div>';
        html += '<div style="font-size:0.8rem;color:#adb5bd;">No assertions defined</div>';
        html += '<button class="card-add-assertion-btn edit-only" onclick="onAddAssertion(\'' + nodeId + '\')" style="display:none;">+ Add Assertion</button>';
        html += '</div>';
    }

    // Children (requirements only)
    const childReqs = (data.children || []).filter(function(c) {
        return c.kind === 'requirement';
    });
    if (childReqs.length > 0) {
        html += '<div class="card-section"><div class="card-section-label">Children (' + childReqs.length + ')</div>';
        html += '<div class="card-children">';
        childReqs.forEach(function(c) {
            html += '<a class="card-child-link" href="#" onclick="event.preventDefault(); openCard(\'' + c.id + '\')">';
            html += c.id.replace('REQ-', '');
            if (c.title) html += ' - ' + escapeHtml(c.title);
            html += '</a>';
        });
        html += '</div></div>';
    }

    html += '</div>'; // end req-card-body
    html += '</div>'; // end req-card

    return html;
}

function updateNavSelection() {
    document.querySelectorAll('.nav-tree-row').forEach(function(row) {
        row.classList.toggle('selected', editState.openCards.has(row.dataset.id));
    });
}

// =====================================================================
// Edit Mode
// =====================================================================

function toggleEditMode() {
    editState.enabled = !editState.enabled;
    document.body.classList.toggle('edit-mode', editState.enabled);
    document.getElementById('edit-toggle').classList.toggle('active', editState.enabled);

    // Toggle contenteditable on assertion text fields
    document.querySelectorAll('.card-assertion-text').forEach(function(el) {
        el.contentEditable = editState.enabled ? 'true' : 'false';
    });

    // Show/hide edit-only elements
    document.querySelectorAll('.edit-only').forEach(function(el) {
        el.style.display = editState.enabled ? '' : 'none';
    });

    saveState();
}

// =====================================================================
// Edit Handlers
// =====================================================================

function onStatusChange(selectEl) {
    const nodeId = selectEl.dataset.nodeId;
    const newStatus = selectEl.value;
    const original = selectEl.dataset.original;

    if (newStatus.toLowerCase() === original) {
        selectEl.classList.remove('dirty');
        return;
    }

    selectEl.classList.add('dirty');
    mutate('/api/mutate/status', { node_id: nodeId, new_status: newStatus }).then(function(result) {
        if (result && result.success) {
            selectEl.dataset.original = newStatus.toLowerCase();
            selectEl.classList.remove('dirty');
            // Refresh the card data
            refreshCard(nodeId);
        }
    });
}

function onTitleBlur(el) {
    if (!editState.enabled) return;
    const nodeId = el.dataset.nodeId;
    const newTitle = el.textContent.trim();
    const original = el.dataset.original;

    if (newTitle === original) {
        el.classList.remove('dirty');
        return;
    }

    if (!newTitle) {
        el.textContent = original;
        el.classList.remove('dirty');
        showToast('Title cannot be empty', 'error');
        return;
    }

    el.classList.add('dirty');
    mutate('/api/mutate/title', { node_id: nodeId, new_title: newTitle }).then(function(result) {
        if (result && result.success) {
            el.dataset.original = newTitle;
            el.classList.remove('dirty');
            refreshCard(nodeId);
        } else {
            el.textContent = original;
            el.classList.remove('dirty');
        }
    });
}

function onAssertionBlur(el) {
    if (!editState.enabled) return;
    const assertionId = el.dataset.assertionId;
    const newText = el.textContent.trim();
    const original = el.dataset.original;

    if (newText === original) {
        el.classList.remove('dirty');
        return;
    }

    if (!newText) {
        el.textContent = original;
        el.classList.remove('dirty');
        showToast('Assertion text cannot be empty', 'error');
        return;
    }

    el.classList.add('dirty');
    mutate('/api/mutate/assertion', { assertion_id: assertionId, new_text: newText }).then(function(result) {
        if (result && result.success) {
            el.dataset.original = newText;
            el.classList.remove('dirty');
        } else {
            el.textContent = original;
            el.classList.remove('dirty');
        }
    });
}

function onAddAssertion(nodeId) {
    const label = prompt('Assertion label (e.g., A, B, C):');
    if (!label) return;
    const text = prompt('Assertion text (SHALL statement):');
    if (!text) return;

    mutate('/api/mutate/assertion/add', {
        req_id: nodeId,
        label: label.trim().toUpperCase(),
        text: text.trim()
    }).then(function(result) {
        if (result && result.success) {
            refreshCard(nodeId);
        }
    });
}

function onEditableKeydown(event) {
    // Enter key = blur (save)
    if (event.key === 'Enter' && !event.shiftKey) {
        event.preventDefault();
        event.target.blur();
    }
    // Escape = revert
    if (event.key === 'Escape') {
        event.target.textContent = event.target.dataset.original;
        event.target.classList.remove('dirty');
        event.target.blur();
    }
}

async function refreshCard(nodeId) {
    const data = await apiFetch('/api/requirement/' + encodeURIComponent(nodeId));
    if (!data) return;
    const info = editState.openCards.get(nodeId);
    if (!info) return;
    info.data = data;
    renderCardStack();
    // Restore edit mode state after re-render
    if (editState.enabled) {
        document.querySelectorAll('.card-assertion-text').forEach(function(el) {
            el.contentEditable = 'true';
        });
        document.querySelectorAll('.edit-only').forEach(function(el) {
            el.style.display = '';
        });
    }
}

// =====================================================================
// Save / Revert / Undo
// =====================================================================

async function doSave() {
    const result = await mutate('/api/save', {});
    if (result && result.success) {
        showToast('Saved to disk', 'success');
    }
    // Even if it returns 501 (not yet implemented), display message
    if (result && result.message) {
        showToast(result.message, 'info');
    }
}

async function doRevert() {
    if (!confirm('Revert all unsaved changes? This cannot be undone.')) return;
    const result = await mutate('/api/revert', {});
    if (result && result.success) {
        showToast('All changes reverted', 'success');
        // Reload all open cards
        editState.openCardOrder.forEach(function(id) {
            refreshCard(id);
        });
    }
    if (result && result.message) {
        showToast(result.message, 'info');
    }
}

async function doUndo() {
    const result = await mutate('/api/mutate/undo', {});
    if (result && result.success) {
        // Reload all open cards to reflect undo
        editState.openCardOrder.forEach(function(id) {
            refreshCard(id);
        });
    }
}

// =====================================================================
// Search
// =====================================================================

function initSearch() {
    const input = document.getElementById('search-input');
    const results = document.getElementById('search-results');

    input.addEventListener('input', function() {
        clearTimeout(editState.searchDebounce);
        const query = input.value.trim();
        if (query.length < 2) {
            results.classList.remove('visible');
            return;
        }
        editState.searchDebounce = setTimeout(function() {
            performSearch(query);
        }, 250);
    });

    input.addEventListener('focus', function() {
        if (results.children.length > 0 && input.value.trim().length >= 2) {
            results.classList.add('visible');
        }
    });

    // Close search results on click outside
    document.addEventListener('click', function(e) {
        if (!document.getElementById('search-box').contains(e.target)) {
            results.classList.remove('visible');
        }
    });

    // Keyboard navigation
    input.addEventListener('keydown', function(e) {
        if (e.key === 'Escape') {
            results.classList.remove('visible');
            input.blur();
        }
        if (e.key === 'Enter') {
            const first = results.querySelector('.search-result-item');
            if (first) {
                first.click();
                results.classList.remove('visible');
            }
        }
    });
}

async function performSearch(query) {
    const data = await apiFetch('/api/search?q=' + encodeURIComponent(query));
    const results = document.getElementById('search-results');
    if (!data || data.length === 0) {
        results.innerHTML = '<div style="padding:12px;color:#adb5bd;text-align:center;font-size:0.8rem;">No results</div>';
        results.classList.add('visible');
        return;
    }

    let html = '';
    data.slice(0, 20).forEach(function(item) {
        const level = (item.level || '').toUpperCase();
        const levelColor = level === 'PRD' ? '#212529'
            : level === 'OPS' ? '#fd7e14'
            : level === 'DEV' ? '#20c997' : '#6c757d';
        html += '<div class="search-result-item" onclick="openCard(\'' + item.id + '\'); ' +
            'document.getElementById(\'search-results\').classList.remove(\'visible\');">';
        html += '<span class="search-result-level" style="background:' + levelColor + ';color:white;">' + level + '</span>';
        html += '<span class="search-result-id">' + item.id.replace('REQ-', '') + '</span>';
        html += '<span class="search-result-title">' + escapeHtml(item.title || '') + '</span>';
        html += '</div>';
    });

    results.innerHTML = html;
    results.classList.add('visible');
}

// =====================================================================
// File Viewer
// =====================================================================

async function showSource(filePath, lineNumber) {
    const panel = document.getElementById('file-viewer-panel');
    const divider = document.getElementById('divider-right');
    const pathEl = document.getElementById('fv-path');
    const statusEl = document.getElementById('fv-status');
    const body = document.getElementById('fv-body');

    pathEl.textContent = filePath;
    pathEl.title = filePath;
    statusEl.textContent = '';
    statusEl.className = 'fv-status';

    // Show panel and divider
    panel.classList.add('open');
    divider.style.display = '';

    // Show loading state
    body.innerHTML = '<div style="padding:24px;color:#adb5bd;text-align:center;">Loading...</div>';

    try {
        const resp = await fetch('/api/file-content?path=' + encodeURIComponent(filePath));
        if (!resp.ok) {
            const err = await resp.json().catch(function() { return {}; });
            body.innerHTML = '<div style="padding:24px;color:#dc3545;text-align:center;">' +
                escapeHtml(err.error || 'Failed to load file') + '</div>';
            return;
        }
        const data = await resp.json();

        // Update status badge
        if (data.has_pending_mutations) {
            statusEl.textContent = data.pending_mutation_count + ' pending edit' +
                (data.pending_mutation_count !== 1 ? 's' : '');
            statusEl.className = 'fv-status has-mutations';
            statusEl.title = 'Unsaved mutations would modify this file: ' +
                (data.affected_nodes || []).join(', ');
        } else {
            statusEl.textContent = 'on disk';
            statusEl.className = 'fv-status on-disk';
            statusEl.title = 'Showing current file contents from disk';
        }

        // Render lines with line numbers
        var html = '<div class="source-table" role="presentation">';
        var lines = data.lines || [];
        for (var i = 0; i < lines.length; i++) {
            var num = i + 1;
            var cls = 'source-line';
            if (num === lineNumber) cls += ' highlighted';
            html += '<div class="' + cls + '" id="fv-line-' + num + '">' +
                '<span class="line-num">' + num + '</span>' +
                '<span class="line-content">' + escapeHtml(lines[i]) + '</span>' +
                '</div>';
        }
        html += '</div>';
        body.innerHTML = html;

        // Scroll to the target line
        if (lineNumber > 0) {
            var target = document.getElementById('fv-line-' + lineNumber);
            if (target) {
                setTimeout(function() {
                    target.scrollIntoView({ block: 'center', behavior: 'smooth' });
                }, 100);
            }
        }

    } catch (e) {
        body.innerHTML = '<div style="padding:24px;color:#dc3545;text-align:center;">' +
            'Error loading file: ' + escapeHtml(String(e)) + '</div>';
    }
}

function closeFileViewer() {
    document.getElementById('file-viewer-panel').classList.remove('open');
    document.getElementById('divider-right').style.display = 'none';
}

// =====================================================================
// Resizable Dividers
// =====================================================================

function initDividers() {
    initDivider('divider-left', 'nav-panel', 'left');
    initDivider('divider-right', 'file-viewer-panel', 'right');
}

function initDivider(dividerId, panelId, side) {
    const divider = document.getElementById(dividerId);
    const panel = document.getElementById(panelId);
    const layout = document.getElementById('layout');
    let isDragging = false;

    divider.addEventListener('mousedown', function(e) {
        isDragging = true;
        divider.classList.add('dragging');
        document.body.style.cursor = 'col-resize';
        document.body.style.userSelect = 'none';
        e.preventDefault();
    });

    document.addEventListener('mousemove', function(e) {
        if (!isDragging) return;
        const layoutRect = layout.getBoundingClientRect();
        if (side === 'left') {
            const width = Math.max(150, Math.min(500, e.clientX - layoutRect.left));
            panel.style.width = width + 'px';
        } else {
            const width = Math.max(250, Math.min(layoutRect.width * 0.6, layoutRect.right - e.clientX));
            panel.style.width = width + 'px';
        }
    });

    document.addEventListener('mouseup', function() {
        if (!isDragging) return;
        isDragging = false;
        divider.classList.remove('dragging');
        document.body.style.cursor = '';
        document.body.style.userSelect = '';
        saveState();
    });
}

// =====================================================================
// Keyboard Shortcuts
// =====================================================================

document.addEventListener('keydown', function(e) {
    // Escape closes file viewer first
    if (e.key === 'Escape') {
        if (document.getElementById('file-viewer-panel').classList.contains('open')) {
            closeFileViewer();
        }
    }

    // Ctrl+E toggles edit mode
    if (e.key === 'e' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        toggleEditMode();
    }

    // Ctrl+Z = undo (only when not in a text field)
    if (e.key === 'z' && (e.ctrlKey || e.metaKey) && !e.target.isContentEditable && e.target.tagName !== 'INPUT') {
        e.preventDefault();
        doUndo();
    }

    // Ctrl+K = focus search
    if (e.key === 'k' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        document.getElementById('search-input').focus();
    }
});

// =====================================================================
// Utilities
// =====================================================================

function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

function escapeAttr(text) {
    return text.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

// =====================================================================
// Initialize
// =====================================================================

document.addEventListener('DOMContentLoaded', function() {
    // Load initial data
    loadStats();
    loadTreeData();
    initSearch();
    initDividers();
    refreshDirtyCount();

    // Restore saved state
    const saved = loadState();
    if (saved) {
        // Restore nav tab
        if (saved.activeNavTab) {
            editState.activeNavTab = saved.activeNavTab;
            document.querySelectorAll('.nav-tab').forEach(function(tab) {
                tab.classList.toggle('active', tab.dataset.kind === saved.activeNavTab);
            });
        }

        // Restore edit mode
        if (saved.editEnabled) {
            toggleEditMode();
        }

        // Restore collapsed tree nodes
        if (saved.collapsedTreeNodes && Array.isArray(saved.collapsedTreeNodes)) {
            editState.collapsedTreeNodes = new Set(saved.collapsedTreeNodes);
        }

        // Restore open cards (fetch each)
        if (saved.openCardIds && saved.openCardIds.length > 0) {
            const collapsedSet = new Set(saved.collapsedCards || []);
            // Load cards in reverse so they end up in correct order
            const ids = saved.openCardIds.slice().reverse();
            (async function restoreCards() {
                for (const id of ids) {
                    const data = await apiFetch('/api/requirement/' + encodeURIComponent(id));
                    if (data && !data.error) {
                        editState.openCards.set(id, {
                            data: data,
                            collapsed: collapsedSet.has(id)
                        });
                        editState.openCardOrder.push(id);
                    }
                }
                // Reverse to restore original order (most recent first)
                editState.openCardOrder.reverse();
                renderCardStack();
                updateNavSelection();
                // Restore edit mode state on cards
                if (editState.enabled) {
                    document.querySelectorAll('.card-assertion-text').forEach(function(el) {
                        el.contentEditable = 'true';
                    });
                    document.querySelectorAll('.edit-only').forEach(function(el) {
                        el.style.display = '';
                    });
                }
            })();
        }
    }
});
</script>

</body>
</html>
