{% extends "shared/frontend/base.html" %}

{% block title %}{{ case.titel }} - BMC Hub{% endblock %}

{% block extra_css %}
<style>
        .time-v1-calendar-container {
            background: var(--bg-surface, #fff);
            border: 1px solid var(--border-color, #e0e0e0);
            border-radius: 12px;
            margin-bottom: 2rem;
            overflow: hidden;
            box-shadow: 0 4px 12px rgba(0,0,0,0.03);
        }
        .time-v1-calendar-header {
            background: var(--bg-element, #f8f9fa);
            border-bottom: 1px solid var(--border-color, #e0e0e0);
            padding: 12px 20px;
            font-weight: 600;
            font-size: 1rem;
            display: flex;
            align-items: center;
            gap: 8px;
            color: var(--text-color);
        }
        .time-v1-calendar-grid {
            display: flex;
            position: relative;
        }
        .time-v1-time-axis {
            width: 60px;
            flex-shrink: 0;
            border-right: 1px solid var(--border-color, #f0f0f0);
            position: relative;
            background: var(--bg-element, #fafafa);
            padding-top: 40px; 
        }
        .time-v1-hour-marker {
            position: absolute;
            width: 100%;
            text-align: center;
            font-size: 0.75rem;
            color: var(--text-secondary);
            transform: translateY(-50%);
        }
        .time-v1-tech-col {
            width: 200px;
            max-width: 200px;
            flex-shrink: 0;
            border-right: 1px solid var(--border-color, #f0f0f0);
            position: relative;
        }
        .time-v1-tech-col:last-child {
            border-right: none;
        }
        .time-v1-tech-header {
            text-align: center;
            padding: 8px;
            height: 40px;
            font-weight: 600;
            font-size: 0.85rem;
            border-bottom: 1px solid var(--border-color, #e0e0e0);
            background: var(--bg-element, #f8f9fa);
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
            position: sticky;
            z-index: 50;
            color: var(--text-color);
        }
        .time-v1-tech-body {
            position: relative;
            height: 600px;
            background-image: linear-gradient(to bottom, transparent 59px, var(--border-color, #f0f0f0) 60px);
            background-size: 100% 60px; 
        }
        .time-v1-entry-block {
            position: absolute;
            box-sizing: border-box;
            border-radius: 6px;
            padding: 6px 8px;
            font-size: 0.8rem;
            overflow: hidden;
            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
            transition: transform 0.2s, box-shadow 0.2s, z-index 0.2s;
            border-left: 4px solid var(--bs-secondary);
            background: var(--bg-surface, #fff);
            cursor: grab;
            z-index: 10;
        }
        .time-v1-entry-block:active { cursor: grabbing; opacity: 0.9; }
        .time-v1-entry-block:hover {
            transform: translateY(-1px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.15);
            z-index: 20;
        }
        .time-v1-entry-pending { border-left-color: #f59e0b; background: rgba(245, 158, 11, 0.05) !important; }
        .time-v1-entry-godkendt { border-left-color: #2fb344; background: rgba(47, 179, 68, 0.05) !important; }
        .time-v1-entry-kladde { border-left-color: #6c757d; background: rgba(108, 117, 125, 0.05) !important; }
        .time-v1-entry-time {
            font-weight: 600;
            font-size: 0.75rem;
            margin-bottom: 2px;
            color: var(--text-color);
        }
        .time-v1-entry-desc {
            color: var(--text-secondary);
            font-size: 0.75rem;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }
        .time-v1-unplaced-container {
            padding: 12px 20px;
            border-top: 1px solid var(--border-color);
            background: var(--bg-element);
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            align-items: center;
        }
        .time-v1-unplaced-item {
            background: var(--bg-surface);
            border: 1px solid var(--border-color);
            padding: 4px 10px;
            border-radius: 20px;
            font-size: 0.8rem;
            display: inline-flex;
            align-items: center;
            gap: 6px;
            color: var(--text-color);
        }
        .time-v1-unplaced-item[draggable="true"] {
            cursor: grab;
        }
        .time-v1-unplaced-item.dragging,
        .time-v1-entry-block.dragging {
            opacity: 0.6;
        }
        .time-v1-tech-body.time-v1-drop-target {
            outline: 2px dashed rgba(15, 76, 117, 0.45);
            outline-offset: -4px;
            background-color: rgba(15, 76, 117, 0.06);
        }

        .time-v1-calendar-container {
            background: var(--bg-surface, #fff);
            border: 1px solid var(--border-color, #e0e0e0);
            border-radius: 12px;
            margin-bottom: 2rem;
            overflow: hidden;
            box-shadow: 0 4px 12px rgba(0,0,0,0.03);
        }
        .time-v1-calendar-header {
            background: var(--bg-element, #f8f9fa);
            border-bottom: 1px solid var(--border-color, #e0e0e0);
            padding: 12px 20px;
            font-weight: 600;
            font-size: 1rem;
            display: flex;
            align-items: center;
            gap: 8px;
            color: var(--text-color);
        }
        .time-v1-calendar-grid {
            display: flex;
            position: relative;
            overflow-x: auto;
        }
        .time-v1-time-axis {
            width: 60px;
            flex-shrink: 0;
            border-right: 1px solid var(--border-color, #f0f0f0);
            position: relative;
            background: var(--bg-element, #fafafa);
            padding-top: 40px; 
        }
        .time-v1-hour-marker {
            position: absolute;
            width: 100%;
            text-align: center;
            font-size: 0.75rem;
            color: var(--text-secondary);
            transform: translateY(-50%);
        }
        .time-v1-tech-col {
            width: 200px;
            max-width: 200px;
            flex-shrink: 0;
            border-right: 1px solid var(--border-color, #f0f0f0);
            position: relative;
        }
        .time-v1-tech-col:last-child {
            border-right: none;
        }
        .time-v1-tech-header {
            text-align: center;
            padding: 8px;
            height: 40px;
            font-weight: 600;
            font-size: 0.85rem;
            border-bottom: 1px solid var(--border-color, #e0e0e0);
            background: var(--bg-element, #f8f9fa);
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
            position: sticky;
            top: 0;
            z-index: 50;
            color: var(--text-color);
        }
        .time-v1-tech-body {
            position: relative;
            height: 600px;
            background-image: linear-gradient(to bottom, transparent 59px, var(--border-color, #f0f0f0) 60px);
            background-size: 100% 60px; 
        }
        .time-v1-entry-block {
            position: absolute;
            box-sizing: border-box;
            border-radius: 6px;
            padding: 6px 8px;
            font-size: 0.8rem;
            overflow: hidden;
            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
            transition: transform 0.2s, box-shadow 0.2s, z-index 0.2s;
            border-left: 4px solid var(--bs-secondary);
            background: var(--bg-surface, #fff);
            cursor: grab;
            z-index: 10;
        }
        .time-v1-entry-block:active { cursor: grabbing; opacity: 0.9; }
        .time-v1-entry-block:hover {
            transform: translateY(-1px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.15);
            z-index: 20;
        }
        .time-v1-entry-pending { border-left-color: #f59e0b; background: rgba(245, 158, 11, 0.05) !important; }
        .time-v1-entry-godkendt { border-left-color: #2fb344; background: rgba(47, 179, 68, 0.05) !important; }
        .time-v1-entry-kladde { border-left-color: #6c757d; background: rgba(108, 117, 125, 0.05) !important; }
        .time-v1-entry-time {
            font-weight: 600;
            font-size: 0.75rem;
            margin-bottom: 2px;
            color: var(--text-color);
        }
        .time-v1-entry-desc {
            color: var(--text-secondary);
            font-size: 0.75rem;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }
        .time-v1-unplaced-container {
            padding: 12px 20px;
            border-top: 1px solid var(--border-color);
            background: var(--bg-element);
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            align-items: center;
        }
        .time-v1-unplaced-item {
            background: var(--bg-surface);
            border: 1px solid var(--border-color);
            padding: 4px 10px;
            border-radius: 20px;
            font-size: 0.8rem;
            display: inline-flex;
            align-items: center;
            gap: 6px;
            color: var(--text-color);
        }

    .info-row {
        display: flex;
        justify-content: space-between;
        padding: 0.8rem 0;
        border-bottom: 1px solid rgba(0,0,0,0.05);
    }

    .info-row:last-child {
        border-bottom: none;
    }

    .info-label {
        font-weight: 600;
        color: var(--text-secondary);
        min-width: 150px;
    }

    .info-value {
        color: var(--text-primary);
    }

    .tag {
        display: inline-block;
        background: var(--accent-light);
        color: var(--accent);
        padding: 0.4rem 0.8rem;
        border-radius: 20px;
        font-size: 0.85rem;
        font-weight: 500;
        margin-right: 0.5rem;
        margin-bottom: 0.5rem;
    }

    .person-card {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 1rem;
        background: var(--bg-body);
        border-radius: 8px;
        margin-bottom: 0.5rem;
    }

    .person-info strong {
        display: block;
        color: var(--accent);
    }

    .person-info small {
        color: var(--text-secondary);
        display: block;
    }

    .action-buttons {
        display: flex;
        gap: 1rem;
        flex-wrap: wrap;
        margin-top: 2rem;
    }

    .btn-delete {
        background-color: #e74c3c;
        color: white;
    }

    .btn-delete:hover {
        background-color: #c0392b;
    }

    .form-control, .form-select {
        border-radius: 8px;
        border: 1px solid rgba(0,0,0,0.1);
    }

    .tag-closed {
        background-color: #e0e0e0;
        color: #666;
        text-decoration: line-through;
    }

    [data-bs-theme="dark"] .tag-closed {
        background-color: #3a3a3a;
        color: #999;
    }

    .tag-state-badge {
        font-size: 0.75rem;
        padding: 0.2rem 0.4rem;
        border-radius: 4px;
        margin-left: 0.5rem;
        font-weight: 600;
    }

    .tag-state-open {
        background: #d4edda;
        color: #155724;
    }

    .tag-state-closed {
        background: #f8d7da;
        color: #721c24;
    }

    [data-bs-theme="dark"] .tag-state-open {
        background: #1e4620;
        color: #7fd98d;
    }

    [data-bs-theme="dark"] .tag-state-closed {
        background: #5c2b2f;
        color: #f8a5ac;
    }

    /* ═══════════════ PREMIUM CASE HERO ═══════════════ */
    .case-hero {
        background: var(--bg-card);
        border-radius: 16px;
        overflow: visible;
        box-shadow:
            0 0 0 1px rgba(0,0,0,0.06),
            0 4px 6px -1px rgba(0,0,0,0.05),
            0 16px 32px -8px rgba(15,76,117,0.10);
    }

    .case-hero-identity {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0.75rem 1.5rem;
        background: linear-gradient(135deg, rgba(15,76,117,0.04) 0%, rgba(15,76,117,0.01) 100%);
        border-bottom: 1px solid rgba(0,0,0,0.06);
        flex-wrap: wrap;
        gap: 0.5rem;
        border-radius: 16px 16px 0 0;
        overflow: hidden;
    }

    .case-id-chip {
        display: inline-flex;
        align-items: center;
        font-size: 1.0rem;
        font-weight: 900;
        letter-spacing: -0.5px;
        color: var(--tcolor, #0f4c75);
        background: color-mix(in srgb, var(--tcolor, #0f4c75) 10%, transparent);
        border: 1.5px solid color-mix(in srgb, var(--tcolor, #0f4c75) 30%, transparent);
        border-radius: 8px;
        padding: 0.2em 0.65em;
    }

    .case-type-chip {
        display: inline-flex;
        align-items: center;
        gap: 0.3em;
        font-size: 0.73rem;
        font-weight: 700;
        letter-spacing: 0.05em;
        text-transform: uppercase;
        color: var(--tcolor, #0f4c75);
        background: color-mix(in srgb, var(--tcolor, #0f4c75) 8%, transparent);
        border: 1px solid color-mix(in srgb, var(--tcolor, #0f4c75) 25%, transparent);
        border-radius: 999px;
        padding: 0.3em 0.8em;
        transition: all 0.15s ease;
    }

    .case-type-chip:hover {
        background: color-mix(in srgb, var(--tcolor, #0f4c75) 18%, transparent);
        transform: translateY(-1px);
    }

    .case-status-chip {
        display: inline-flex;
        align-items: center;
        gap: 0.4em;
        font-size: 0.73rem;
        font-weight: 700;
        letter-spacing: 0.04em;
        border-radius: 999px;
        padding: 0.3em 0.85em;
        border: 1px solid transparent;
    }

    .case-status-chip.open {
        background: #dcfce7;
        color: #15803d;
        border-color: #86efac;
    }

    .case-status-chip.closed {
        background: #f1f5f9;
        color: #475569;
        border-color: #cbd5e1;
    }

    [data-bs-theme="dark"] .case-status-chip.open {
        background: rgba(21,128,61,0.15);
        color: #4ade80;
        border-color: rgba(74,222,128,0.3);
    }

    [data-bs-theme="dark"] .case-status-chip.closed {
        background: rgba(71,85,105,0.15);
        color: #94a3b8;
        border-color: rgba(148,163,184,0.2);
    }

    .case-status-dot {
        width: 7px;
        height: 7px;
        border-radius: 50%;
        background: currentColor;
        opacity: 0.85;
        flex-shrink: 0;
        animation: none;
    }

    .case-status-chip.open .case-status-dot {
        background: #16a34a;
        box-shadow: 0 0 0 2px #dcfce7, 0 0 6px #16a34a80;
        animation: pulse-dot 2s ease-in-out infinite;
    }

    @keyframes pulse-dot {
        0%, 100% { opacity: 1; }
        50% { opacity: 0.5; }
    }

    .case-date-item {
        display: inline-flex;
        align-items: center;
        gap: 0.3em;
        font-size: 0.72rem;
        color: var(--text-secondary);
        opacity: 0.8;
    }

    .case-date-item i {
        opacity: 0.5;
        font-size: 0.75rem;
    }

    .case-date-sep {
        color: var(--text-secondary);
        opacity: 0.3;
        font-size: 1rem;
    }

    .case-hero-meta {
        display: flex;
        align-items: stretch;
        flex-wrap: wrap;
        padding: 0 0.25rem;
        min-height: 70px;
    }

    .case-meta-cell {
        display: flex;
        flex-direction: column;
        justify-content: center;
        padding: 0.85rem 1.25rem;
        min-width: 0;
        transition: background 0.12s;
        border-radius: 4px;
    }

    .case-meta-cell:hover {
        background: rgba(0,0,0,0.025);
    }

    [data-bs-theme="dark"] .case-meta-cell:hover {
        background: rgba(255,255,255,0.04);
    }

    .case-meta-divider {
        width: 1px;
        background: rgba(0,0,0,0.07);
        margin: 0.6rem 0;
        align-self: stretch;
        flex-shrink: 0;
    }

    [data-bs-theme="dark"] .case-meta-divider {
        background: rgba(255,255,255,0.06);
    }

    .case-meta-label {
        font-size: 0.6rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        color: var(--text-secondary);
        opacity: 0.55;
        display: flex;
        align-items: center;
        gap: 0.3em;
        margin-bottom: 3px;
        white-space: nowrap;
    }

    .case-meta-label i {
        font-size: 0.72rem;
        opacity: 0.8;
    }

    .case-meta-value {
        font-size: 0.88rem;
        font-weight: 600;
        color: var(--text-primary);
        white-space: nowrap;
        display: block;
        line-height: 1.3;
    }

    .case-meta-link {
        cursor: pointer;
        transition: color 0.12s;
    }

    .case-meta-link:hover {
        color: var(--accent) !important;
    }

    .case-meta-empty {
        font-size: 0.8rem;
        color: var(--text-secondary);
        opacity: 0.5;
        font-style: italic;
    }

    .case-inline-select {
        border: 1px solid rgba(0,0,0,0.09);
        background: var(--bg-body);
        color: var(--text-primary);
        font-weight: 600;
        font-size: 0.82rem;
        border-radius: 8px;
        padding: 0.3rem 0.6rem;
        cursor: pointer;
        min-width: 120px;
        max-width: 160px;
        box-shadow: 0 1px 3px rgba(0,0,0,0.04);
        transition: border-color 0.12s, box-shadow 0.12s;
        appearance: auto;
    }

    .case-inline-select:focus {
        outline: none;
        border-color: var(--accent);
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
    }

    .case-date-badge {
        display: inline-flex;
        align-items: center;
        gap: 0.35em;
        font-size: 0.8rem;
        font-weight: 700;
        padding: 0.25em 0.75em;
        border-radius: 8px;
        background: rgba(0,0,0,0.04);
        border: 1px solid rgba(0,0,0,0.09);
        color: var(--text-primary);
        white-space: nowrap;
    }

    .case-date-badge.overdue {
        background: #fef2f2;
        border-color: #fca5a5;
        color: #b91c1c;
    }

    .case-date-badge.deferred {
        background: #fffbeb;
        border-color: #fcd34d;
        color: #92400e;
    }

    [data-bs-theme="dark"] .case-date-badge {
        background: rgba(255,255,255,0.05);
        border-color: rgba(255,255,255,0.1);
    }

    [data-bs-theme="dark"] .case-date-badge.overdue {
        background: rgba(185,28,28,0.2);
        border-color: rgba(252,165,165,0.3);
        color: #fca5a5;
    }

    [data-bs-theme="dark"] .case-date-badge.deferred {
        background: rgba(146,64,14,0.2);
        border-color: rgba(252,211,77,0.3);
        color: #fcd34d;
    }

    .case-edit-btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 24px;
        height: 24px;
        border-radius: 6px;
        border: 1px solid rgba(0,0,0,0.08);
        background: transparent;
        color: var(--text-secondary);
        font-size: 0.7rem;
        opacity: 0.5;
        transition: all 0.12s;
        cursor: pointer;
        padding: 0;
        flex-shrink: 0;
    }

    .case-edit-btn:hover {
        opacity: 1;
        background: var(--bg-body);
        border-color: var(--accent);
        color: var(--accent);
        transform: scale(1.1);
    }

    .hero-meta-label {
        font-size: 0.62rem;
        text-transform: uppercase;
        letter-spacing: 0.07em;
        font-weight: 700;
        color: var(--text-secondary);
        opacity: 0.6;
        margin-bottom: 3px;
        white-space: nowrap;
    }

    .hero-meta-value {
        font-size: 0.9rem;
        font-weight: 600;
        color: var(--text-primary);
        display: block;
        white-space: nowrap;
    }

    .hero-meta-value:hover {
        color: var(--accent);
    }

    [data-bs-theme="dark"] .hero-meta-label {
        color: rgba(255,255,255,0.45);
    }

    .case-summary-card {
        border: 1px solid rgba(0,0,0,0.06);
        background: var(--bg-card);
        box-shadow: 0 6px 18px rgba(15, 76, 117, 0.08);
    }

    .case-summary-header {
        background: linear-gradient(135deg, rgba(15, 76, 117, 0.12), rgba(15, 76, 117, 0.02));
        border-bottom: 1px solid rgba(0,0,0,0.06);
        padding: 0.85rem 1rem;
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 1rem;
    }

    .case-summary-title {
        font-size: 1.15rem;
        font-weight: 700;
        color: var(--accent);
        margin-bottom: 0.25rem;
    }

    .case-summary-meta {
        display: flex;
        gap: 0.4rem;
        flex-wrap: wrap;
    }

    .case-pill {
        display: inline-flex;
        align-items: center;
        gap: 0.25rem;
        padding: 0.2rem 0.6rem;
        border-radius: 999px;
        font-size: 0.7rem;
        font-weight: 600;
        background: rgba(15, 76, 117, 0.12);
        color: var(--accent);
    }

    .case-pill-muted {
        background: rgba(0,0,0,0.06);
        color: var(--text-secondary);
    }

    .case-summary-body {
        padding: 1rem;
    }

    .case-summary-grid {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: 0.75rem 1rem;
    }

    @media (max-width: 992px) {
        .case-summary-grid {
            grid-template-columns: repeat(2, minmax(0, 1fr));
        }
    }

    @media (max-width: 576px) {
        .case-summary-grid {
            grid-template-columns: 1fr;
        }
    }

    .summary-item {
        padding: 0.4rem 0.5rem;
        border-radius: 10px;
        background: rgba(0,0,0,0.02);
        border: 1px solid rgba(0,0,0,0.04);
        min-height: 44px;
    }

    .summary-label {
        font-size: 0.62rem;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        color: var(--text-secondary);
        margin-bottom: 0.15rem;
        font-weight: 600;
    }

    .summary-value {
        font-weight: 600;
        font-size: 0.85rem;
        color: var(--text-primary);
        word-break: break-word;
    }

    .summary-link {
        color: var(--accent);
        cursor: pointer;
        text-decoration: underline;
        text-underline-offset: 3px;
    }

    .case-summary-desc {
        margin-top: 0.9rem;
        padding: 0.8rem 0.9rem;
        border-radius: 12px;
        background: rgba(15, 76, 117, 0.05);
        border: 1px dashed rgba(15, 76, 117, 0.2);
    }

    .defer-controls {
        display: flex;
        gap: 0.4rem;
        flex-wrap: wrap;
        margin-top: 0.35rem;
    }

    .defer-controls .btn {
        padding: 0.15rem 0.45rem;
        font-size: 0.72rem;
    }

    .summary-inline {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 0.5rem;
        flex-wrap: wrap;
    }

    .summary-inline .summary-pill {
        display: inline-flex;
        align-items: center;
        gap: 0.3rem;
        padding: 0.2rem 0.5rem;
        border-radius: 999px;
        font-size: 0.72rem;
        background: rgba(0,0,0,0.05);
        color: var(--text-secondary);
    }

    /* Forslag 1: Opgavebeskrivelse + kommentarspor (venstre side) */
    .narrative-description {
        border: 0;
        background: transparent;
        border-radius: 0;
        padding: 0.25rem 0.1rem 0;
        box-shadow: none;
    }

    #beskrivelse-section {
        display: flex;
        flex-direction: column;
        gap: 1rem;
    }

    .case-left-section-title {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        font-size: 0.82rem;
        font-weight: 800;
        letter-spacing: 0.06em;
        text-transform: uppercase;
        color: color-mix(in srgb, var(--accent) 68%, #2f3a45);
        margin-bottom: 0.55rem;
    }

    .case-left-section-title i {
        color: var(--accent);
    }

    .case-left-panel {
        border: 1px solid rgba(15, 76, 117, 0.18);
        border-radius: 12px;
        background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 4%, var(--bg-card)), var(--bg-card));
        padding: 0.9rem;
        box-shadow: 0 2px 8px rgba(15, 76, 117, 0.06);
    }

    #beskrivelse-history-wrap {
        border: 1px solid rgba(15, 76, 117, 0.18);
        border-radius: 12px;
        background: color-mix(in srgb, var(--accent) 6%, var(--bg-card));
        padding: 0.75rem 0.85rem;
    }

    #beskrivelse-history-wrap .btn-link {
        font-weight: 600;
        font-size: 0.86rem;
    }

    #beskrivelse-comments-wrap {
        border: 0;
        border-radius: 0;
        background: transparent;
        padding: 0;
    }

    .narrative-lead {
        color: var(--accent);
        font-size: 1.1rem;
        font-weight: 800;
        margin-bottom: 0.55rem;
        line-height: 1.3;
    }

    #beskrivelse-text {
        color: var(--text-primary) !important;
        font-size: 1rem !important;
        line-height: 1.7 !important;
    }

    .comment-thread {
        border: 1px solid rgba(15, 76, 117, 0.2);
        border-radius: 10px;
        padding: 0.65rem;
        max-height: 360px;
        overflow-y: auto;
        background: color-mix(in srgb, var(--accent) 3%, var(--bg-body));
    }

    .comment-item {
        border: 1px solid rgba(15, 76, 117, 0.16);
        border-radius: 10px;
        background: var(--bg-card);
        padding: 0.55rem 0.65rem;
        margin-bottom: 0.5rem;
        box-shadow: 0 1px 4px rgba(15, 76, 117, 0.05);
    }

    .comment-item:last-child {
        margin-bottom: 0;
    }

    .comment-meta {
        display: flex;
        align-items: center;
        gap: 0.45rem;
        margin-bottom: 0.25rem;
        font-size: 0.75rem;
        color: var(--text-secondary);
    }

    .comment-meta b {
        color: var(--text-primary);
        font-size: 0.8rem;
    }

    .comment-time {
        margin-left: auto;
        font-size: 0.72rem;
        color: var(--text-secondary);
    }

    .comment-avatar {
        width: 22px;
        height: 22px;
        border-radius: 50%;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        font-size: 0.63rem;
        font-weight: 700;
        color: #fff;
        background: var(--accent);
        flex-shrink: 0;
    }

    .comment-item.comment-internal .comment-avatar {
        background: #2f7aa8;
    }

    .comment-item.comment-system .comment-avatar {
        background: #6f7f8e;
    }

    .comment-body {
        line-height: 1.45;
        color: var(--text-primary);
        font-size: 0.89rem;
        display: -webkit-box;
        -webkit-line-clamp: 6;
        -webkit-box-orient: vertical;
        overflow: hidden;
        white-space: normal;
        word-break: break-word;
    }

    .comment-actions {
        margin-top: 0.35rem;
        display: flex;
        align-items: center;
        gap: 0.75rem;
        flex-wrap: wrap;
    }

    .comment-actions .btn-link {
        padding: 0;
        font-size: 0.78rem;
        text-decoration: none;
    }

    .comment-quick-reply-box {
        margin-top: 0.75rem;
        border: 1px solid rgba(15, 76, 117, 0.2);
        border-radius: 10px;
        background: color-mix(in srgb, var(--accent) 3%, var(--bg-card));
        padding: 0.6rem;
    }

    .comment-quick-reply-actions {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 0.5rem;
        margin-top: 0.45rem;
    }

    .comment-quick-reply-status {
        font-size: 0.8rem;
        color: var(--text-secondary);
    }

    .comment-email-header {
        font-size: 0.78rem;
        color: var(--text-secondary);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .comment-email-text {
        margin-top: 0.2rem;
    }

    .comment-composer {
        display: flex;
        gap: 0.5rem;
        align-items: stretch;
    }

    .comment-composer textarea {
        border-radius: 10px;
        min-height: 68px;
    }

    .comment-send {
        border-radius: 10px;
        font-weight: 700;
        white-space: nowrap;
        min-width: 96px;
    }

    .email-column-shell {
        border: 1px solid var(--border-color, #dbe3ea);
        border-radius: 14px;
        overflow: hidden;
        background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(247, 250, 253, 0.96));
        box-shadow: 0 6px 20px rgba(15, 76, 117, 0.06);
    }

    .email-column-shell .column-header {
        background: linear-gradient(90deg, rgba(15, 76, 117, 0.08), rgba(15, 76, 117, 0.02));
    }

    .email-thread-item .participants-line {
        font-size: 0.78rem;
        color: var(--text-secondary);
    }

    .email-thread-item.active .participants-line {
        color: rgba(255, 255, 255, 0.82);
    }

    .mail-read-chip {
        font-size: 0.72rem;
        letter-spacing: 0.02em;
        border-radius: 999px;
    }

    .email-tab-unread-badge {
        display: none;
        margin-left: 0.45rem;
        min-width: 1.35rem;
        height: 1.35rem;
        padding: 0 0.38rem;
        border-radius: 999px;
        font-size: 0.72rem;
        font-weight: 700;
        line-height: 1.35rem;
        text-align: center;
        background: #2f9e44;
        color: #fff;
        box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.92);
    }

    .email-tab-unread-badge.is-warm {
        background: #f08c00;
    }

    .email-tab-unread-badge.is-hot {
        background: #c92a2a;
        animation: unreadPulse 1.6s ease-in-out infinite;
    }

    @keyframes unreadPulse {
        0% { transform: scale(1); }
        50% { transform: scale(1.09); }
        100% { transform: scale(1); }
    }

    [data-bs-theme="dark"] .email-column-shell {
        background: linear-gradient(180deg, rgba(19, 28, 38, 0.96), rgba(17, 24, 33, 0.96));
        border-color: rgba(117, 194, 239, 0.2);
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
    }

    [data-bs-theme="dark"] .email-column-shell .column-header {
        background: linear-gradient(90deg, rgba(117, 194, 239, 0.16), rgba(117, 194, 239, 0.05));
    }

    [data-bs-theme="dark"] .email-tab-unread-badge {
        box-shadow: 0 0 0 2px rgba(20, 28, 36, 0.95);
    }

    .case-tab-count-badge {
        display: none;
        margin-left: 0.42rem;
        min-width: 1.25rem;
        height: 1.25rem;
        padding: 0 0.35rem;
        border-radius: 999px;
        font-size: 0.7rem;
        font-weight: 700;
        line-height: 1.25rem;
        text-align: center;
        background: color-mix(in srgb, var(--accent) 82%, #2f9e44);
        color: #fff;
        box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.9);
    }

    .case-details-shell {
        background: transparent;
        border: 0;
        border-radius: 0;
        box-shadow: none;
    }

    #case-left-column > .row.g-4,
    #inner-center-col > .row.mb-3 {
        --bs-gutter-x: 0;
        --bs-gutter-y: 0;
        margin-left: 0 !important;
        margin-right: 0 !important;
    }

    #inner-left-col,
    #inner-center-col,
    #inner-center-col > .row.mb-3 > .col-12 {
        padding-left: 0 !important;
        padding-right: 0 !important;
    }

    #inner-center-col > .row.mb-3 > .col-12 {
        margin-top: 0 !important;
        margin-bottom: 0.75rem !important;
    }

    #inner-center-col .case-details-shell > .card-body {
        padding: 0 !important;
    }

    #beskrivelse-section {
        margin-top: 0 !important;
        padding-top: 0 !important;
        border-top: 0 !important;
    }

    [data-bs-theme="dark"] .case-tab-count-badge {
        box-shadow: 0 0 0 2px rgba(20, 28, 36, 0.95);
    }

    [data-bs-theme="dark"] .narrative-description {
        border-color: transparent;
        background: transparent;
        box-shadow: none;
    }

    [data-bs-theme="dark"] .case-left-section-title {
        color: #d4e8f8;
    }

    [data-bs-theme="dark"] .case-left-section-title i {
        color: #8fc3e8;
    }

    [data-bs-theme="dark"] .case-left-panel,
    [data-bs-theme="dark"] #beskrivelse-history-wrap {
        border-color: rgba(117, 194, 239, 0.28);
        background: linear-gradient(180deg, rgba(117, 194, 239, 0.08), rgba(17, 24, 33, 0.94));
    }

    [data-bs-theme="dark"] .comment-thread,
    [data-bs-theme="dark"] .comment-item,
    [data-bs-theme="dark"] .comment-quick-reply-box {
        border-color: rgba(117, 194, 239, 0.24);
        background: rgba(20, 30, 41, 0.86);
    }

    .card[data-module].module-empty-compact {
        height: auto !important;
        min-height: 0;
        --module-compact-min-height: 48px;
    }

    .card[data-module].module-empty-compact .card-body {
        display: none;
    }

    .card[data-module="buzzwords"].module-empty-compact .card-body {
        display: block;
    }

    .card[data-module].module-empty-compact .card-header,
    .card[data-module].module-empty-compact .module-header {
        margin-bottom: 0;
        padding-top: 0.45rem;
        padding-bottom: 0.45rem;
        min-height: var(--module-compact-min-height);
    }

    .card[data-module].module-empty-compact .card-title,
    .card[data-module].module-empty-compact h5,
    .card[data-module].module-empty-compact h6 {
        margin-bottom: 0;
        font-size: 0.95rem;
    }

    .card[data-module].module-empty-compact .btn {
        --bs-btn-padding-y: 0.2rem;
        --bs-btn-padding-x: 0.45rem;
    }

    .todo-section-header {
        padding: 0.28rem 0.55rem;
        font-size: 0.66rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.03em;
        background: rgba(15, 76, 117, 0.06);
        border-top: 1px solid rgba(15, 76, 117, 0.08);
        border-bottom: 1px solid rgba(15, 76, 117, 0.08);
    }

    #caseTabsContent .tab-pane {
        display: none !important;
        opacity: 1 !important;
        transition: none !important;
    }

    #caseTabsContent .tab-pane.active,
    #caseTabsContent .tab-pane.show.active {
        display: block !important;
        opacity: 1 !important;
        visibility: visible !important;
    }

    .todo-step-item {
        padding: 0.38rem 0.5rem;
    }

    .todo-step-header {
        display: flex;
        align-items: flex-start;
        gap: 0.5rem;
    }

    .todo-step-left {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        flex-wrap: wrap;
    }

    .todo-step-right {
        margin-left: auto;
        display: flex;
        align-items: center;
        gap: 0.4rem;
        flex-wrap: wrap;
        justify-content: flex-end;
        text-align: right;
    }

    .todo-step-title {
        font-weight: 600;
        margin-bottom: 0;
        font-size: 0.82rem;
        line-height: 1.2;
    }

    .todo-step-meta {
        display: flex;
        flex-wrap: wrap;
        gap: 0.2rem;
        margin-top: 0.2rem;
    }

    .todo-step-meta .meta-pill {
        display: inline-flex;
        align-items: center;
        padding: 0.08rem 0.34rem;
        border-radius: 999px;
        background: rgba(0,0,0,0.05);
        color: var(--text-secondary);
        font-size: 0.64rem;
    }

    .todo-step-actions {
        display: flex;
        gap: 0.25rem;
        margin-top: 0.3rem;
    }

    .todo-step-right .todo-step-actions {
        margin-top: 0;
    }

    .todo-info-btn {
        width: 18px;
        height: 18px;
        padding: 0;
        border-radius: 999px;
        font-size: 0.65rem;
        line-height: 1;
    }

    .todo-step-actions .btn {
        --bs-btn-padding-y: 0.1rem;
        --bs-btn-padding-x: 0.28rem;
        --bs-btn-font-size: 0.68rem;
        line-height: 1;
    }

    .relation-tree {
        list-style: none;
        margin: 0;
        padding-left: 0;
    }

    /* Sub-trees need indentation */
    .relation-children .relation-tree {
        margin-left: 8px; /* Indent children */
    }

    .relation-node {
        position: relative;
        padding-left: 24px; /* Space for the connector */
    }

    /* Vertical Line (Spine) */
    .relation-children {
        /* This container wraps the child <ul> */
        position: relative;
        margin-left: 8px; /* Align with parent connector start */
        border-left: 1px solid rgba(15, 76, 117, 0.2);
    }

    /* Horizontal Line (Connector) */
    .relation-node:before {
        content: "";
        position: absolute;
        left: 0;
        top: 1.1rem; /* Mid-height of the top row (approx 32px/2 + padding) */
        width: 20px;
        height: 1px;
        background: rgba(15, 76, 117, 0.2);
    }

    /* Fix: Last child should stop drawing the vertical line if we used ul border, 
       but here we use .relation-children border which covers all. 
       To get the "L" shape for the last child, we need the vertical line to come from the ITEM, not the LIST.
    */
    
    /* Reset simpler approach: Stifinder style */
    .relation-tree, .relation-children { border: none !important; margin: 0; padding: 0; }
    
    .relation-node {
        position: relative;
        padding-left: 24px;
    }

    /* Vertical line up to this node */
    .relation-node::before {
        content: '';
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        border-left: 1px solid rgba(15, 76, 117, 0.25);
    }
    
    /* Horizontal link */
    .relation-node::after {
        content: '';
        position: absolute;
        top: 18px; /* Half of row height approx */
        left: 0;
        width: 20px;
        height: 1px;
        border-top: 1px solid rgba(15, 76, 117, 0.25);
    }

    /* Remove vertical line for the last item, but keep the top half to form "L" */
    .relation-node:last-child::before {
        height: 18px; /* connectors height */
        bottom: auto;
    }

    /* Root node shouldn't have lines if it's top level? 
       Our macro recursively renders, so top level nodes are also .relation-node.
       We might need a wrapper. */
    .relation-tree > .relation-node:first-child::before,
    .relation-tree > .relation-node:first-child::after {
       /* If it's the absolute root, maybe no lines? depends on if we show multiple roots */
    }

    .relation-children {
        margin-left: 24px; /* Indent for next level */
    }


    .relation-node-card {
        background: rgba(15, 76, 117, 0.03);
        border: 1px solid rgba(15, 76, 117, 0.12);
        transition: background 0.2s;
    }
    
    .relation-node-card:hover {
        background: rgba(15, 76, 117, 0.08);
    }

    /* ── Relation row quick actions ────────────────────────────────────────── */
    .rel-row-actions {
        display: flex;
        align-items: center;
        gap: 0.2rem;
        margin-left: auto;
        padding-left: 0.35rem;
        flex-shrink: 0;
    }
    .rel-row-actions .btn-rel-action {
        padding: 2px 6px;
        line-height: 1;
        border: 1px solid transparent;
        background: transparent;
        color: var(--text-secondary, #6c757d);
        font-size: 0.8rem;
        opacity: 1;
        transition: background 0.15s, color 0.15s, border-color 0.15s;
        cursor: pointer;
        border-radius: 5px;
    }
    .btn-rel-action:hover,
    .btn-rel-action:focus,
    .btn-rel-action.active {
        background: rgba(15,76,117,0.1);
        border-color: rgba(15,76,117,0.2);
        color: var(--accent);
        outline: none;
    }
    .btn-rel-action:hover {
        opacity: 1 !important;
        background: rgba(15,76,117,0.1);
        color: var(--accent);
    }

    /* tag pills inside relation rows */
    .rel-tag-row {
        display: flex;
        flex-wrap: wrap;
        gap: 3px;
        padding: 2px 4px 3px 4px;
        min-height: 0;
    }
    .rel-tag-pill {
        display: inline-flex;
        align-items: center;
        gap: 3px;
        padding: 1px 7px;
        border-radius: 999px;
        background: rgba(15,76,117,0.09);
        border: 1px solid rgba(15,76,117,0.18);
        color: var(--accent);
        font-size: 0.68rem;
        font-weight: 600;
        line-height: 1.5;
        cursor: default;
    }
    .rel-tag-pill .rel-tag-del {
        cursor: pointer;
        opacity: 0.5;
        font-size: 0.7rem;
        transition: opacity .15s;
        padding: 0 1px;
    }
    .rel-tag-pill .rel-tag-del:hover { opacity: 1; color: #dc3545; }
    .rel-tag-overflow {
        font-size: 0.68rem;
        color: var(--text-secondary, #6c757d);
        cursor: default;
        align-self: center;
    }

    /* tag popover */
    .rel-tag-popover {
        position: absolute;
        z-index: 1080;
        background: var(--bg-card, #fff);
        border: 1px solid rgba(15,76,117,0.2);
        border-radius: 8px;
        box-shadow: 0 6px 24px rgba(0,0,0,0.12);
        min-width: 220px;
        max-width: 280px;
        padding: 0.5rem;
    }
    .rel-tag-popover input {
        font-size: 0.82rem;
    }
    .rel-tag-popover .rel-tag-suggestion {
        padding: 4px 8px;
        font-size: 0.82rem;
        border-radius: 5px;
        cursor: pointer;
        transition: background .12s;
    }
    .rel-tag-popover .rel-tag-suggestion:hover {
        background: rgba(15,76,117,0.09);
        color: var(--accent);
    }
    .rel-tag-popover .rel-tag-suggestion.new-tag {
        color: #198754;
        font-style: italic;
    }

    /* quick-action dropdown */
    .rel-qa-menu {
        position: absolute;
        z-index: 1080;
        background: var(--bg-card, #fff);
        border: 1px solid rgba(15,76,117,0.2);
        border-radius: 8px;
        box-shadow: 0 6px 24px rgba(0,0,0,0.12);
        min-width: 185px;
        padding: 0.35rem 0;
    }
    .rel-qa-menu .qa-item {
        display: flex;
        align-items: center;
        gap: 0.55rem;
        padding: 0.42rem 0.9rem;
        font-size: 0.84rem;
        cursor: pointer;
        transition: background .12s;
        border-radius: 5px;
        margin: 0 0.2rem;
    }
    .rel-qa-menu .qa-item:hover {
        background: rgba(15,76,117,0.09);
        color: var(--accent);
    }

    .relation-type-pill {
        display: inline-flex;
        align-items: center;
        gap: 0.3rem;
        font-size: 0.72rem;
        font-weight: 700;
        padding: 0.22rem 0.5rem;
        border-radius: 999px;
        border: 1px solid transparent;
        line-height: 1.2;
        white-space: nowrap;
    }

    .relation-type-pill.is-root {
        background: rgba(15, 76, 117, 0.12);
        color: #0f4c75;
        border-color: rgba(15, 76, 117, 0.25);
    }

    .relation-type-pill.is-related {
        background: rgba(100, 116, 139, 0.12);
        color: #334155;
        border-color: rgba(100, 116, 139, 0.25);
    }

    .relation-type-pill.is-derived {
        background: rgba(59, 130, 246, 0.12);
        color: #1d4ed8;
        border-color: rgba(59, 130, 246, 0.25);
    }

    .relation-type-pill.is-cause {
        background: rgba(16, 185, 129, 0.13);
        color: #047857;
        border-color: rgba(16, 185, 129, 0.3);
    }

    .relation-type-pill.is-block {
        background: rgba(239, 68, 68, 0.12);
        color: #b91c1c;
        border-color: rgba(239, 68, 68, 0.3);
    }

    .relation-type-subtext {
        font-size: 0.68rem;
        color: var(--text-secondary, #6b7280);
        margin-top: 0.2rem;
    }

    .right-modules-grid {
        display: grid;
        grid-template-columns: 1fr;
        gap: 0.75rem;
    }

    #beskrivelse-section {
        gap: 0.75rem;
    }

    .module-priority-low {
        --module-accent: #64748b;
    }

    .module-priority-normal {
        --module-accent: #0f4c75;
    }

    .module-priority-high {
        --module-accent: #d97706;
    }

    .module-priority-critical {
        --module-accent: #dc2626;
    }

    .right-module-card {
        border: 1px solid rgba(15, 76, 117, 0.14);
        border-left: 4px solid var(--module-accent, var(--accent));
        border-radius: 12px;
        overflow: hidden;
        background: linear-gradient(165deg, color-mix(in srgb, var(--module-accent, var(--accent)) 6%, var(--bg-card)) 0%, var(--bg-card) 100%);
        box-shadow: 0 4px 14px rgba(15, 76, 117, 0.08);
    }

    .left-module-card {
        border: 1px solid rgba(15, 76, 117, 0.14);
        border-left: 4px solid var(--module-accent, var(--accent));
        border-radius: 12px;
        overflow: hidden;
        background: linear-gradient(165deg, color-mix(in srgb, var(--module-accent, var(--accent)) 6%, var(--bg-card)) 0%, var(--bg-card) 100%);
        box-shadow: 0 4px 14px rgba(15, 76, 117, 0.08);
    }

    .right-module-card .card-header,
    .left-module-card .card-header {
        border-bottom: 1px solid color-mix(in srgb, var(--module-accent, var(--accent)) 22%, #d1d5db);
        background: color-mix(in srgb, var(--module-accent, var(--accent)) 7%, var(--bg-card));
        padding: 0.35rem 0.6rem;
        min-height: 0;
    }

    .right-module-card > .card-body,
    .left-module-card > .card-body {
        padding: 0.4rem !important;
    }

    #beskrivelse-section .left-module-card + .left-module-card {
        margin-top: 0.75rem;
    }

    .module-title {
        display: inline-flex;
        align-items: center;
        gap: 0.35rem;
        margin: 0;
        font-size: 0.82rem;
        font-weight: 700;
        line-height: 1.2;
        color: var(--text-primary);
    }

    .module-icon {
        color: var(--module-accent, var(--accent));
        font-size: 0.9rem;
        flex-shrink: 0;
    }

    .right-modules-grid .card-header {
        padding: 0.35rem 0.6rem;
    }

    .right-modules-grid .card-header h6 {
        font-size: 0.82rem;
    }

    .right-modules-grid .card-body {
        padding: 0.4rem;
    }

    .contact-list-header,
    .contact-row {
        display: grid;
        grid-template-columns: 1.2fr 0.9fr 1fr auto;
        gap: 0.5rem;
        align-items: center;
    }

    .contact-list-header {
        font-size: 0.7rem;
        text-transform: uppercase;
        letter-spacing: 0.03em;
        color: #6c757d;
        padding: 0 0.25rem 0.25rem;
        border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    }

    .contact-row {
        padding: 0.35rem 0.25rem;
        border-bottom: 1px solid rgba(0, 0, 0, 0.06);
        cursor: pointer;
    }

    .contact-row:last-child {
        border-bottom: none;
    }

    .contact-row .contact-name {
        font-weight: 600;
    }

    .contact-row small {
        color: #6c757d;
    }

    .hardware-list-header,
    .hardware-row,
    .location-list-header,
    .location-row,
    .customer-list-header,
    .customer-row {
        display: grid;
        align-items: center;
        gap: 0.5rem;
    }

    .hardware-list-header,
    .location-list-header,
    .customer-list-header {
        font-size: 0.7rem;
        text-transform: uppercase;
        letter-spacing: 0.03em;
        color: #6c757d;
        padding: 0 0.25rem 0.25rem;
        border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    }

    .hardware-row,
    .location-row,
    .customer-row {
        padding: 0.35rem 0.25rem;
        border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    }

    .hardware-row:last-child,
    .location-row:last-child,
    .customer-row:last-child {
        border-bottom: none;
    }

    .hardware-list-header,
    .hardware-row {
        grid-template-columns: minmax(0, 1.5fr) minmax(110px, 1fr) 56px 56px;
    }

    .hardware-list-header span:nth-child(3),
    .hardware-list-header span:nth-child(4),
    .hardware-row > *:nth-child(3),
    .hardware-row > *:nth-child(4) {
        justify-self: end;
    }

    .hardware-row > div:first-child {
        min-width: 0;
    }

    .hardware-row > div:first-child a {
        display: inline-block;
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .hardware-row small {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .location-list-header,
    .location-row {
        grid-template-columns: 1.3fr 1fr auto;
    }

    .customer-list-header,
    .customer-row {
        grid-template-columns: 1.2fr 0.9fr 1fr auto;
    }

    .tag-toggle-btn {
        background: none;
        border: 1px solid rgba(0,0,0,0.2);
        padding: 0.2rem 0.5rem;
        border-radius: 4px;
        cursor: pointer;
        font-size: 0.75rem;
        margin-left: 0.5rem;
        transition: all 0.2s;
    }

    .tag-toggle-btn:hover {
        background: rgba(0,0,0,0.05);
    }

    .tag-toggle-open {
        color: #28a745;
        border-color: #28a745;
    }

    .tag-toggle-open:hover {
        background: #28a745;
        color: white;
    }

    .tag-toggle-closed {
        color: #6c757d;
        border-color: #6c757d;
    }

    .tag-toggle-closed:hover {
        background: #6c757d;
        color: white;
    }

    .case-tabs-topbar {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: 0.7rem;
        align-items: start;
        background: transparent;
        border: 1px solid rgba(0,0,0,0.08);
        border-radius: 0;
        padding: 0.55rem 0.45rem;
        margin-bottom: 0.75rem;
        width: 100%;
        min-width: 0;
        overflow-x: auto;
    }

    .case-tabs-topbar.topbar-primary {
        grid-template-columns: minmax(86px, 0.55fr) minmax(220px, 1.7fr) repeat(6, minmax(120px, 1fr));
        background: #0f4c75;
        border: 1px solid #0b3a59;
        border-radius: 0;
        box-shadow: none;
        margin-bottom: 1rem;
    }

    .topbar-primary .case-tabs-topbar-item {
        background: transparent;
        border: none;
        border-left: 1px solid rgba(255,255,255,0.24);
        border-radius: 0;
        padding: 0.45rem 0.7rem;
    }

    .topbar-primary .case-tabs-topbar-item:first-child {
        border-left: none;
    }

    .topbar-primary .case-tabs-topbar-label {
        color: rgba(255,255,255,0.88);
        opacity: 1;
        font-size: 0.72rem;
        letter-spacing: 0.1em;
    }

    .topbar-primary .case-tabs-topbar-value {
        font-size: 1.12rem;
        font-weight: 750;
        color: #ffffff;
    }

    .topbar-primary .field-case-id .case-tabs-topbar-value {
        font-size: 0.96rem;
        font-weight: 700;
        letter-spacing: 0.01em;
    }

    .topbar-primary .field-case-id {
        padding-right: 0.45rem;
    }

    .topbar-company-row {
        display: inline-flex;
        align-items: center;
        gap: 0.42rem;
        max-width: 100%;
    }

    .topbar-company-name {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .topbar-primary .topbar-company-name {
        color: #ffffff !important;
        font-size: 1.18rem;
        font-weight: 800;
        line-height: 1.15;
        letter-spacing: 0.01em;
        text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
    }

    .topbar-company-contact {
        margin-top: 0.22rem;
        font-size: 0.8rem;
        line-height: 1.2;
        color: rgba(255,255,255,0.88);
        opacity: 1;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .topbar-company-contact i {
        margin-right: 0.25rem;
    }

    .topbar-company-edit-btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 1.5rem;
        height: 1.5rem;
        padding: 0;
        border-radius: 999px;
        border: 1px solid rgba(15,76,117,0.35);
        background: #0d6efd;
        color: #ffffff;
        box-shadow: 0 1px 4px rgba(13,110,253,0.25);
    }

    .topbar-company-edit-btn:hover,
    .topbar-company-edit-btn:focus-visible {
        background: #0b5ed7;
        border-color: rgba(11,94,215,0.85);
        color: #ffffff;
    }

    .topbar-primary .case-inline-select {
        background: rgba(255,255,255,0.14);
        border-color: rgba(255,255,255,0.36);
        box-shadow: none;
        border-radius: 4px;
        font-weight: 700;
        color: #ffffff;
    }

    .topbar-primary .topbar-next-meta {
        margin-top: 0.12rem;
        font-size: 0.78rem;
        color: rgba(255,255,255,0.8);
        opacity: 1;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .topbar-primary .topbar-secondary-action {
        border-color: rgba(255,255,255,0.36);
        background: rgba(255,255,255,0.12);
        color: #ffffff;
        font-size: 0.88rem;
    }

    .topbar-primary .topbar-secondary-action:hover,
    .topbar-primary .topbar-secondary-action:focus-visible {
        background: rgba(255,255,255,0.22);
        color: #ffffff;
    }

    .topbar-primary .case-tabs-topbar-label i,
    .topbar-primary .topbar-next-meta i,
    .topbar-primary .case-tabs-topbar-value i {
        color: rgba(255,255,255,0.9);
    }

    .back-link {
        display: inline-flex;
        align-items: center;
        gap: 0.5rem;
        font-weight: 700;
        font-size: 0.84rem;
        letter-spacing: 0.01em;
        color: var(--text-primary);
        text-decoration: none;
        padding: 0.38rem 0.1rem;
        min-height: 38px;
        border-radius: 0;
        border: none;
        background: transparent;
        box-shadow: none;
        transition: transform 0.14s ease, box-shadow 0.14s ease, filter 0.14s ease;
    }

    .back-link:hover {
        color: var(--accent);
        background: transparent;
        text-decoration: none;
    }

    .back-link:focus-visible {
        outline: 3px solid color-mix(in srgb, var(--accent) 42%, #9dd3ff);
        outline-offset: 2px;
    }

    [data-bs-theme="dark"] .back-link {
        color: #dce8f4;
        background: transparent;
        border: none;
    }

    [data-bs-theme="dark"] .back-link:hover {
        color: #9fc4e8;
        background: transparent;
    }

    [data-bs-theme="dark"] .case-tabs-topbar.topbar-primary {
        background: #0f4c75;
        border-color: #75a7cc;
    }

    [data-bs-theme="dark"] .topbar-primary .case-tabs-topbar-item {
        border-left-color: rgba(255,255,255,0.28);
    }

    [data-bs-theme="dark"] .topbar-primary .case-tabs-topbar-label,
    [data-bs-theme="dark"] .topbar-primary .case-tabs-topbar-value {
        color: #ffffff;
    }

    [data-bs-theme="dark"] .topbar-primary .case-inline-select {
        background: rgba(255,255,255,0.14);
        border-color: rgba(255,255,255,0.4);
        color: #ffffff;
    }

    .card[data-module] {
        border-width: 2px !important;
        border-color: rgba(15, 76, 117, 0.28) !important;
        box-shadow: 0 4px 12px rgba(15, 76, 117, 0.10);
    }

    #caseTabsContent .tab-pane:not(#details) .card,
    #caseTabsContent .tab-pane:not(#details) .history-timeline-shell {
        --module-accent: var(--accent);
        border: 2px solid rgba(15, 76, 117, 0.28) !important;
        border-left: 2px solid rgba(15, 76, 117, 0.28) !important;
        border-radius: 12px !important;
        box-shadow: 0 4px 12px rgba(15, 76, 117, 0.10) !important;
        background: linear-gradient(165deg, color-mix(in srgb, var(--module-accent, var(--accent)) 6%, var(--bg-card)) 0%, var(--bg-card) 100%);
        overflow: hidden;
    }

    #caseTabsContent .tab-pane:not(#details) .card .card-header,
    #caseTabsContent .tab-pane:not(#details) .history-timeline-toolbar {
        border-bottom: 1px solid color-mix(in srgb, var(--module-accent, var(--accent)) 22%, #d1d5db);
        background: color-mix(in srgb, var(--module-accent, var(--accent)) 7%, var(--bg-card));
    }

    .left-module-card,
    .right-module-card {
        border: 2px solid rgba(15, 76, 117, 0.28) !important;
        border-left: 2px solid rgba(15, 76, 117, 0.28) !important;
        border-radius: 12px !important;
        box-shadow: 0 4px 12px rgba(15, 76, 117, 0.10) !important;
    }

    [data-bs-theme="dark"] .card[data-module] {
        border-color: rgba(117, 167, 204, 0.45) !important;
        box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
    }

    [data-bs-theme="dark"] #caseTabsContent .tab-pane:not(#details) .card,
    [data-bs-theme="dark"] #caseTabsContent .tab-pane:not(#details) .history-timeline-shell {
        border: 2px solid rgba(117, 167, 204, 0.45) !important;
        border-left: 2px solid rgba(117, 167, 204, 0.45) !important;
        box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28) !important;
        background: linear-gradient(165deg, color-mix(in srgb, var(--module-accent, #69a6d5) 12%, rgba(18, 28, 40, 0.94)) 0%, rgba(18, 28, 40, 0.94) 100%);
    }

    [data-bs-theme="dark"] #caseTabsContent .tab-pane:not(#details) .card .card-header,
    [data-bs-theme="dark"] #caseTabsContent .tab-pane:not(#details) .history-timeline-toolbar {
        border-bottom-color: color-mix(in srgb, var(--module-accent, #69a6d5) 45%, #4b5563);
        background: color-mix(in srgb, var(--module-accent, #69a6d5) 18%, rgba(18, 28, 40, 0.98));
    }

    [data-bs-theme="dark"] .left-module-card,
    [data-bs-theme="dark"] .right-module-card {
        border: 2px solid rgba(117, 167, 204, 0.45) !important;
        border-left: 2px solid rgba(117, 167, 204, 0.45) !important;
        box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28) !important;
    }

    [data-bs-theme="dark"] .topbar-company-edit-btn {
        border-color: rgba(170,205,245,0.5);
        box-shadow: 0 1px 6px rgba(75,145,255,0.35);
    }

    [data-bs-theme="dark"] .topbar-company-contact {
        color: #b8d9f1;
    }

    [data-bs-theme="dark"] .topbar-primary .topbar-company-name {
        color: #ffffff !important;
        text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
    }

    [data-bs-theme="dark"] .right-module-card {
        border-color: rgba(140, 182, 219, 0.25);
        box-shadow: 0 4px 16px rgba(5, 22, 40, 0.45);
        background: linear-gradient(165deg, color-mix(in srgb, var(--module-accent, #69a6d5) 12%, rgba(18, 28, 40, 0.94)) 0%, rgba(18, 28, 40, 0.94) 100%);
    }

    [data-bs-theme="dark"] .left-module-card {
        border-color: rgba(140, 182, 219, 0.25);
        box-shadow: 0 4px 16px rgba(5, 22, 40, 0.45);
        background: linear-gradient(165deg, color-mix(in srgb, var(--module-accent, #69a6d5) 12%, rgba(18, 28, 40, 0.94)) 0%, rgba(18, 28, 40, 0.94) 100%);
    }

    [data-bs-theme="dark"] .right-module-card .card-header,
    [data-bs-theme="dark"] .left-module-card .card-header {
        border-bottom-color: color-mix(in srgb, var(--module-accent, #69a6d5) 45%, #4b5563);
        background: color-mix(in srgb, var(--module-accent, #69a6d5) 18%, rgba(18, 28, 40, 0.98));
    }

    [data-bs-theme="dark"] .case-details-shell {
        border-color: transparent;
        box-shadow: none;
        background: transparent;
    }

    [data-bs-theme="dark"] .module-title {
        color: #e5edf5;
    }

    .case-tabs-topbar.topbar-secondary {
        /* Vægt kolonner så dato-felter (som har indlejrede ikoner) får mere plads */
        grid-template-columns: 
            minmax(105px, 0.75fr) /* Oprettet */
            minmax(180px, 1.2fr)  /* Arbejdsstart (2 knapper) */
            minmax(180px, 1.2fr)  /* Start senest (2 knapper) */
            minmax(150px, 1.1fr)  /* Deadline (1 knap) */
            minmax(120px, 0.85fr) /* AnyDesk */
            minmax(140px, 1fr)    /* Dokumenter */;
        align-items: stretch;
        background: linear-gradient(180deg, rgba(15, 76, 117, 0.10), rgba(15, 76, 117, 0.04));
        border: 1px solid rgba(15, 76, 117, 0.30);
        border-radius: 10px;
        padding: 0.42rem 0.5rem;
    }

    .case-tabs-topbar.topbar-secondary .case-tabs-topbar-item {
        display: flex;
        flex-direction: column;
        justify-content: flex-start;
        height: 100%;
        background: rgba(255, 255, 255, 0.82);
        border: 1px solid rgba(15, 76, 117, 0.24);
        border-left: 1px solid rgba(15, 76, 117, 0.24);
        border-radius: 8px;
    }

    .case-tabs-topbar.topbar-secondary .case-tabs-topbar-item:first-child {
        border-left: 1px solid rgba(15, 76, 117, 0.24);
    }

    .case-tabs-topbar.topbar-secondary .case-tabs-topbar-label {
        color: #1c425c;
        opacity: 1;
    }

    .case-tabs-topbar.topbar-secondary .case-tabs-topbar-value {
        color: #0f2f45;
        font-weight: 700;
    }

    .case-tabs-topbar.topbar-secondary .case-inline-select {
        background: #ffffff;
        border: 1px solid rgba(15, 76, 117, 0.34);
        color: #0f2f45;
        font-weight: 700;
    }

    .case-tabs-topbar.topbar-secondary .topbar-secondary-action {
        border-color: rgba(15, 76, 117, 0.34);
        background: #ffffff;
        color: #0f2f45;
    }

    .case-tabs-topbar.topbar-secondary .topbar-secondary-action:hover,
    .case-tabs-topbar.topbar-secondary .topbar-secondary-action:focus-visible {
        background: rgba(15, 76, 117, 0.12);
        border-color: rgba(15, 76, 117, 0.55);
        color: #0b2535;
    }

    .case-tabs-topbar-item {
        background: transparent;
        border: none;
        border-left: 1px solid rgba(15,76,117,0.16);
        border-radius: 0;
        padding: 0.58rem 0.68rem;
        min-width: 0;
        transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
    }

    .case-tabs-topbar-item:first-child {
        border-left: none;
    }

    .case-tabs-topbar-item:hover {
        border-color: rgba(15, 76, 117, 0.28);
        box-shadow: none;
    }

    .case-tabs-topbar-label {
        font-size: 0.62rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        color: var(--text-secondary);
        opacity: 0.95;
        margin-bottom: 0.2rem;
        display: flex;
        align-items: center;
        gap: 0.25rem;
    }

    .case-tabs-topbar-label .field-importance-bubble {
        margin-left: auto;
    }

    .field-importance-bubble {
        width: 0.78rem;
        height: 0.78rem;
        border-radius: 999px;
        flex: 0 0 auto;
        border: 1px solid rgba(0,0,0,0.18);
        background: rgba(148, 163, 184, 0.45);
        box-shadow: 0 0 0 1px rgba(255,255,255,0.65), 0 0 0 0.5px rgba(0,0,0,0.12) inset;
    }

    .field-importance-bubble.sev-neutral {
        background: rgba(148, 163, 184, 0.55);
        border-color: rgba(100, 116, 139, 0.55);
    }

    .field-importance-bubble.sev-ok {
        background: #22c55e;
        border-color: #15803d;
    }

    .field-importance-bubble.sev-warn {
        background: #f59e0b;
        border-color: #b45309;
    }

    .field-importance-bubble.sev-critical {
        background: #ef4444;
        border-color: #991b1b;
    }

    [data-bs-theme="dark"] .field-importance-bubble {
        box-shadow: 0 0 0 1px rgba(10, 17, 26, 0.55);
    }

    .case-tabs-topbar-value {
        font-size: 0.9rem;
        font-weight: 600;
        color: var(--text-primary);
        line-height: 1.25;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .case-tabs-topbar-value.multiline {
        white-space: normal;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    .case-tabs-topbar .case-inline-select {
        width: 100%;
        min-width: 0;
        max-width: none;
        font-size: 0.86rem;
        padding: 0.45rem 0.7rem;
        min-height: 38px;
        border-radius: 0;
        box-shadow: none;
    }

    .case-top-aux {
        flex: 1 1 auto;
        min-width: 0;
        width: 100%;
    }

    .case-top-aux .case-tabs-topbar {
        background: transparent;
        border: none;
        padding: 0;
        margin-bottom: 0;
    }

    .case-hero {
        display: none;
    }

    .topbar-secondary-action {
        border: 1px solid rgba(0,0,0,0.12);
        background: rgba(255,255,255,0.72);
        color: var(--text-primary);
        border-radius: 0;
        font-size: 0.8rem;
        font-weight: 600;
        padding: 0.45rem 0.7rem;
        min-height: 38px;
        text-align: left;
        display: inline-flex;
        align-items: center;
        justify-content: flex-start;
        gap: 0.3rem;
        line-height: 1.1;
    }

    .topbar-secondary-action.is-wide {
        width: 100%;
    }

    .topbar-secondary-action.is-icon {
        width: auto;
        min-width: 38px;
        flex: 0 0 38px;
        justify-content: center;
        padding: 0.45rem 0.5rem;
    }

    .case-tabs-topbar .dropdown-menu {
        z-index: 1080;
    }

    .topbar-secondary-inline {
        display: flex;
        align-items: center;
        flex-wrap: nowrap;
        gap: 0.45rem;
        width: 100%;
        min-width: 0;
    }

    .topbar-secondary-inline > * {
        min-width: 0;
    }

    .topbar-secondary-inline .case-inline-select[type="date"] {
        flex: 1 1 auto;
        min-width: 0;
        max-width: none;
        font-variant-numeric: tabular-nums;
        text-align: left;
    }


    .topbar-deferred-current {
        margin-top: 0.4rem;
        padding: 0.3rem 0.45rem;
        border-radius: 8px;
        font-size: 0.72rem;
        line-height: 1.25;
        color: var(--text-secondary);
        background: rgba(255, 255, 255, 0.52);
        border: 1px dashed rgba(0, 0, 0, 0.12);
        display: flex;
        align-items: center;
        gap: 0.28rem;
    }

    .topbar-deferred-current.is-set {
        color: #0f4c75;
        border-style: solid;
        border-color: rgba(15, 76, 117, 0.28);
        background: rgba(15, 76, 117, 0.09);
    }



    .topbar-secondary-action:hover {
        border-color: var(--accent);
        color: var(--accent);
        background: rgba(255,255,255,0.95);
    }

    [data-bs-theme="dark"] .topbar-deferred-current {
        color: rgba(236, 242, 255, 0.82);
        background: rgba(255, 255, 255, 0.06);
        border-color: rgba(255, 255, 255, 0.16);
    }

    [data-bs-theme="dark"] .topbar-deferred-current.is-set {
        color: #9dd7ff;
        border-color: rgba(108, 188, 255, 0.42);
        background: rgba(19, 100, 154, 0.24);
    }

    [data-bs-theme="dark"] .topbar-secondary-action {
        background: rgba(20, 27, 38, 0.72);
        border-color: rgba(170, 190, 216, 0.35);
        color: #dce8f4;
    }

    [data-bs-theme="dark"] .topbar-secondary-action:hover {
        border-color: #9fc4e8;
        color: #9fc4e8;
    }

    [data-bs-theme="dark"] .topbar-secondary-action.is-icon {
        background: rgba(20, 27, 38, 0.78);
    }

    [data-bs-theme="dark"] .case-tabs-topbar.topbar-secondary {
        background: linear-gradient(180deg, rgba(117, 194, 239, 0.18), rgba(117, 194, 239, 0.08));
        border-color: rgba(117, 194, 239, 0.36);
    }

    [data-bs-theme="dark"] .case-tabs-topbar.topbar-secondary .case-tabs-topbar-item {
        background: rgba(15, 24, 34, 0.9);
        border-color: rgba(117, 194, 239, 0.32);
    }

    [data-bs-theme="dark"] .case-tabs-topbar.topbar-secondary .case-tabs-topbar-label {
        color: #cfe6f7;
    }

    [data-bs-theme="dark"] .case-tabs-topbar.topbar-secondary .case-tabs-topbar-value {
        color: #f2f8fe;
    }

    [data-bs-theme="dark"] .case-tabs-topbar.topbar-secondary .case-inline-select,
    [data-bs-theme="dark"] .case-tabs-topbar.topbar-secondary .topbar-secondary-action {
        background: rgba(19, 30, 42, 0.92);
        border-color: rgba(117, 194, 239, 0.38);
        color: #eef6fd;
    }



    .case-add-side-backdrop {
        position: fixed;
        inset: 0;
        background: transparent;
        z-index: 1060;
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.2s ease;
    }

    .case-add-side-backdrop.open {
        opacity: 0;
        pointer-events: none;
    }

    .case-add-side-panel {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        width: min(460px, 92vw);
        background: var(--bg-card, #ffffff);
        border-right: 1px solid rgba(15, 76, 117, 0.16);
        box-shadow: 8px 0 28px rgba(5, 16, 30, 0.2);
        z-index: 1061;
        transform: translateX(-105%);
        transition: transform 0.22s ease;
        display: flex;
        flex-direction: column;
    }

    .case-add-side-panel.open {
        transform: translateX(0);
    }

    .case-add-side-reopen {
        position: fixed;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
        z-index: 1063;
        border: 1px solid #c97700;
        border-left: 0;
        border-radius: 0 8px 8px 0;
        background: #f59e0b;
        color: #ffffff;
        font-size: 0.78rem;
        font-weight: 700;
        padding: 0.42rem 0.55rem;
        display: inline-flex;
        align-items: center;
        gap: 0.25rem;
    }

    .case-add-side-reopen.show {
        display: inline-flex;
        align-items: center;
        gap: 0.25rem;
    }

    .case-add-side-header {
        padding: 0.8rem 0.95rem;
        border-bottom: 1px solid rgba(15, 76, 117, 0.14);
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 0.75rem;
    }

    .case-add-side-title {
        font-size: 0.95rem;
        font-weight: 700;
        color: var(--text-primary);
        margin: 0;
        display: flex;
        align-items: center;
        gap: 0.45rem;
    }

    .case-add-side-body {
        padding: 0.85rem;
        display: flex;
        flex-direction: column;
        gap: 0.7rem;
        height: 100%;
        min-height: 0;
    }

    .case-add-module-list {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.45rem;
    }

    .case-add-module-item {
        display: flex;
        align-items: center;
        gap: 0.4rem;
    }

    .case-add-module-btn {
        flex: 1 1 auto;
        border: 1px solid rgba(0, 0, 0, 0.12);
        border-radius: 8px;
        background: #f8fbff;
        color: var(--text-primary);
        font-size: 0.8rem;
        font-weight: 600;
        padding: 0.4rem 0.5rem;
        text-align: left;
    }

    .case-add-module-btn.active {
        border-color: var(--accent);
        background: color-mix(in srgb, var(--accent) 14%, white);
        color: var(--accent);
    }

    .case-add-module-toggle {
        width: 1rem;
        height: 1rem;
        margin: 0;
        cursor: pointer;
        accent-color: var(--accent);
    }

    .case-add-workspace {
        border: 1px solid rgba(15, 76, 117, 0.14);
        border-radius: 10px;
        padding: 0.8rem;
        background: #fbfdff;
        overflow-y: auto;
        flex: 1 1 auto;
        min-height: 0;
    }

    .case-add-workspace .section-title {
        font-size: 0.86rem;
        font-weight: 700;
        margin-bottom: 0.55rem;
        color: var(--text-primary);
    }

    .case-add-workspace .list-group-item {
        border-radius: 6px;
        margin-bottom: 0.3rem;
        border: 1px solid rgba(0, 0, 0, 0.06);
    }

    [data-bs-theme="dark"] .case-add-side-panel {
        background: #0f1723;
        border-right-color: rgba(166, 200, 235, 0.25);
        box-shadow: 10px 0 30px rgba(0, 0, 0, 0.5);
    }

    [data-bs-theme="dark"] .case-add-side-header {
        border-bottom-color: rgba(166, 200, 235, 0.2);
    }

    [data-bs-theme="dark"] .case-add-module-btn {
        background: rgba(18, 34, 53, 0.85);
        border-color: rgba(170, 190, 216, 0.25);
        color: #d8e5f3;
    }

    [data-bs-theme="dark"] .case-add-module-btn.active {
        background: rgba(44, 107, 162, 0.3);
        border-color: #8ec1ee;
        color: #b7d8f4;
    }

    [data-bs-theme="dark"] .case-add-module-toggle {
        accent-color: #8ec1ee;
    }

    [data-bs-theme="dark"] .case-add-workspace {
        background: rgba(13, 24, 38, 0.9);
        border-color: rgba(166, 200, 235, 0.2);
    }

    [data-bs-theme="dark"] .case-add-side-reopen {
        background: #f59e0b;
        color: #1f1300;
        border-color: #ffbf4d;
    }

    @media (max-width: 1200px) {
        .case-tabs-topbar {
            grid-template-columns: repeat(2, minmax(0, 1fr));
        }

        .case-tabs-topbar.topbar-secondary {
            grid-template-columns: repeat(3, minmax(0, 1fr));
        }

        .topbar-primary .case-tabs-topbar-item {
            border-left: none;
            border-top: 1px solid rgba(15,76,117,0.2);
        }

        .topbar-primary .case-tabs-topbar-item:nth-child(-n+2) {
            border-top: none;
        }
    }

    @media (max-width: 768px) {
        .case-tabs-topbar {
            grid-template-columns: 1fr;
        }

        .case-tabs-topbar.topbar-secondary {
            grid-template-columns: 1fr;
        }
    }

    .case-detail-page-shell {
        --case-topbar-offset: 0px;
        margin-top: calc(3rem + var(--case-topbar-offset));
        margin-bottom: 2rem;
        position: relative;
    }

    @media (max-width: 992px) {
        .case-detail-page-shell {
            margin-top: calc(2.2rem + var(--case-topbar-offset));
        }
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid case-detail-page-shell">

    <div class="case-tabs-topbar topbar-primary" role="region" aria-label="Primær sagsbar">
        <div class="case-tabs-topbar-item field-case-id">
            <div class="case-tabs-topbar-label"><i class="bi bi-hash"></i>SagsID</div>
            <div class="case-tabs-topbar-value">#{{ case.id }}</div>
        </div>
        <div class="case-tabs-topbar-item">
            <div class="case-tabs-topbar-label"><i class="bi bi-building"></i>Firma</div>
            <div>
                <div class="case-tabs-topbar-value topbar-company-row">
                    <span class="topbar-company-name">{{ customer.name if customer else 'Ingen kunde' }}</span>
                    <button type="button" class="topbar-company-edit-btn" onclick="showCustomerSearch('replace')" title="Skift kunde/firma">
                        <i class="bi bi-pencil"></i>
                    </button>
                </div>
                <div class="topbar-company-contact">
                    <i class="bi bi-person"></i>Hoved kontakt: {{ (hovedkontakt.first_name ~ ' ' ~ hovedkontakt.last_name) if hovedkontakt else 'Ingen kontakt' }}
                </div>
            </div>
        </div>
        <div class="case-tabs-topbar-item field-status-item">
            <div class="case-tabs-topbar-label"><i class="bi bi-circle-half"></i>Status <span class="field-importance-bubble {{ 'sev-ok' if (case.status or '')|lower in ['lukket', 'løst', 'closed', 'resolved'] else 'sev-warn' }}" data-field-bubble="status" aria-hidden="true"></span></div>
            <select id="topbarStatusSelect" class="case-inline-select" onchange="saveCaseStatusFromTopbar()">
                {% for st in status_options %}
                <option value="{{ st }}" {% if (case.status or '')|lower == st|lower %}selected{% endif %}>{{ st|capitalize }}</option>
                {% endfor %}
            </select>
        </div>
        <div class="case-tabs-topbar-item field-type">
            <div class="case-tabs-topbar-label"><i class="bi bi-tag"></i>Type <span class="field-importance-bubble sev-ok" data-field-bubble="type" aria-hidden="true"></span></div>
            <select id="topbarTypeSelect" class="case-inline-select" onchange="saveCaseTypeFromTopbar()">
                {% set topbar_type = (case.template_key or case.type or 'ticket')|lower %}
                <option value="ticket" {% if topbar_type == 'ticket' %}selected{% endif %}>Ticket</option>
                <option value="pipeline" {% if topbar_type == 'pipeline' %}selected{% endif %}>Pipeline</option>
                <option value="opgave" {% if topbar_type == 'opgave' %}selected{% endif %}>Opgave</option>
                <option value="ordre" {% if topbar_type == 'ordre' %}selected{% endif %}>Ordre</option>
                <option value="projekt" {% if topbar_type == 'projekt' %}selected{% endif %}>Projekt</option>
                <option value="service" {% if topbar_type == 'service' %}selected{% endif %}>Service</option>
            </select>
        </div>
        <div class="case-tabs-topbar-item field-priority">
            <div class="case-tabs-topbar-label"><i class="bi bi-flag"></i>Prioritet <span class="field-importance-bubble {{ 'sev-critical' if (case.priority or 'normal')|lower == 'urgent' else ('sev-warn' if (case.priority or 'normal')|lower == 'high' else 'sev-ok') }}" data-field-bubble="priority" aria-hidden="true"></span></div>
            <select id="topbarPrioritySelect" class="case-inline-select" onchange="saveCasePriorityFromTopbar()">
                {% set topbar_priority = (case.priority or 'normal')|lower %}
                <option value="low" {% if topbar_priority == 'low' %}selected{% endif %}>Lav</option>
                <option value="normal" {% if topbar_priority == 'normal' %}selected{% endif %}>Normal</option>
                <option value="high" {% if topbar_priority == 'high' %}selected{% endif %}>Hoj</option>
                <option value="urgent" {% if topbar_priority == 'urgent' %}selected{% endif %}>Akut</option>
            </select>
        </div>
        <div class="case-tabs-topbar-item field-assignee-item">
            <div class="case-tabs-topbar-label"><i class="bi bi-person-check"></i>Ansvarlig <span class="field-importance-bubble {{ 'sev-ok' if case.ansvarlig_bruger_id else 'sev-critical' }}" data-field-bubble="assignee" aria-hidden="true"></span></div>
            <select id="tabsAssignmentUserSelect" class="case-inline-select" onchange="saveAssignmentFromTabsBar()">
                <option value="">Ingen bruger</option>
                {% for user in assignment_users or [] %}
                <option value="{{ user.user_id }}" {% if case.ansvarlig_bruger_id == user.user_id %}selected{% endif %}>{{ user.display_name }}</option>
                {% endfor %}
            </select>
        </div>
        <div class="case-tabs-topbar-item field-group-item">
            <div class="case-tabs-topbar-label"><i class="bi bi-people"></i>Gruppe <span class="field-importance-bubble {{ 'sev-ok' if case.assigned_group_id else 'sev-warn' }}" data-field-bubble="group" aria-hidden="true"></span></div>
            <select id="tabsAssignmentGroupSelect" class="case-inline-select" onchange="saveAssignmentFromTabsBar()">
                <option value="">Ingen gruppe</option>
                {% for group in assignment_groups or [] %}
                <option value="{{ group.id }}" {% if case.assigned_group_id == group.id %}selected{% endif %}>{{ group.name }}</option>
                {% endfor %}
            </select>
        </div>
        <div class="case-tabs-topbar-item field-next-item">
            <div class="case-tabs-topbar-label"><i class="bi bi-list-check"></i>Næste <span class="field-importance-bubble sev-warn" data-field-bubble="next" aria-hidden="true"></span></div>
            <div id="topbarNextTodoValue" class="case-tabs-topbar-value multiline">Henter næste todo...</div>
            <div id="topbarNextTodoMeta" class="topbar-next-meta">-</div>
        </div>
    </div>

    <!-- Top Bar: Secondary Bar -->
    <div class="mb-2">
        <div class="case-top-aux">
            <div class="case-tabs-topbar topbar-secondary" role="region" aria-label="Sekundær sagsbar">
                <div class="case-tabs-topbar-item field-created">
                    <div class="case-tabs-topbar-label"><i class="bi bi-plus-circle"></i>Oprettelses dato <span class="field-importance-bubble sev-ok" data-field-bubble="created" aria-hidden="true"></span></div>
                    <div class="case-tabs-topbar-value">{{ case.created_at.strftime('%d/%m/%Y') if case.created_at else '-' }}</div>
                </div>
                <div class="case-tabs-topbar-item field-start">
                    <div class="case-tabs-topbar-label"><i class="bi bi-play-circle"></i>Arbejdsstart <span class="field-importance-bubble {{ 'sev-ok' if case.start_date else 'sev-warn' }}" data-field-bubble="start" aria-hidden="true"></span></div>
                    <div class="topbar-secondary-inline" style="gap: 0.25rem;">
                        <input
                            id="topbarStartDateInput"
                            type="date"
                            class="case-inline-select"
                            value="{{ case.start_date.strftime('%Y-%m-%d') if case.start_date else '' }}"
                            onchange="saveCaseStartDateFromTopbar()"
                            style="padding-left: 0.35rem; padding-right: 0.1rem;"
                        >
                        <div class="dropdown">
                            <button class="topbar-secondary-action is-icon" style="padding: 0.35rem 0.2rem; min-width: 32px; flex: 0 0 32px;" type="button" data-bs-toggle="dropdown" aria-expanded="false" title="Menu">
                                <i class="bi bi-three-dots-vertical"></i>
                            </button>
                            <ul class="dropdown-menu dropdown-menu-end shadow-sm" style="font-size: 0.85rem;">
                                <li><a class="dropdown-item text-danger" href="#" onclick="event.preventDefault(); clearCaseStartDateFromTopbar();"><i class="bi bi-x-circle me-2"></i>Ryd dato</a></li>
                                <li><hr class="dropdown-divider"></li>
                                <li><h6 class="dropdown-header">Udskyd til...</h6></li>
                                <li><a class="dropdown-item" href="#" onclick="event.preventDefault(); setStartDateAndSave(0);"><i class="bi bi-calendar-event me-2 text-muted"></i>I dag</a></li>
                                <li><a class="dropdown-item" href="#" onclick="event.preventDefault(); setStartDateAndSave(1);"><i class="bi bi-calendar-plus me-2 text-muted"></i>I morgen (+1 dag)</a></li>
                                <li><a class="dropdown-item" href="#" onclick="event.preventDefault(); setStartDateAndSave(7);"><i class="bi bi-calendar-week me-2 text-muted"></i>Næste uge (+1 uge)</a></li>
                                <li><hr class="dropdown-divider"></li>
                                <li><a class="dropdown-item" href="#" onclick="event.preventDefault(); openStartDateModal();"><i class="bi bi-gear me-2 text-muted"></i>Flere valg...</a></li>
                                <li><a class="dropdown-item" href="#" onclick="event.preventDefault(); openDeferredModal();"><i class="bi bi-lightning-charge me-2 text-muted"></i>Sæt afhængighed (Trigger)...</a></li>
                            </ul>
                        </div>
                    </div>
                </div>
                <div class="case-tabs-topbar-item field-start-before">
                    <div class="case-tabs-topbar-label"><i class="bi bi-hourglass-split"></i>Start senest <span class="field-importance-bubble {{ 'sev-warn' if case.deferred_until else 'sev-neutral' }}" data-field-bubble="start_before" aria-hidden="true"></span></div>
                    <div class="topbar-secondary-inline" style="gap: 0.25rem;">
                        <input
                            id="topbarDeferredInput"
                            type="date"
                            class="case-inline-select"
                            value="{{ case.deferred_until.strftime('%Y-%m-%d') if case.deferred_until else '' }}"
                            onchange="updateDeferredUntil(this.value || null)"
                            style="padding-left: 0.35rem; padding-right: 0.1rem;"
                        >
                        <div class="dropdown">
                            <button class="topbar-secondary-action is-icon" style="padding: 0.35rem 0.2rem; min-width: 32px; flex: 0 0 32px;" type="button" data-bs-toggle="dropdown" aria-expanded="false" title="Menu">
                                <i class="bi bi-three-dots-vertical"></i>
                            </button>
                            <ul class="dropdown-menu dropdown-menu-end shadow-sm" style="font-size: 0.85rem;">
                                <li><a class="dropdown-item text-danger" href="#" onclick="event.preventDefault(); updateDeferredUntil(null); document.getElementById('topbarDeferredInput').value='';"><i class="bi bi-x-circle me-2"></i>Ryd dato</a></li>
                                <li><hr class="dropdown-divider"></li>
                                <li><h6 class="dropdown-header">Venter på sag...</h6></li>
                                <li><a class="dropdown-item" href="#" onclick="event.preventDefault(); openDeferredModalWithPresetStatus('lukket');"><i class="bi bi-check2-circle me-2 text-success"></i>Trigger: Sag Lukket</a></li>
                                <li><a class="dropdown-item" href="#" onclick="event.preventDefault(); openDeferredModalWithPresetStatus('løst');"><i class="bi bi-check-lg me-2 text-primary"></i>Trigger: Sag Løst</a></li>
                            </ul>
                        </div>
                    </div>
                    {% set deferred_case_ns = namespace(title='') %}
                    {% if case.deferred_until_case_id %}
                        {% for rc in related_case_options %}
                            {% if rc.id == case.deferred_until_case_id %}
                                {% set deferred_case_ns.title = rc.titel %}
                            {% endif %}
                        {% endfor %}
                    {% endif %}
                    <div class="topbar-deferred-current {% if case.deferred_until_case_id and case.deferred_until_status %}is-set{% endif %}" id="topbarDeferredStatusIndicator">
                        {% if case.deferred_until_case_id and case.deferred_until_status %}
                            <i class="bi bi-link-45deg"></i>
                            <span>
                                Trigger: #{{ case.deferred_until_case_id }}{% if deferred_case_ns.title %} {{ deferred_case_ns.title }}{% endif %} → {{ (case.deferred_until_status or '')|replace('__any_change__', 'Statusskifte') }}
                            </span>
                        {% else %}
                            <i class="bi bi-dot"></i>
                            <span>Ingen status-trigger valgt</span>
                        {% endif %}
                    </div>
                </div>
                <div class="case-tabs-topbar-item field-deadline">
                    <div class="case-tabs-topbar-label"><i class="bi bi-clock"></i>Deadline dato <span class="field-importance-bubble {{ 'sev-warn' if case.deadline else 'sev-neutral' }}" data-field-bubble="deadline" aria-hidden="true"></span></div>
                    <div class="topbar-secondary-inline" style="gap: 0.25rem;">
                        <input
                            id="topbarDeadlineInput"
                            type="date"
                            class="case-inline-select"
                            value="{{ case.deadline.strftime('%Y-%m-%d') if case.deadline else '' }}"
                            onchange="updateDeadline(this.value || null)"
                            style="padding-left: 0.35rem; padding-right: 0.1rem;"
                        >
                        <button type="button" class="topbar-secondary-action is-icon" style="padding: 0.35rem 0.2rem; min-width: 32px; flex: 0 0 32px;" onclick="updateDeadline(null); document.getElementById('topbarDeadlineInput').value=''" title="Fjern deadline"><i class="bi bi-x-lg"></i></button>
                    </div>
                </div>
                <div class="case-tabs-topbar-item field-anydesk">
                    <div class="case-tabs-topbar-label"><i class="bi bi-display"></i>AnyDesk</div>
                    <button id="caseAnyDeskOpenBtn" type="button" class="topbar-secondary-action is-wide" onclick="openCaseAnyDeskModal()" title="Start AnyDesk quick connect for denne sag">
                        <i class="bi bi-plug"></i> Quick connect
                    </button>
                </div>
                <div class="case-tabs-topbar-item field-documents">
                    <div class="case-tabs-topbar-label"><i class="bi bi-printer"></i>Arbejdsdokumenter</div>
                    <div class="d-flex gap-2 flex-wrap">
                        <button type="button" class="topbar-secondary-action is-wide" onclick="openCaseWorkOrderPrint()" title="Print arbejdsseddel">
                            <i class="bi bi-file-earmark-text"></i> Print arbejdsseddel
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    {% set tkey = (case.template_key or case.type or 'ticket')|lower %}
    {% set type_icons = {'ticket': 'bi-ticket-perforated', 'pipeline': 'bi-graph-up-arrow', 'opgave': 'bi-puzzle', 'ordre': 'bi-receipt', 'projekt': 'bi-folder2-open', 'service': 'bi-tools'} %}
    {% set type_labels = {'ticket': 'Ticket', 'pipeline': 'Pipeline', 'opgave': 'Opgave', 'ordre': 'Ordre', 'projekt': 'Projekt', 'service': 'Service'} %}
    {% set type_colors = {'ticket': '#6366f1', 'pipeline': '#0ea5e9', 'opgave': '#f59e0b', 'ordre': '#10b981', 'projekt': '#8b5cf6', 'service': '#ef4444'} %}
    {% set tcolor = type_colors.get(tkey, '#0f4c75') %}
    {% set ticon = type_icons.get(tkey, 'bi-card-text') %}
    {% set tlabel = type_labels.get(tkey, tkey|capitalize) %}

    <div id="caseCustomerTopAlerts" class="mb-3 d-none"></div>

    <!-- ═══════════════ PREMIUM CASE HEADER ═══════════════ -->
    <div class="case-hero mb-4">

        <!-- ── Row 1: Identity stripe ── -->
        <div class="case-hero-identity">

            <!-- Left cluster: ID + status -->
            <div class="d-flex align-items-center gap-2 flex-wrap">
                <span class="case-id-chip" style="--tcolor:{{ tcolor }};">#{{ case.id }}</span>

                <span class="case-status-chip {{ 'open' if case.status == 'åben' else 'closed' }}">
                    <span class="case-status-dot"></span>{{ case.status|capitalize }}
                </span>
            </div>

            <!-- Right cluster: dates -->
            <div class="d-flex align-items-center gap-3">
                <button type="button" class="btn btn-sm btn-primary" onclick="showCustomerSearch('replace')" title="Skift kunde eller firma på sagen">
                    <i class="bi bi-building-gear me-1"></i>Skift kunde/firma
                </button>
                <span class="case-date-item">
                    <i class="bi bi-plus-circle"></i>
                    <span>{{ case.created_at.strftime('%d. %b %Y') if case.created_at else '—' }}</span>
                </span>
                <span class="case-date-sep">·</span>
                <span class="case-date-item">
                    <i class="bi bi-arrow-repeat"></i>
                    <span>{{ case.updated_at.strftime('%d. %b %Y') if case.updated_at else '—' }}</span>
                </span>
            </div>
        </div>

        <!-- ── Row 2: Meta fields ── -->
        <div class="case-hero-meta">

            <!-- Kunde -->
            <div class="case-meta-cell">
                <div class="case-meta-label"><i class="bi bi-building"></i>Kunde</div>
                {% if customer %}
                <div class="d-flex align-items-center gap-2 flex-wrap">
                    <a href="/customers/{{ customer.id }}" class="case-meta-value case-meta-link" style="color:{{ tcolor }}; font-size:1.0rem; font-weight:700;">{{ customer.name }}</a>
                    <button type="button" class="btn btn-sm btn-outline-primary" onclick="showCustomerSearch('replace')" title="Skift primær kunde på sagen">
                        <i class="bi bi-arrow-left-right me-1"></i>Skift kunde
                    </button>
                </div>
                {% else %}
                <div class="d-flex align-items-center gap-2 flex-wrap">
                    <span class="case-meta-value text-muted fst-italic">Ingen</span>
                    <button type="button" class="btn btn-sm btn-outline-primary" onclick="showCustomerSearch('replace')" title="Vælg kunde til sagen">
                        <i class="bi bi-plus-lg me-1"></i>Vælg kunde
                    </button>
                </div>
                {% endif %}
            </div>

            <div class="case-meta-divider"></div>

            <!-- Kontakt -->
            <div class="case-meta-cell" onclick="showKontaktModal()" style="cursor:pointer;" title="Se kontaktinfo">
                <div class="case-meta-label"><i class="bi bi-person"></i>Kontakt</div>
                {% if hovedkontakt %}
                <span class="case-meta-value case-meta-link">{{ hovedkontakt.first_name ~ ' ' ~ hovedkontakt.last_name }}</span>
                {% else %}
                <span class="case-meta-value text-muted fst-italic">Ingen</span>
                {% endif %}
            </div>

            <div class="case-meta-divider"></div>

            <!-- Afdeling -->
            <div class="case-meta-cell" onclick="showAfdelingModal()" style="cursor:pointer;" title="Ændre afdeling">
                <div class="case-meta-label"><i class="bi bi-diagram-3"></i>Afdeling</div>
                <span class="case-meta-value case-meta-link">{{ customer.department if customer and customer.department else '—' }}</span>
            </div>

            <div class="case-meta-divider"></div>

            <!-- Type -->
            <div class="case-meta-cell">
                <div class="case-meta-label"><i class="bi bi-tag"></i>Type</div>
                <div class="dropdown mt-1" id="caseTypeDropdownWrap">
                    <button class="case-type-chip border-0 dropdown-toggle" id="caseTypeDropdownBtn"
                            style="--tcolor:{{ tcolor }};cursor:pointer;"
                            data-bs-toggle="dropdown" aria-expanded="false" title="Skift type">
                        <i class="bi {{ ticon }}" id="caseTypeIcon"></i><span id="caseTypeLabel">{{ tlabel }}</span>
                    </button>
                    <ul class="dropdown-menu dropdown-menu-end shadow-sm" style="min-width:170px;">
                        <li><h6 class="dropdown-header" style="font-size:.7rem;">Skift sagstype</h6></li>
                        {% for tval, tlbl, tico, tclr in [
                            ('ticket',  'Ticket',   'bi-ticket-perforated', '#6366f1'),
                            ('pipeline','Pipeline', 'bi-graph-up-arrow',    '#0ea5e9'),
                            ('opgave',  'Opgave',   'bi-puzzle',            '#f59e0b'),
                            ('ordre',   'Ordre',    'bi-receipt',           '#10b981'),
                            ('projekt', 'Projekt',  'bi-folder2-open',      '#8b5cf6'),
                            ('service', 'Service',  'bi-tools',             '#ef4444')
                        ] %}
                        <li>
                            <button class="dropdown-item d-flex align-items-center gap-2 {% if tkey == tval %}fw-semibold{% endif %}"
                                    onclick='saveCaseType({{ tval|tojson }}, {{ tlbl|tojson }}, {{ tico|tojson }}, {{ tclr|tojson }})'
                                    style="font-size:.875rem;">
                                <i class="bi {{ tico }}" style="color:{{ tclr }};"></i>{{ tlbl }}
                                {% if tkey == tval %}<i class="bi bi-check ms-auto"></i>{% endif %}
                            </button>
                        </li>
                        {% endfor %}
                    </ul>
                </div>
            </div>

            <div class="case-meta-divider"></div>

            <!-- Ansvarlig -->
            <div class="case-meta-cell" style="flex:0 0 auto;">
                <div class="case-meta-label"><i class="bi bi-person-check"></i>Ansvarlig</div>
                <div class="d-flex gap-2 flex-wrap mt-1">
                    <select id="assignmentUserSelect" class="case-inline-select" onchange="saveAssignment()">
                        <option value="">Ingen bruger</option>
                        {% for user in assignment_users or [] %}
                        <option value="{{ user.user_id }}" {% if case.ansvarlig_bruger_id == user.user_id %}selected{% endif %}>{{ user.display_name }}</option>
                        {% endfor %}
                    </select>
                    <select id="assignmentGroupSelect" class="case-inline-select" onchange="saveAssignment()">
                        <option value="">Ingen gruppe</option>
                        {% for group in assignment_groups or [] %}
                        <option value="{{ group.id }}" {% if case.assigned_group_id == group.id %}selected{% endif %}>{{ group.name }}</option>
                        {% endfor %}
                    </select>
                </div>
            </div>

            <div class="case-meta-divider"></div>

            <!-- Deadline -->
            <div class="case-meta-cell">
                <div class="case-meta-label"><i class="bi bi-clock"></i>Deadline</div>
                <div class="d-flex align-items-center gap-1 mt-1">
                    {% if case.deadline %}
                        <span class="case-date-badge {{ 'overdue' if is_deadline_overdue else '' }}">
                            <i class="bi {{ 'bi-exclamation-circle-fill' if is_deadline_overdue else 'bi-calendar-check' }}"></i>
                            {{ case.deadline.strftime('%d/%m/%Y') }}
                        </span>
                    {% else %}
                        <span class="case-meta-empty">Ingen deadline</span>
                    {% endif %}
                    <button class="case-edit-btn" onclick="openDeadlineModal()" title="Rediger"><i class="bi bi-pencil-square"></i></button>
                </div>
            </div>

            <div class="case-meta-divider"></div>

            <!-- Udsat til -->
            <div class="case-meta-cell">
                <div class="case-meta-label"><i class="bi bi-calendar-event"></i>Udsat til</div>
                <div class="d-flex align-items-center gap-1 mt-1">
                    {% if case.deferred_until %}
                        <span class="case-date-badge deferred">
                            <i class="bi bi-hourglass-split"></i>
                            {{ case.deferred_until.strftime('%d/%m/%Y') }}
                        </span>
                    {% else %}
                        <span class="case-meta-empty">Ikke udsat</span>
                    {% endif %}
                    <button class="case-edit-btn" onclick="openDeferredModal()" title="Rediger"><i class="bi bi-pencil-square"></i></button>
                </div>
            </div>

        </div>
    </div>
    <!-- ═══════════════ END CASE HEADER ═══════════════ -->

    <script>
        // Defensive bootstrap: keep core tab/module globals available even if a later
        // inline script fails to parse due template edge-cases.
        var caseTypeModuleDefaults = window.caseTypeModuleDefaults || {};
        window.caseTypeModuleDefaults = caseTypeModuleDefaults;
        window.caseTypeKey = window.caseTypeKey || {{ ((case.template_key or case.type or 'ticket')|lower)|tojson }};

        window.syncCaseTabPaneVisibility = window.syncCaseTabPaneVisibility || function(activeTabId) {
            if (!activeTabId) return;
            const tabContent = document.getElementById('caseTabsContent');
            if (!tabContent) return;
            const paneIds = Array.from(document.querySelectorAll('#caseTabs [data-bs-target^="#"]'))
                .map((btn) => (btn.getAttribute('data-bs-target') || '').replace('#', ''))
                .filter(Boolean);
            if (!paneIds.length) return;

            paneIds.forEach((paneId) => {
                const pane = document.getElementById(paneId);
                if (pane && pane.parentElement !== tabContent) {
                    tabContent.appendChild(pane);
                }
            });

            paneIds.forEach((paneId) => {
                const pane = document.getElementById(paneId);
                if (!pane) return;
                const isActive = pane.id === activeTabId;
                pane.classList.toggle('active', isActive);
                pane.classList.toggle('show', isActive);
                pane.classList.remove('d-none');
                pane.style.display = isActive ? 'block' : 'none';
                pane.style.opacity = '1';
                pane.style.visibility = isActive ? 'visible' : 'hidden';
                pane.hidden = !isActive;
            });

            const tabButtons = document.querySelectorAll('#caseTabs [data-bs-target]');
            tabButtons.forEach((btn) => {
                const isActive = btn.getAttribute('data-bs-target') === `#${activeTabId}`;
                btn.classList.toggle('active', isActive);
                btn.setAttribute('aria-selected', isActive ? 'true' : 'false');
                btn.tabIndex = isActive ? 0 : -1;
            });
        };

        window.forceCaseTabActivation = window.forceCaseTabActivation || function(tabId) {
            if (!tabId) return;
            const trigger = document.querySelector(`#caseTabs [data-bs-target="#${tabId}"]`);
            if (!trigger) return;
            window.syncCaseTabPaneVisibility(tabId);
            trigger.dispatchEvent(new Event('shown.bs.tab', { bubbles: true }));
            if (typeof window.loadCaseTabData === 'function') window.loadCaseTabData(tabId);
        };

        window.activateCaseTabFromButton = window.activateCaseTabFromButton || function(event, tabId) {
            if (event) {
                event.preventDefault();
                event.stopPropagation();
            }
            window.forceCaseTabActivation(tabId);
            return false;
        };
    </script>

    <!-- Tabs Navigation -->
    <ul class="nav nav-tabs mb-4" id="caseTabs" role="tablist">
        <li class="nav-item" role="presentation">
            <button class="nav-link active" id="details-tab" data-bs-target="#details" type="button" role="tab" onclick="return activateCaseTabFromButton(event, 'details')">
                <i class="bi bi-card-text me-2"></i>Sagsdetaljer
                <span class="case-tab-count-badge" id="detailsTabCountBadge"></span>
            </button>
        </li>
        <li class="nav-item" role="presentation">
            <button class="nav-link" id="solution-tab" data-bs-target="#solution" type="button" role="tab" data-module-tab="solution" onclick="return activateCaseTabFromButton(event, 'solution')">
                <i class="bi bi-lightbulb me-2"></i>Løsning
                <span class="case-tab-count-badge" id="solutionTabCountBadge"></span>
                {% if solution %}
                <span class="badge bg-success ms-1 rounded-pill"><i class="bi bi-check"></i></span>
                {% endif %}
            </button>
        </li>
        <li class="nav-item" role="presentation">
            <button class="nav-link" id="emails-tab" data-bs-target="#emails" type="button" role="tab" data-module-tab="emails" onclick="return activateCaseTabFromButton(event, 'emails')">
                <i class="bi bi-envelope me-2"></i>E-mail
                <span class="case-tab-count-badge" id="emailsTabCountBadge"></span>
                <span id="emailTabUnreadBadge" class="email-tab-unread-badge" aria-label="Ulæste emails"></span>
            </button>
        </li>
        <li class="nav-item" role="presentation">
            <button class="nav-link" id="sales-tab" data-bs-target="#sales" type="button" role="tab" data-module-tab="sales" onclick="return activateCaseTabFromButton(event, 'sales')">
                <i class="bi bi-basket3 me-2"></i>Varekøb & Salg
                <span class="case-tab-count-badge" id="salesTabCountBadge"></span>
            </button>
        </li>
        <li class="nav-item" role="presentation">
            <button class="nav-link" id="supplier-tab" data-bs-target="#supplier" type="button" role="tab" data-module-tab="supplier" onclick="return activateCaseTabFromButton(event, 'supplier')">
                <i class="bi bi-receipt-cutoff me-2"></i>Leverandør
                <span class="case-tab-count-badge" id="supplierTabCountBadge"></span>
            </button>
        </li>
        <li class="nav-item" role="presentation">
            <button class="nav-link" id="timetracking-tab" data-bs-target="#timetracking" type="button" role="tab" onclick="return activateCaseTabFromButton(event, 'timetracking')">
                <i class="bi bi-clock-history me-2"></i>Tidsforbrug
                <span class="case-tab-count-badge" id="timetrackingTabCountBadge"></span>
            </button>
        </li>
        <li class="nav-item" role="presentation">
            <button class="nav-link" id="subscription-tab" data-bs-target="#subscription" type="button" role="tab" data-module-tab="subscription" onclick="return activateCaseTabFromButton(event, 'subscription')">
                <i class="bi bi-repeat me-2"></i>Abonnement
                <span class="case-tab-count-badge" id="subscriptionTabCountBadge"></span>
            </button>
        </li>
        <li class="nav-item" role="presentation">
            <button class="nav-link" id="reminders-tab" data-bs-target="#reminders" type="button" role="tab" data-module-tab="reminders" onclick="return activateCaseTabFromButton(event, 'reminders')">
                <i class="bi bi-bell me-2"></i>Påmindelser
                <span class="case-tab-count-badge" id="remindersTabCountBadge"></span>
            </button>
        </li>
    </ul>

    <div class="tab-content" id="caseTabsContent">
        <!-- Tab: Sagsdetaljer (Existing Content) -->
        <div class="tab-pane fade show active" id="details" role="tabpanel" tabindex="0" style="display:block;">
        <div class="row g-4">
        <div class="col-xl-8 col-lg-8" id="case-left-column">
<div class="row g-4">
<!-- TREDELT-1: Relations, History, etc. -->
<div class="col-12" id="inner-left-col">
</div>
<!-- TREDELT-2: Hero, Info -->
<div class="col-12" id="inner-center-col">




    <!-- ROW 1: Main Info -->
    <div class="row mb-3">
        <!-- MAIN HERO CARD: Titel & Beskrivelse -->
        <div class="col-12 mb-3 mt-1">
            <div class="case-details-shell">
                <div class="card-body p-3 position-relative">
                    <div class="d-flex justify-content-between align-items-start mb-1 d-none">
                        <div class="w-100 pe-3">
                            <!-- Title view -->
                            <div id="sag-titel-view" class="d-flex align-items-center gap-2">
                                <h2 id="sag-titel-text" class="mb-2 fw-bolder" style="color: var(--accent); font-size: 1.8rem; letter-spacing: -0.5px;">{{ case.titel }}</h2>
                                <button class="btn btn-sm btn-link text-muted p-0 mb-1" onclick="startTitelEdit()" title="Rediger overskrift"><i class="bi bi-pencil-square"></i></button>
                                <button class="btn btn-sm btn-link text-info p-0 mb-1 ms-2" onclick="openManualHelp('Sag')" title="Hjælp til sagsbehandling"><i class="bi bi-question-circle fs-5"></i></button>
                            </div>
                            <!-- Title edit -->
                            <div id="sag-titel-editor" class="d-none">
                                <input id="sag-titel-input" type="text" class="form-control form-control-lg fw-bold" value="{{ case.titel }}" style="font-size:1.5rem;color:var(--accent);" />
                                <div class="d-flex gap-2 mt-2">
                                    <button class="btn btn-sm btn-outline-secondary" onclick="cancelTitelEdit()"><i class="bi bi-x me-1"></i>Annuller</button>
                                    <button id="sag-titel-save-btn" class="btn btn-sm btn-primary" onclick="saveTitelEdit()"><i class="bi bi-check2 me-1"></i>Gem</button>
                                </div>
                            </div>
                        </div>

                    </div>

                    <div class="pt-2" id="beskrivelse-section">
                        <div class="card left-module-card module-priority-normal">
                            <div class="card-header d-flex justify-content-between align-items-center">
                                <h6 class="module-title"><i class="bi bi-card-text module-icon"></i>{{ case.titel }}</h6>
                                <button class="btn btn-sm btn-link text-info p-0" onclick="openManualHelp('Sag')" title="Hjælp til sagsbehandling"><i class="bi bi-question-circle"></i></button>
                            </div>
                            <div class="card-body">
                                <!-- View mode -->
                                <div id="beskrivelse-view" class="narrative-description" style="min-height: 120px; cursor: pointer;" ondblclick="startBeskrivelsEdit()">
                                    <div id="beskrivelse-text" class="prose" style="white-space: pre-wrap;">{{ case.beskrivelse or '' }}</div>
                                    {% if not case.beskrivelse %}
                                    <div id="beskrivelse-empty" class="text-center p-3">
                                        <p class="text-muted fst-italic mb-2">Ingen opgavebeskrivelse tilføjet endnu.</p>
                                        <span class="text-muted small"><i class="bi bi-pencil me-1"></i>Dobbeltklik for at tilføje</span>
                                    </div>
                                    {% endif %}
                                </div>

                                <!-- Edit mode (hidden by default) -->
                                <div id="beskrivelse-editor" class="d-none mt-1">
                                    <textarea id="beskrivelse-textarea" class="form-control"
                                              rows="8" style="font-size: 1rem; line-height: 1.7; resize: vertical; min-height: 150px;"></textarea>
                                    <div class="d-flex justify-content-between align-items-center mt-2">
                                        <span class="text-muted small"><i class="bi bi-keyboard me-1"></i>Ctrl+Enter for at gemme · Esc for at annullere</span>
                                        <div class="d-flex gap-2">
                                            <button class="btn btn-sm btn-outline-secondary" onclick="cancelBeskrivelsEdit()">
                                                <i class="bi bi-x me-1"></i>Annuller
                                            </button>
                                            <button id="beskrivelse-rewrite-btn" type="button" class="btn btn-sm btn-outline-primary" onclick="rewriteCaseDescriptionWithApproval()">
                                                <i class="bi bi-magic me-1"></i>Renskriv med AI
                                            </button>
                                            <button id="beskrivelse-save-btn" class="btn btn-sm btn-primary" onclick="saveBeskrivelsEdit()">
                                                <i class="bi bi-check2 me-1"></i>Gem
                                            </button>
                                        </div>
                                    </div>
                                </div>

                                <!-- History accordion -->
                                <div id="beskrivelse-history-wrap" class="mt-3 d-none">
                                    <button class="btn btn-link btn-sm p-0 text-muted text-decoration-none"
                                            type="button" data-bs-toggle="collapse" data-bs-target="#beskrivelse-history-collapse"
                                            onclick="loadBeskrivelsHistory()">
                                        <i class="bi bi-clock-history me-1"></i><span id="beskrivelse-history-label">Historik</span>
                                    </button>
                                    <div class="collapse mt-2" id="beskrivelse-history-collapse">
                                        <div id="beskrivelse-history-list" class="list-group list-group-flush small border rounded">
                                            <div class="list-group-item text-muted text-center py-3">
                                                <span class="spinner-border spinner-border-sm me-1"></span> Indlæser...
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <div class="card left-module-card module-priority-low">
                            <div class="card-header d-flex justify-content-between align-items-center">
                                <h6 class="module-title"><i class="bi bi-chat-left-text module-icon"></i>Kommentarer</h6>
                                <span id="commentsTotalCountBadge" class="badge bg-secondary">{{ comments|length if comments else 0 }}</span>
                            </div>
                            <div class="card-body">
                                <div id="beskrivelse-comments-wrap">

                                    <div class="comment-thread" id="comments-container">
                                        {% if comments %}
                                            {% for comment in comments %}
                                            {% if comment.er_system_besked or comment.forfatter == 'System' %}
                                            <div class="comment-item comment-system" data-created-at="{{ comment.created_at.timestamp() if comment.created_at else 0 }}">
                                            {% elif comment.er_intern %}
                                            <div class="comment-item comment-internal" data-created-at="{{ comment.created_at.timestamp() if comment.created_at else 0 }}">
                                            {% else %}
                                            <div class="comment-item comment-external" data-created-at="{{ comment.created_at.timestamp() if comment.created_at else 0 }}">
                                            {% endif %}
                                                <div class="comment-meta">
                                                    <span class="comment-avatar">{{ (comment.forfatter or 'Bruger')[:2]|upper }}</span>
                                                    <b>{{ comment.forfatter }}</b>
                                                    <span class="comment-time">{{ comment.created_at.strftime('%d/%m-%Y %H:%M') }}</span>
                                                </div>
                                                <div class="comment-body" data-comment-raw="{{ comment.indhold|e }}">{{ comment.indhold|replace('\n', '<br>')|safe }}</div>
                                            </div>
                                            {% endfor %}
                                        {% else %}
                                        <p class="text-center text-muted my-3">Ingen kommentarer endnu.</p>
                                        {% endif %}
                                    </div>

                                    <div id="comment-quick-reply-host"></div>

                                    <div class="mt-3">
                                        <form id="comment-form" onsubmit="submitComment(event)">
                                            <div class="comment-composer">
                                                <textarea class="form-control" name="indhold" required placeholder="Skriv en kommentar..." rows="2" style="resize: none;"></textarea>
                                                <button type="submit" class="btn btn-primary d-flex align-items-center justify-content-center comment-send">
                                                    <i class="bi bi-send me-1"></i>Send
                                                </button>
                                            </div>
                                        </form>
                                    </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        </div>
    </div>
    </div>
    </div>
    
    <!-- ROW 1B: Pipeline -->
    

    <!-- ROW 2: Relations -->
    

    <!-- ROW: Call History -->
    

    <script>
        let caseCurrentUserId = null;

        async function ensureCaseCurrentUserId() {
            if (caseCurrentUserId !== null) return caseCurrentUserId;
            try {
                const res = await fetch('/api/v1/auth/me', { credentials: 'include' });
                if (!res.ok) return null;
                const me = await res.json();
                caseCurrentUserId = Number(me?.id) || null;
                return caseCurrentUserId;
            } catch (e) {
                return null;
            }
        }

        async function logCaseSystemComment(message) {
            try {
                await fetch('/api/v1/sag/{{ case.id }}/kommentarer', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    credentials: 'include',
                    body: JSON.stringify({
                        forfatter: 'System',
                        indhold: message,
                        er_system_besked: true
                    })
                });
            } catch (e) {
                console.warn('Kunne ikke logge systemkommentar', e);
            }
        }

        if (!window.__caseSmsCommentListenerBound) {
            window.__caseSmsCommentListenerBound = true;
            window.addEventListener('bmc:sms-sent', async (event) => {
                try {
                    const detail = event?.detail || {};
                    const to = String(detail.to || '').trim();
                    const text = String(detail.message || '').replace(/\s+/g, ' ').trim();
                    if (!to || !text) return;

                    const preview = text.length > 220 ? `${text.slice(0, 217)}...` : text;
                    await logCaseSystemComment(`💬 SMS sendt til ${to}: ${preview}`);
                } catch (err) {
                    console.warn('Kunne ikke logge sendt SMS i kommentarer', err);
                }
            });
        }

        async function ringOutFromCase(number, opts = {}) {
            const clean = String(number || '').trim();
            if (!clean || clean === '-') {
                if (!opts.silent) alert('Intet gyldigt nummer at ringe til');
                return false;
            }

            const userId = await ensureCaseCurrentUserId();
            try {
                const res = await fetch('/api/v1/telefoni/click-to-call', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    credentials: 'include',
                    body: JSON.stringify({ number: clean, user_id: userId })
                });

                if (!res.ok) {
                    const t = await res.text();
                    if (!opts.silent) alert('Ring ud fejlede: ' + t);
                    return false;
                }

                if (opts.logToCase) {
                    const who = opts.contactName ? `${opts.contactName} (${clean})` : clean;
                    await logCaseSystemComment(`📞 Opkald startet til ${who}`);
                }

                if (!opts.silent) alert('Ringer ud via Yealink...');
                return true;
            } catch (e) {
                if (!opts.silent) alert('Kunne ikke starte opkald');
                return false;
            }
        }
    </script>


    <!-- Relationer (center) -->
<div class="row mb-3">
        <div class="col-12 mb-3">
            <div class="card h-100 d-flex flex-column right-module-card module-priority-normal" data-module="relations" data-has-content="{{ 'true' if relation_tree else 'false' }}">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <div class="d-flex align-items-center gap-2">
                        <h6 class="module-title"><i class="bi bi-diagram-3-fill module-icon"></i>Relationer</h6>
                        <i class="bi bi-info-circle text-muted"
                           style="font-size:0.9rem; cursor:help;"
                           data-bs-toggle="tooltip"
                           data-bs-html="true"
                           data-bs-placement="right"
                           title="<strong>Hvad betyder relationstyper?</strong><br><br><strong>Relateret til</strong>: Faglig kobling uden direkte afhængighed.<br><strong>Afledt af</strong>: Denne sag er opstået på baggrund af en anden sag.<br><strong>Årsag til</strong>: Denne sag er årsagen til en anden sag.<br><strong>Blokkerer</strong>: Arbejde i en sag stopper fremdrift i den anden."></i>
                    </div>
                    <div class="d-flex gap-2">
                        <button class="btn btn-sm btn-outline-primary" onclick="showRelationModal()">
                            <i class="bi bi-link-45deg"></i>
                        </button>
                        <button class="btn btn-sm btn-outline-primary" onclick="showCreateRelatedModal()">
                            <i class="bi bi-plus-lg"></i>
                        </button>
                    </div>
                </div>
                <div class="card-body flex-grow-1 overflow-auto" style="max-height: 300px;">
                    {% macro render_relation_rows(nodes, level=0) %}
                        {% for node in nodes %}
                            <tr class="{{ 'table-primary' if node.is_current else '' }}">
                                <td class="small text-muted">{{ level }}</td>
                                <td>
                                    <span class="badge bg-light text-dark border">#{{ node.case.id }}</span>
                                </td>
                                <td>
                                    {% if node.is_current %}
                                    <span class="fw-semibold" style="color: var(--accent);">{{ node.case.titel }}</span>
                                    <span class="badge ms-1" style="background: var(--accent);">Aktuel</span>
                                    {% else %}
                                    <a href="/sag/{{ node.case.id }}/v3" class="text-decoration-none fw-semibold">{{ node.case.titel }}</a>
                                    {% endif %}
                                </td>
                                <td>
                                    {% set row_status = (node.case.status or '')|lower %}
                                    <span class="badge {{ 'bg-success-subtle text-success border border-success-subtle' if row_status == 'åben' else 'bg-secondary-subtle text-secondary border border-secondary-subtle' }}">
                                        {{ node.case.status or '-' }}
                                    </span>
                                </td>
                                <td>
                                    <span class="badge bg-light text-dark border">{{ node.case.template_key or node.case.type or 'ticket' }}</span>
                                </td>
                                <td>
                                    {% set rel_raw = (node.relation_type or '')|trim %}
                                    {% set rel_key = rel_raw|lower %}
                                    {% if node.is_current %}
                                        <span class="relation-type-pill is-root" title="Rodsag i visningen.">Rodsag</span>
                                    {% elif rel_key == 'afledt af' %}
                                        <span class="relation-type-pill is-derived" title="Denne sag kommer fra en anden sag. Funktion: styrer retning i relationstræet.">Kommer fra</span>
                                        <div class="relation-type-subtext">(Afledt af)</div>
                                    {% elif rel_key == 'årsag til' %}
                                        <span class="relation-type-pill is-cause" title="Denne sag skaber en følge-sag. Funktion: styrer retning i relationstræet.">Skaber følge-sag</span>
                                        <div class="relation-type-subtext">(Årsag til)</div>
                                    {% elif rel_key == 'blokkerer' %}
                                        <span class="relation-type-pill is-block" title="Denne sag blokerer den anden, indtil den er løst.">Blokerer</span>
                                    {% else %}
                                        <span class="relation-type-pill is-related" title="Sagerne er fagligt koblet uden direkte afhængighed.">Koblet til</span>
                                        <div class="relation-type-subtext">(Relateret til)</div>
                                    {% endif %}
                                    {% if node.is_repeated %}
                                    <i class="bi bi-arrow-repeat text-muted ms-1" title="Vises flere steder i relationstræet"></i>
                                    {% endif %}
                                </td>
                                <td class="text-end">
                                    <div class="btn-group btn-group-sm" role="group">
                                        {% if node.relation_id %}
                                        <button onclick="deleteRelation({{ node.relation_id }})" class="btn btn-outline-danger btn-rel-action" title="Fjern relation">
                                            <i class="bi bi-x-lg"></i>
                                        </button>
                                        {% endif %}
                                        <button class="btn btn-outline-secondary btn-rel-action" title="Tags" onclick="openRelTagPopover({{ node.case.id }})">
                                            <i class="bi bi-tag"></i>
                                        </button>
                                        <button class="btn btn-outline-primary btn-rel-action" title="Quick action" onclick='openRelQaMenu({{ node.case.id }}, {{ (node.case.titel or "")|tojson }}, this)'>
                                            <i class="bi bi-plus-lg"></i>
                                        </button>
                                    </div>
                                </td>
                            </tr>
                            {% if node.children %}
                                {{ render_relation_rows(node.children, level + 1) }}
                            {% endif %}
                        {% endfor %}
                    {% endmacro %}

                    {% set has_relations = relation_tree and (relation_tree|length > 1 or (relation_tree|length == 1 and relation_tree[0].children)) %}
                    {% if has_relations %}
                        <div class="table-responsive">
                            <table class="table table-hover table-sm align-middle mb-0">
                                <thead class="table-light sticky-top">
                                    <tr>
                                        <th style="width: 56px;">Niv.</th>
                                        <th style="width: 88px;">Sag</th>
                                        <th>Titel</th>
                                        <th style="width: 120px;">Status</th>
                                        <th style="width: 130px;">Type</th>
                                        <th style="width: 180px;">Sammenhæng</th>
                                        <th class="text-end" style="width: 130px;">Handling</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {{ render_relation_rows(relation_tree) }}
                                </tbody>
                            </table>
                        </div>
                    {% else %}
                        <p class="text-muted text-center pt-3"><i class="bi bi-diagram-3 me-1"></i>Ingen relaterede sager</p>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>

    <!-- ROW 3: Files + Linked Emails -->
    <div class="row mb-3">
        <!-- Files -->
        <div class="col-12 mb-3">
            <div class="card h-100 right-module-card module-priority-low" data-module="files" data-has-content="unknown">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="module-title"><i class="bi bi-folder2-open module-icon"></i>Filer & Dokumenter</h6>
                    <input type="file" id="fileInput" multiple style="display: none;" onchange="handleFileUpload(this.files)">
                    <button class="btn btn-sm btn-outline-primary" onclick="document.getElementById('fileInput').click()">
                        <i class="bi bi-cloud-upload"></i> Upload
                    </button>
                </div>
                <!-- Drag & Drop Zone -->
                <div class="card-body p-0 d-flex flex-column" id="fileDropZone">
                    <div class="p-4 text-center border-bottom bg-light" id="fileDropMessage" style="cursor: pointer;" onclick="document.getElementById('fileInput').click()">
                        <i class="bi bi-cloud-arrow-up display-6 text-muted"></i>
                        <p class="small text-muted mb-0 mt-2">Træk filer hertil for at uploade</p>
                    </div>
                    <div class="list-group list-group-flush flex-grow-1 overflow-auto" id="files-list" style="max-height: 300px;">
                        <div class="p-3 text-center text-muted">Ingen filer fundet...</div>
                    </div>
                </div>
            </div>
        </div>

    </div>

    <!-- File Preview Modal -->
    <div class="modal fade" id="filePreviewModal" tabindex="-1" data-bs-backdrop="static">
        <div class="modal-dialog modal-xl modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">
                        <i class="bi bi-file-earmark-text me-2"></i>
                        <span id="previewFileName">Fil preview</span>
                    </h5>
                    <div class="ms-auto d-flex align-items-center gap-2">
                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                    </div>
                </div>
                <div class="modal-body p-0" style="min-height: 60vh; max-height: 80vh; overflow: hidden;">
                    <div id="previewContent" class="w-100 h-100 d-flex align-items-center justify-content-center">
                        <div class="spinner-border text-primary" role="status">
                            <span class="visually-hidden">Indlæser...</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Search Modals -->
    <div class="modal fade" id="contactSearchModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Søg kontakt</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <input type="text" id="contactSearch" placeholder="Søg efter kontakt..." class="form-control mb-3">
                    <div id="contactSearchResults" style="max-height: 300px; overflow-y: auto;"></div>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="customerSearchModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="customerSearchModalTitle">Søg kunde</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <input type="text" id="customerSearch" placeholder="Søg efter kunde..." class="form-control mb-3">
                    <div id="customerSearchResults" style="max-height: 300px; overflow-y: auto;"></div>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="relationModal" tabindex="-1">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">🔗 Tilføj relation til sag</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <div class="mb-3">
                        <label class="form-label fw-bold">1. Søg og vælg sag</label>
                        <input type="text" 
                               id="relationCaseSearch" 
                               placeholder="Søg efter sag ID, titel, kunde eller beskrivelse..." 
                               class="form-control form-control-lg"
                               autocomplete="off">
                        <div id="relationSearchResults" 
                             style="max-height: 400px; overflow-y: auto; margin-top: 0.5rem;"
                             class="border rounded"></div>
                    </div>
                    
                    <div id="selectedCasePreview" style="display: none;" class="alert alert-info mb-3">
                        <div class="d-flex justify-content-between align-items-start">
                            <div>
                                <strong>Valgt sag:</strong>
                                <div id="selectedCaseTitle" class="mt-1"></div>
                            </div>
                            <button type="button" class="btn btn-sm btn-outline-secondary" onclick="clearSelectedRelationCase()">
                                Ryd valg
                            </button>
                        </div>
                    </div>
                    
                    <div class="mb-3">
                        <label class="form-label fw-bold">2. Vælg relationstype</label>
                        <select id="relationTypeSelect" class="form-control form-control-lg" onchange="updateAddRelationButton(); updateRelationTypeHint();">
                            <option value="">Vælg hvordan sagerne er relateret...</option>
                            <option value="Relateret til">🔗 Koblet til (Relateret) - Faglig kobling uden direkte afhængighed</option>
                            <option value="Afledt af">↪ Kommer fra (Afledt af) - Denne sag er opstået pga. den anden</option>
                            <option value="Årsag til">➡ Skaber følge-sag (Årsag til) - Denne sag skaber den anden</option>
                            <option value="Blokkerer">⛔ Blokerer - Den anden kan ikke videre før denne er løst</option>
                        </select>
                    </div>

                    <div id="relationTypeHint" class="alert alert-info small mb-3" style="display:none;"></div>

                    <div class="alert alert-light border small mb-3">
                        <div class="fw-semibold mb-1">Betydning i praksis</div>
                        <div><strong>Koblet til (Relateret)</strong>: Faglig sammenhæng, men ingen direkte afhængighed.</div>
                        <div><strong>Kommer fra (Afledt af)</strong>: Sagen er opstået pga. en anden sag.</div>
                        <div><strong>Skaber følge-sag (Årsag til)</strong>: Sagen skaber behovet for en anden sag.</div>
                        <div><strong>Blokkerer</strong>: Bruges når løsning i én sag er nødvendig før den anden kan videre.</div>
                    </div>
                    
                    <div class="alert alert-light d-flex align-items-center" style="font-size: 0.9rem;">
                        <i class="bi bi-info-circle me-2"></i>
                        <div>
                            <strong>Tip:</strong> Brug pile (↑↓) til at navigere i søgeresultater, Enter til at vælge.
                        </div>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Luk</button>
                    <button type="button" 
                            class="btn btn-primary btn-lg" 
                            onclick="addRelation()"
                            id="addRelationBtn"
                            disabled>
                        <i class="bi bi-plus-circle me-1"></i> Tilføj relation
                    </button>
                </div>
            </div>
        </div>
    </div>

    <!-- Contact Info Modal -->
    <div class="modal fade" id="contactInfoModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered modal-sm">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="contactInfoName">Kontakt</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <div class="mb-2">
                        <div class="text-muted small">Titel</div>
                        <div id="contactInfoTitle">-</div>
                    </div>
                    <div class="mb-2">
                        <div class="text-muted small">Kunde</div>
                        <div id="contactInfoCompany">-</div>
                    </div>
                    <div class="mb-2">
                        <div class="text-muted small">E-mail</div>
                        <div id="contactInfoEmail">-</div>
                    </div>
                    <div class="mb-2">
                        <div class="text-muted small">Telefon</div>
                        <div id="contactInfoPhone">-</div>
                    </div>
                    <div class="mb-2">
                        <div class="text-muted small">Mobil</div>
                        <div id="contactInfoMobile">-</div>
                    </div>
                    <div class="mb-2">
                        <div class="text-muted small">Rolle</div>
                        <div id="contactInfoRole">-</div>
                    </div>
                    <div id="contactInfoPrimary" class="badge bg-primary d-none">Hovedkontakt</div>
                </div>
                <div class="modal-footer">
                    <div class="me-auto d-flex gap-2 flex-wrap">
                        <button type="button" class="btn btn-sm btn-outline-success" onclick="callCurrentContactFromInfo()"><i class="bi bi-telephone me-1"></i>Ring</button>
                        <button type="button" class="btn btn-sm btn-outline-primary" onclick="smsCurrentContactFromInfo()"><i class="bi bi-chat-left-text me-1"></i>SMS</button>
                        <button type="button" class="btn btn-sm btn-outline-secondary" onclick="emailCurrentContactFromInfo()"><i class="bi bi-envelope me-1"></i>Email</button>
                    </div>
                    <button type="button" class="btn btn-light" data-bs-dismiss="modal">Luk</button>
                    <button type="button" class="btn btn-primary" onclick="openContactRoleFromInfo()">Rediger rolle</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Contact Role Modal -->
    <div class="modal fade" id="contactRoleModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Rediger kontaktrolle</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <input type="hidden" id="contactRoleContactId" />
                    <div class="mb-2">
                        <label class="form-label">Kontakt</label>
                        <div id="contactRoleName" class="fw-semibold">-</div>
                    </div>
                    <div class="mb-3">
                        <label class="form-label">Rolle</label>
                        <input type="text" class="form-control" id="contactRoleInput" placeholder="fx ansvarlig, beslutningstager">
                    </div>
                    <div class="form-check">
                        <input class="form-check-input" type="checkbox" id="contactRolePrimary">
                        <label class="form-check-label" for="contactRolePrimary">Sæt som hovedkontakt</label>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-light" data-bs-dismiss="modal">Annuller</button>
                    <button type="button" class="btn btn-primary" onclick="saveContactRole()">Gem</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Deadline Modal -->
    <div class="modal fade" id="deadlineModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Deadline</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <label class="form-label">Dato</label>
                    <input
                        type="date"
                        class="form-control form-control-sm"
                        id="deadlineInput"
                        value="{{ case.deadline.strftime('%Y-%m-%d') if case.deadline else '' }}"
                    />
                    <div class="defer-controls mt-2">
                        <button class="btn btn-outline-primary" onclick="shiftDeadlineDays(1)">+1 dag</button>
                        <button class="btn btn-outline-primary" onclick="shiftDeadlineDays(7)">+1 uge</button>
                        <button class="btn btn-outline-primary" onclick="shiftDeadlineMonths(1)">+1 mnd</button>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-light" data-bs-dismiss="modal">Luk</button>
                    <button type="button" class="btn btn-outline-danger" onclick="clearDeadlineAll()">Ryd</button>
                    <button type="button" class="btn btn-primary" onclick="saveDeadlineAll()">Gem</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Deferred Modal -->
    <div class="modal fade" id="deferredModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Udsat start</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <label class="form-label">Dato</label>
                    <input
                        type="date"
                        class="form-control form-control-sm"
                        id="deferredUntilInput"
                        value="{{ case.deferred_until.strftime('%Y-%m-%d') if case.deferred_until else '' }}"
                    />
                    <div class="defer-controls mt-2">
                        <button class="btn btn-outline-primary" onclick="shiftDeferredDays(1)">+1 dag</button>
                        <button class="btn btn-outline-primary" onclick="shiftDeferredDays(7)">+1 uge</button>
                        <button class="btn btn-outline-primary" onclick="shiftDeferredMonths(1)">+1 mnd</button>
                    </div>

                    <label class="form-label mt-3">Start når anden sag har status</label>
                    <select class="form-select form-select-sm" id="deferredCaseSelect">
                        <option value="">Vælg relateret sag</option>
                        {% for rc in related_case_options %}
                        <option value="{{ rc.id }}" {% if case.deferred_until_case_id == rc.id %}selected{% endif %}>
                            #{{ rc.id }} – {{ rc.titel }}
                        </option>
                        {% endfor %}
                    </select>
                    {% set deferred_status_values = (case.deferred_until_status or '').lower().replace(', ', ',').split(',') %}
                    <select class="form-select form-select-sm mt-2" id="deferredStatusSelect" multiple size="6">
                        <option value="__any_change__" {% if '__any_change__' in deferred_status_values %}selected{% endif %}>
                            Ved statusskifte fra nuværende
                        </option>
                        {% for st in status_options %}
                        <option value="{{ st }}" {% if st|lower in deferred_status_values %}selected{% endif %}>
                            {{ st }}
                        </option>
                        {% endfor %}
                    </select>
                    <div class="form-text mt-1">Du kan vælge flere statuser (Cmd/Ctrl + klik).</div>
                    <div class="defer-controls mt-2">
                        <button class="btn btn-outline-primary" type="button" onclick="applyDeferredCloseTrigger()">Når valgt sag lukkes</button>
                        <button class="btn btn-outline-primary" type="button" onclick="applyDeferredResolvedTrigger()">Når valgt sag er løst</button>
                        <button class="btn btn-outline-primary" type="button" onclick="applyDeferredAnyStatusChangeTrigger()">Ved statusskifte</button>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-light" data-bs-dismiss="modal">Luk</button>
                    <button type="button" class="btn btn-outline-danger" onclick="clearDeferredAll()">Ryd</button>
                    <button type="button" class="btn btn-primary" onclick="saveDeferredAll()">Gem</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Start Date Modal -->
    <div class="modal fade" id="startDateModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Arbejdsstart</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <label class="form-label">Dato</label>
                    <input
                        type="date"
                        class="form-control form-control-sm"
                        id="startDateModalInput"
                        value="{{ case.start_date.strftime('%Y-%m-%d') if case.start_date else '' }}"
                    />
                    <div class="defer-controls mt-2">
                        <button class="btn btn-outline-primary" type="button" onclick="setStartDateModalToday()">I dag</button>
                        <button class="btn btn-outline-primary" type="button" onclick="shiftStartDateDays(1)">+1 dag</button>
                        <button class="btn btn-outline-primary" type="button" onclick="shiftStartDateDays(7)">+1 uge</button>
                        <button class="btn btn-outline-primary" type="button" onclick="shiftStartDateMonths(1)">+1 mnd</button>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-light" data-bs-dismiss="modal">Luk</button>
                    <button type="button" class="btn btn-outline-danger" onclick="clearStartDateFromModal()">Ryd</button>
                    <button type="button" class="btn btn-primary" onclick="saveStartDateFromModal()">Gem</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Module Control Modal -->
    <div class="modal fade" id="moduleControlModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Vis/skjul moduler</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body" id="moduleControlList">
                    <div class="text-muted small">Indlæser...</div>
                </div>
                <div class="modal-footer">
                    {% if hovedkontakt %}
                    <div class="me-auto d-flex gap-2 flex-wrap">
                        <button type="button" class="btn btn-sm btn-outline-success" onclick="callMainContactFromModal()"><i class="bi bi-telephone me-1"></i>Ring</button>
                        <button type="button" class="btn btn-sm btn-outline-primary" onclick="smsMainContactFromModal()"><i class="bi bi-chat-left-text me-1"></i>SMS</button>
                        <button type="button" class="btn btn-sm btn-outline-secondary" onclick="emailMainContactFromModal()"><i class="bi bi-envelope me-1"></i>Email</button>
                    </div>
                    {% endif %}
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Luk</button>
                </div>
            </div>
        </div>
    </div>

    <!-- AnyDesk quick-connect modal -->
    <div class="modal fade" id="caseAnyDeskModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="bi bi-display me-2"></i>AnyDesk quick connect</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <div class="mb-3">
                        <label class="form-label">AnyDesk ID</label>
                        <div class="input-group">
                            <input type="text" class="form-control" id="caseAnydeskIdInput" placeholder="fx 123 456 789" oninput="onCaseAnyDeskIdInputChange()" />
                            <a href="#" class="btn btn-outline-primary" id="caseAnydeskOpenLinkBtn" target="_self" style="display:none;">
                                <i class="bi bi-box-arrow-up-right me-1"></i>Åbn AnyDesk
                            </a>
                        </div>
                        <div class="form-text">ID gemmes automatisk på sagen når du klikker forbind.</div>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Gemte IDs på sagen</label>
                        <div id="caseAnyDeskSavedIds" class="d-flex flex-wrap gap-2">
                            <span class="text-muted small">Indlæser...</span>
                        </div>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Relatér til hardware (valgfri)</label>
                        <select class="form-select" id="caseAnydeskHardwareSelect">
                            <option value="">Ingen hardware valgt</option>
                        </select>
                        <div class="form-text">Sagens hardware vises først. Derefter hardware hos kunden.</div>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Kontakt (valgfri)</label>
                        <select class="form-select" id="caseAnydeskContactSelect">
                            <option value="">Ingen kontakt</option>
                            {% for contact in contacts %}
                            <option value="{{ contact.contact_id }}">{{ contact.contact_name }}{% if contact.customer_name %} - {{ contact.customer_name }}{% endif %}</option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="mb-1">
                        <label class="form-label">Notat (valgfri)</label>
                        <textarea class="form-control" id="caseAnydeskNoteInput" rows="3" placeholder="Kort notat om supporten"></textarea>
                    </div>
                    <div class="small text-muted mt-2">
                        Når du klikker forbind oprettes sessionen på sagen med det samme, så varighed/status kan beriges via lokal AnyDesk sync.
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-light" data-bs-dismiss="modal">Annuller</button>
                    <button id="caseAnyDeskConnectBtn" type="button" class="btn btn-primary" onclick="registerCaseAnyDeskSession()"><i class="bi bi-plug me-1"></i>Forbind og gem</button>
                </div>
            </div>
        </div>
    </div>

    <script>
        const caseId = {{ case.id }};
        const caseCustomerId = {{ case.customer_id if case.customer_id else 'null' }};
        const wikiCustomerId = {{ customer.id if customer else 'null' }};
        const wikiDefaultTag = "guide";
        let contactSearchTimeout;
        let customerSearchTimeout;
        let relationSearchTimeout;
        let wikiSearchTimeout;
        let selectedRelationCaseId = null;
        let customerSearchMode = 'link';
        const caseTypeKey = {{ ((case.template_key or case.type or 'ticket')|lower)|tojson }};
        const initialCaseTagsSnapshot = {{ (tags or [])|tojson }};
        const initialCaseBuzzwordsSnapshot = {{ (buzzwords or [])|tojson }};

        async function markCaseAsRecentlyOpened() {
            try {
                await fetch(`/api/v1/sag/recent/open/${caseId}`, {
                    method: 'POST',
                    credentials: 'include',
                    keepalive: true,
                    headers: { 'Accept': 'application/json' }
                });
            } catch (_err) {
                // Best effort only; page should not break if this call fails.
            }
        }

        function escapeCaseTopAlertHtml(value) {
            return String(value ?? '')
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#39;');
        }

        async function loadCaseCustomerTopAlerts() {
            const container = document.getElementById('caseCustomerTopAlerts');
            if (!container || !caseCustomerId) {
                return;
            }

            container.classList.remove('d-none');
            container.innerHTML = '<div class="alert alert-info mb-0"><span class="spinner-border spinner-border-sm me-2"></span>Henter kunde-alerts...</div>';

            try {
                const response = await fetch(`/api/v1/alert-notes/check?entity_type=customer&entity_id=${caseCustomerId}`, {
                    credentials: 'include'
                });

                if (!response.ok) {
                    throw new Error(`HTTP ${response.status}`);
                }

                const payload = await response.json();
                const alerts = (payload?.alerts || []).filter((alert) => {
                    const severity = String(alert?.severity || '').toLowerCase();
                    return severity === 'critical' || severity === 'warning';
                });

                if (!alerts.length) {
                    container.classList.add('d-none');
                    container.innerHTML = '';
                    return;
                }

                container.innerHTML = alerts.map((alert) => {
                    const isCritical = String(alert.severity || '').toLowerCase() === 'critical';
                    const level = isCritical ? 'KRITISK' : 'ADVARSEL';
                    const klass = isCritical ? 'alert-danger' : 'alert-warning';
                    const title = escapeCaseTopAlertHtml(alert.title || 'Vigtig kundeinformation');
                    const message = escapeCaseTopAlertHtml(alert.message || '');

                    return `
                        <div class="alert ${klass} mb-2" role="alert" style="border-left: 6px solid ${isCritical ? '#e03131' : '#f59f00'};">
                            <strong>${level}:</strong> ${title}
                            ${message ? `<div class="small mt-1">${message}</div>` : ''}
                        </div>
                    `;
                }).join('');
                container.classList.remove('d-none');
            } catch (error) {
                console.error('Failed to load case customer alerts:', error);
                container.innerHTML = '<div class="alert alert-warning mb-0" role="alert"><strong>Advarsel:</strong> Kunde-alerts kunne ikke hentes.</div>';
                container.classList.remove('d-none');
            }
        }

        function forceCaseTabActivation(tabId) {
            if (!tabId) return;

            const trigger = document.querySelector(`#caseTabs [data-bs-target="#${tabId}"]`);
            if (!trigger) return;
            window.syncCaseTabPaneVisibility(tabId);
            trigger.dispatchEvent(new Event('shown.bs.tab', { bubbles: true }));
            if (typeof window.loadCaseTabData === 'function') window.loadCaseTabData(tabId);
        }

        window.moduleDisplayNames = {
            'relations': 'Relationer',
            'call-history': 'Opkaldshistorik',
            'files': 'Filer',
            'emails': 'E-mails',
            'pipeline': 'Salgspipeline',
            'hardware': 'Hardware',
            'locations': 'Lokationer',
            'contacts': 'Kontakter',
            'customers': 'Kunder',
            'tags': 'Tags',
            'buzzwords': 'Buzzwords',
            'wiki': 'Wiki',
            'todo-steps': 'Todo-opgaver',
            'time': 'Tid',
            'timetracking': 'Tidsforbrug',
            'solution': 'Løsning',
            'sales': 'Varekøb & salg',
            'subscription': 'Abonnement',
            'reminders': 'Påmindelser',
            'calendar': 'Kalender'
        };
        caseTypeModuleDefaults = window.caseTypeModuleDefaults || {};

        // Modal instances
        let contactSearchModal, customerSearchModal, relationModal, contactInfoModal, createRelatedCaseModalInstance, caseAnyDeskModal;
        let currentContactInfo = null;

        // Initialize everything when DOM is ready
        document.addEventListener('DOMContentLoaded', () => {
            markCaseAsRecentlyOpened();
            hydrateTopbarStatusOptions();
            loadCaseCustomerTopAlerts();
            applyTopbarImportanceBubbles();
            // Initialize modals
            contactSearchModal = new bootstrap.Modal(document.getElementById('contactSearchModal'));
            customerSearchModal = new bootstrap.Modal(document.getElementById('customerSearchModal'));
            relationModal = new bootstrap.Modal(document.getElementById('relationModal'));
            contactInfoModal = new bootstrap.Modal(document.getElementById('contactInfoModal'));
            createRelatedCaseModalInstance = new bootstrap.Modal(document.getElementById('createRelatedCaseModal'));
            const caseAnyDeskEl = document.getElementById('caseAnyDeskModal');
            if (caseAnyDeskEl) {
                caseAnyDeskModal = new bootstrap.Modal(caseAnyDeskEl);
            }

            // Setup search handlers
            setupContactSearch();
            setupCustomerSearch();
            setupRelationSearch();
            updateRelationTypeHint();
            updateNewCaseRelationTypeHint();

            // Initialize all tooltips on the page
            document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => {
                bootstrap.Tooltip.getOrCreateInstance(el, { html: true, container: 'body' });
            });
            
            Promise.all([loadModulePrefs(), loadCaseTypeModuleDefaultsSetting()]).then(() => applyViewFromTags());

            // Set default context for keyboard shortcuts (Option+Shift+T)
            if (window.setTagPickerContext) {
                window.setTagPickerContext('case', {{ case.id }}, (tag, addResult) => {
                    syncCaseTagsUi();

                    const actionType = addResult && addResult.action ? addResult.action.type : null;
                    const shouldOpenTemplateModal = actionType === 'open_task_template_modal'
                        || String((tag && tag.name) || '').toLowerCase() === 'opgave_template';

                    if (shouldOpenTemplateModal && typeof window.openTaskTemplateSelectorModal === 'function') {
                        window.openTaskTemplateSelectorModal({
                            action: addResult ? addResult.action : null,
                            entity_type: 'case',
                            entity_id: caseId,
                        });
                    }
                });
            }
            
            // Load Hardware & Locations
            loadCaseHardware();
            loadCaseLocations();
            loadCaseWiki();
            loadTodoSteps();
            loadCaseTagsModule();
            loadCaseTagSuggestions();
            loadCaseBuzzwordsModule();

            // Keep suggestions fresh while user works on the case.
            setInterval(loadCaseTagSuggestions, 30000);

            const wikiSearchInput = document.getElementById('wikiSearchInput');
            if (wikiSearchInput) {
                wikiSearchInput.addEventListener('input', () => {
                    clearTimeout(wikiSearchTimeout);
                    wikiSearchTimeout = setTimeout(() => {
                        loadCaseWiki(wikiSearchInput.value || '');
                    }, 300);
                });
            }

            const todoForm = document.getElementById('todoStepForm');
            if (todoForm) {
                todoForm.addEventListener('submit', createTodoStep);
            }

            ['topbarStatusSelect', 'tabsAssignmentUserSelect', 'tabsAssignmentGroupSelect', 'topbarTypeSelect', 'topbarPrioritySelect', 'topbarStartDateInput', 'topbarDeferredInput', 'topbarDeadlineInput'].forEach((id) => {
                const el = document.getElementById(id);
                if (el) {
                    el.addEventListener('change', applyTopbarImportanceBubbles);
                    el.addEventListener('input', applyTopbarImportanceBubbles);
                }
            });

            const caseTabsContent = document.getElementById('caseTabsContent');
            if (caseTabsContent && typeof MutationObserver !== 'undefined') {
                let tabBadgeTimer = null;
                const scheduleBadgeRefresh = () => {
                    if (tabBadgeTimer) {
                        clearTimeout(tabBadgeTimer);
                    }
                    tabBadgeTimer = setTimeout(() => updateCaseTabCountBadges(), 80);
                };

                const tabObserver = new MutationObserver(scheduleBadgeRefresh);
                tabObserver.observe(caseTabsContent, {
                    childList: true,
                    subtree: true,
                    characterData: true,
                    attributes: true,
                    attributeFilter: ['data-has-content', 'class']
                });
            }

            updateCaseTabCountBadges();

            const caseTabs = document.getElementById('caseTabs');
            if (caseTabs) {
                const loadCaseTabData = async (tabId) => {
                    if (!tabId) return;

                    try {
                        if (tabId === 'sales' && typeof loadVarekobSalg === 'function') {
                            await loadVarekobSalg();
                        } else if (tabId === 'timetracking' && typeof loadTimeTrackingTab === 'function') {
                            await loadTimeTrackingTab();
                        } else if (tabId === 'subscription' && typeof loadSubscriptionForCase === 'function') {
                            await loadSubscriptionForCase();
                        } else if (tabId === 'reminders') {
                            if (typeof loadReminders === 'function') await loadReminders();
                            if (typeof loadCaseCalendar === 'function') await loadCaseCalendar();
                        }
                    } catch (tabLoadError) {
                        console.error('Tab data reload failed:', tabLoadError);
                    }
                };
                window.loadCaseTabData = loadCaseTabData;

                caseTabs.addEventListener('click', async (event) => {
                    const trigger = event.target.closest('[data-bs-target]');
                    if (!trigger || !caseTabs.contains(trigger)) return;

                    event.preventDefault();
                    event.stopImmediatePropagation();

                    const targetSelector = trigger.getAttribute('data-bs-target') || '';
                    const tabId = targetSelector.startsWith('#') ? targetSelector.slice(1) : targetSelector;
                    if (!tabId) return;

                    window.syncCaseTabPaneVisibility(tabId);
                    trigger.dispatchEvent(new Event('shown.bs.tab', { bubbles: true }));
                    await loadCaseTabData(tabId);
                }, true);
            }

            window.syncCaseTabPaneVisibility('details');

            // Focus on title when create modal opens
            const createModalEl = document.getElementById('createRelatedCaseModal');
            if (createModalEl) {
                createModalEl.addEventListener('shown.bs.modal', function () {
                    document.getElementById('newCaseTitle').focus();
                });
            }
        });

        // Show modal functions
        function showContactSearch() {
            contactSearchModal.show();
            setTimeout(() => document.getElementById('contactSearch').focus(), 300);
        }

        function showCustomerSearch(mode = 'link') {
            customerSearchMode = mode === 'replace' ? 'replace' : 'link';
            const title = document.getElementById('customerSearchModalTitle');
            if (title) {
                title.textContent = customerSearchMode === 'replace' ? 'Skift kunde på sag' : 'Søg kunde';
            }
            customerSearchModal.show();
            setTimeout(() => document.getElementById('customerSearch').focus(), 300);
        }

        function showRelationModal() {
            const modalEl = document.getElementById('relationModal');
            if (!modalEl) {
                console.error('relationModal element not found');
                return;
            }

            if (!relationModal) {
                relationModal = bootstrap.Modal.getOrCreateInstance(modalEl);
            }

            relationModal.show();
            updateRelationTypeHint();
            setTimeout(() => {
                const input = document.getElementById('relationCaseSearch');
                if (input) input.focus();
            }, 300);
        }

        async function openAuthenticatedPrintView(url, fallbackTitle) {
            const popup = window.open('', '_blank', 'noopener');
            if (!popup) {
                alert('Browser blokerede popup-vinduet. Tillad popups for at printe.');
                return;
            }

            popup.document.write('<!doctype html><html><head><meta charset="utf-8"><title>Loader...</title></head><body style="font-family:Segoe UI,sans-serif;padding:20px;">Henter printvisning...</body></html>');
            popup.document.close();

            const token = localStorage.getItem('access_token') || sessionStorage.getItem('access_token');
            const headers = token ? { Authorization: `Bearer ${token}` } : {};

            try {
                const res = await fetch(url, {
                    method: 'GET',
                    headers,
                    credentials: 'include'
                });

                if (!res.ok) {
                    let detail = `Kunne ikke hente printvisning (${res.status})`;
                    try {
                        const payload = await res.json();
                        if (payload?.detail) detail = payload.detail;
                    } catch (_) {
                    }
                    popup.document.body.innerHTML = `<div style="font-family:Segoe UI,sans-serif;padding:20px;color:#b42318;">${escapeHtml(detail)}</div>`;
                    return;
                }

                const htmlContent = await res.text();
                popup.document.open();
                popup.document.write(htmlContent);
                popup.document.close();
                if (fallbackTitle && !popup.document.title) {
                    popup.document.title = fallbackTitle;
                }
            } catch (error) {
                popup.document.body.innerHTML = `<div style="font-family:Segoe UI,sans-serif;padding:20px;color:#b42318;">Fejl ved hentning af printvisning: ${escapeHtml(error?.message || 'Ukendt fejl')}</div>`;
            }
        }

        function openCaseWorkOrderPrint() {
            window.open(`/sag/${caseId}/work-orders/print`, '_blank', 'noopener');
        }

        function openCaseHardwareLabelsPrint() {
            window.open(`/sag/${caseId}/labels/hardware/print`, '_blank', 'noopener');
        }

        function openCaseHardwareLabelsPrintDirect() {
            window.open(`/sag/${caseId}/labels/hardware/print?auto_print=1`, '_blank', 'noopener');
        }

        async function sendCaseHardwareLabelsToPrinter(hardwareId = null) {
            try {
                const token = localStorage.getItem('access_token') || sessionStorage.getItem('access_token');
                const headers = { 'Content-Type': 'application/json' };
                if (token) {
                    headers.Authorization = `Bearer ${token}`;
                }

                const requestPayload = {};
                if (hardwareId !== null && hardwareId !== undefined) {
                    const parsedHardwareId = Number(hardwareId);
                    if (!Number.isFinite(parsedHardwareId)) {
                        showNotification('Ugyldigt hardware-id', 'error');
                        return;
                    }
                    requestPayload.hardware_id = parsedHardwareId;
                }

                const response = await fetch(`/api/v1/sag/${caseId}/labels/hardware/print-direct`, {
                    method: 'POST',
                    headers,
                    credentials: 'include',
                    body: JSON.stringify(requestPayload)
                });

                if (!response.ok) {
                    let detail = `Print fejlede (${response.status})`;
                    try {
                        const payload = await response.json();
                        if (payload && payload.detail) detail = payload.detail;
                    } catch (_) {}
                    showNotification(detail, 'error');
                    // Fallback: open browser print view if direct printer is unavailable.
                    openCaseHardwareLabelsPrintDirect();
                    return;
                }

                const payload = await response.json().catch(() => ({}));
                const printed = payload?.printed || 0;
                if (hardwareId !== null && hardwareId !== undefined) {
                    showNotification('Label sendt til printer', 'success');
                } else {
                    showNotification(`Sendte ${printed} labels til printer`, 'success');
                }
            } catch (error) {
                showNotification(`Print fejlede: ${error?.message || 'ukendt fejl'}`, 'error');
            }
        }

        function showContactInfoModal(el) {
            currentContactInfo = {
                id: el.dataset.contactId,
                name: el.dataset.name || '-',
                title: el.dataset.title || '-',
                company: el.dataset.company || '-',
                email: el.dataset.email || '-',
                phone: el.dataset.phone || '-',
                mobile: el.dataset.mobile || '-',
                role: el.dataset.role || '-',
                isPrimary: el.dataset.isPrimary === 'true'
            };

            document.getElementById('contactInfoName').textContent = currentContactInfo.name;
            document.getElementById('contactInfoTitle').textContent = currentContactInfo.title || '-';
            document.getElementById('contactInfoCompany').textContent = currentContactInfo.company || '-';
            document.getElementById('contactInfoEmail').textContent = currentContactInfo.email || '-';
            document.getElementById('contactInfoPhone').innerHTML = renderCasePhone(currentContactInfo.phone);
            document.getElementById('contactInfoMobile').innerHTML = renderCaseMobile(currentContactInfo.mobile, currentContactInfo.name);
            document.getElementById('contactInfoRole').textContent = currentContactInfo.role || '-';

            const primaryBadge = document.getElementById('contactInfoPrimary');
            if (currentContactInfo.isPrimary) {
                primaryBadge.classList.remove('d-none');
            } else {
                primaryBadge.classList.add('d-none');
            }

            contactInfoModal.show();
        }

        function renderCasePhone(number) {
            const clean = String(number || '').trim();
            if (!clean || clean === '-') return '-';
            return `<a href="tel:${escapeHtml(clean)}" style="color: var(--accent);">${escapeHtml(clean)}</a>`;
        }

        function renderCaseMobile(number, name) {
            const clean = String(number || '').trim();
            if (!clean || clean === '-') return '-';
            return `
                <div class="d-flex align-items-center gap-2 flex-wrap">
                    <a href="tel:${escapeHtml(clean)}" style="color: var(--accent);">${escapeHtml(clean)}</a>
                    <button type="button" class="btn btn-sm btn-outline-primary" onclick="openSmsPrompt('${escapeHtml(clean)}', '${escapeHtml(name || '')}', ${currentContactInfo?.id || 'null'})">SMS</button>
                </div>
            `;
        }

        function getCurrentContactPreferredNumber() {
            if (!currentContactInfo) return '';
            const mobile = String(currentContactInfo.mobile || '').trim();
            const phone = String(currentContactInfo.phone || '').trim();
            return mobile && mobile !== '-' ? mobile : (phone && phone !== '-' ? phone : '');
        }

        async function callCurrentContactFromInfo() {
            const number = getCurrentContactPreferredNumber();
            if (!number) {
                alert('Ingen telefon eller mobil på kontakten');
                return;
            }
            await ringOutFromCase(number, {
                logToCase: true,
                contactName: currentContactInfo?.name || ''
            });
        }

        function smsCurrentContactFromInfo() {
            if (!currentContactInfo) return;
            const number = String(currentContactInfo.mobile || currentContactInfo.phone || '').trim();
            if (!number || number === '-') {
                alert('Ingen mobil/telefon på kontakten');
                return;
            }
            openSmsPrompt(number, currentContactInfo.name || '', currentContactInfo.id || null);
            logCaseSystemComment(`💬 SMS-vindue åbnet til ${currentContactInfo.name || 'kontakt'} (${number})`);
        }

        function emailCurrentContactFromInfo() {
            if (!currentContactInfo) return;
            const email = String(currentContactInfo.email || '').trim();
            if (!email || email === '-') {
                alert('Ingen e-mail på kontakten');
                return;
            }
            openCaseEmailTab();
            setTimeout(() => {
                const toInput = document.getElementById('caseEmailTo');
                if (toInput) toInput.value = email;
                const composeModalEl = document.getElementById('caseEmailComposeModal');
                if (composeModalEl) {
                    bootstrap.Modal.getOrCreateInstance(composeModalEl).show();
                }
            }, 150);
            logCaseSystemComment(`✉️ Email-kladde åbnet til ${currentContactInfo.name || 'kontakt'} (${email})`);
        }

        async function callMainContactFromModal() {
            const number = {{ ((hovedkontakt.mobile or hovedkontakt.phone or '') if hovedkontakt else '')|tojson }};
            const name = {{ (((hovedkontakt.first_name ~ ' ' ~ hovedkontakt.last_name)|trim) if hovedkontakt else '')|tojson }};
            if (!number) {
                alert('Ingen telefon eller mobil på hovedkontakt');
                return;
            }
            await ringOutFromCase(number, { logToCase: true, contactName: name });
        }

        function smsMainContactFromModal() {
            {% if hovedkontakt %}
            const number = {{ (hovedkontakt.mobile or hovedkontakt.phone or '')|tojson }};
            const name = {{ ((hovedkontakt.first_name ~ ' ' ~ hovedkontakt.last_name)|trim)|tojson }};
            const contactId = {{ hovedkontakt.id|default('null') }};
            if (!number) {
                alert('Ingen mobil/telefon på hovedkontakt');
                return;
            }
            openSmsPrompt(number, name, contactId);
            logCaseSystemComment(`💬 SMS-vindue åbnet til ${name} (${number})`);
            {% endif %}
        }

        function emailMainContactFromModal() {
            {% if hovedkontakt %}
            const email = {{ (hovedkontakt.email or '')|tojson }};
            const name = {{ ((hovedkontakt.first_name ~ ' ' ~ hovedkontakt.last_name)|trim)|tojson }};
            if (!email) {
                alert('Ingen e-mail på hovedkontakt');
                return;
            }
            openCaseEmailTab();
            setTimeout(() => {
                const toInput = document.getElementById('caseEmailTo');
                if (toInput) toInput.value = email;
                const composeModalEl = document.getElementById('caseEmailComposeModal');
                if (composeModalEl) {
                    bootstrap.Modal.getOrCreateInstance(composeModalEl).show();
                }
            }, 150);
            logCaseSystemComment(`✉️ Email-kladde åbnet til ${name} (${email})`);
            {% endif %}
        }

        function openContactRoleFromInfo() {
            if (!currentContactInfo) return;
            contactInfoModal.hide();
            openContactRoleModal(
                currentContactInfo.id,
                currentContactInfo.name,
                currentContactInfo.role || 'Kontakt',
                currentContactInfo.isPrimary
            );
        }

        function showCreateRelatedModal() {
            if (!createRelatedCaseModalInstance) {
                const modalEl = document.getElementById('createRelatedCaseModal');
                if (!modalEl) {
                    console.error('createRelatedCaseModal element not found');
                    return;
                }
                createRelatedCaseModalInstance = bootstrap.Modal.getOrCreateInstance(modalEl);
            }
            createRelatedCaseModalInstance.show();
            updateNewCaseRelationTypeHint();
        }

        function relationTypeMeaning(type) {
            const map = {
                'Relateret til': {
                    icon: '🔗',
                    text: 'Koblet til: Sagerne hænger fagligt sammen, men ingen af dem er direkte afhængig af den anden.'
                },
                'Afledt af': {
                    icon: '↪',
                    text: 'Kommer fra: Denne sag er opstået på baggrund af den anden sag (den anden er ophav/forløber).'
                },
                'Årsag til': {
                    icon: '➡',
                    text: 'Skaber følge-sag: Denne sag er årsag til den anden sag (du peger frem mod en konsekvens/opfølgning).'
                },
                'Blokkerer': {
                    icon: '⛔',
                    text: 'Arbejdet i denne sag stopper fremdrift i den anden sag, indtil blokeringen er løst.'
                }
            };
            return map[type] || null;
        }

        function updateRelationTypeHint() {
            const select = document.getElementById('relationTypeSelect');
            const hint = document.getElementById('relationTypeHint');
            if (!select || !hint) return;

            const meaning = relationTypeMeaning(select.value);
            if (!meaning) {
                hint.style.display = 'none';
                hint.innerHTML = '';
                return;
            }

            hint.style.display = 'block';
            hint.innerHTML = `<strong>${meaning.icon} Betydning:</strong> ${meaning.text}`;
        }

        function updateNewCaseRelationTypeHint() {
            const select = document.getElementById('newCaseRelationType');
            const hint = document.getElementById('newCaseRelationTypeHint');
            if (!select || !hint) return;

            const selected = select.value;
            if (selected === 'Afledt af') {
                hint.innerHTML = '<strong>↪ Effekt:</strong> Nuværende sag markeres som kommer fra den nye sag.';
                return;
            }
            if (selected === 'Årsag til') {
                hint.innerHTML = '<strong>➡ Effekt:</strong> Nuværende sag markeres som at den skaber den nye følge-sag.';
                return;
            }
            if (selected === 'Blokkerer') {
                hint.innerHTML = '<strong>⛔ Effekt:</strong> Nuværende sag markeres som blokering for den nye sag.';
                return;
            }

            hint.innerHTML = '<strong>🔗 Effekt:</strong> Sagerne kobles fagligt uden direkte afhængighed (Koblet til).';
        }

        async function createRelatedCase() {
            const title = document.getElementById('newCaseTitle').value;
            const relationType = document.getElementById('newCaseRelationType').value;
            const description = document.getElementById('newCaseDescription').value;
            const customerId = (caseCustomerId || wikiCustomerId || null);

            if (!title) {
                alert('Titel er påkrævet');
                return;
            }

            if (!customerId) {
                alert('Sagen mangler kunde. Tilknyt kunde først, før du opretter relateret sag.');
                return;
            }

            // 1. Create the new case
            try {
                const caseResponse = await fetch('/api/v1/sag', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({
                        titel: title,
                        beskrivelse: description,
                        customer_id: customerId,
                        status: 'åben'
                    })
                });

                if (!caseResponse.ok) {
                    const payload = await caseResponse.json().catch(() => ({}));
                    throw new Error(payload.detail || 'Kunne ikke oprette sag');
                }
                const newCase = await caseResponse.json();

                // 2. Create the relation
                const relationResponse = await fetch(`/api/v1/sag/${caseId}/relationer`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({
                        målsag_id: newCase.id,
                        relationstype: relationType
                    })
                });

                if (!relationResponse.ok) {
                    const payload = await relationResponse.json().catch(() => ({}));
                    throw new Error(payload.detail || 'Kunne ikke oprette relation');
                }

                // 3. Reload to show new relation
                window.location.reload();

            } catch (err) {
                console.error('Error creating related case:', err);
                alert('Der opstod en fejl: ' + err.message);
            }
        }

        function confirmDeleteCase() {
            if(confirm('Slet denne sag?')) {
                fetch('/api/v1/sag/{{ case.id }}', {method: 'DELETE'})
                    .then(() => window.location='/sag');
            }
        }

        // Contact Search
        function setupContactSearch() {
            const contactSearchInput = document.getElementById('contactSearch');
            contactSearchInput.addEventListener('input', function(e) {
                clearTimeout(contactSearchTimeout);
                const query = e.target.value.trim();
                
                if (query.length < 2) {
                    document.getElementById('contactSearchResults').innerHTML = '';
                    return;
                }
                
                contactSearchTimeout = setTimeout(async () => {
                    try {
                        const response = await fetch(`/api/v1/search/contacts?q=${encodeURIComponent(query)}`);
                        const contacts = await response.json();
                        
                        const resultsDiv = document.getElementById('contactSearchResults');
                        if (contacts.length === 0) {
                            resultsDiv.innerHTML = '<div class="p-3 text-muted">Ingen kontakter fundet</div>';
                        } else {
                            resultsDiv.innerHTML = contacts.map(c => `
                                ${(() => {
                                    const clean = (v) => {
                                        if (v === null || v === undefined) return '';
                                        const s = String(v).trim();
                                        if (!s || s.toLowerCase() === 'null' || s.toLowerCase() === 'none') return '';
                                        return s;
                                    };
                                    const firstName = clean(c.first_name);
                                    const lastName = clean(c.last_name);
                                    const fullName = [firstName, lastName].filter(Boolean).join(' ') || `Kontakt #${c.id}`;
                                    const email = clean(c.email);
                                    const company = clean(c.user_company);
                                    const phones = Array.from(new Set([
                                        clean(c.mobile) ? `Mobil: ${clean(c.mobile)}` : '',
                                        clean(c.phone) ? `Telefon: ${clean(c.phone)}` : '',
                                        clean(c.user_company_phone) ? `Firma: ${clean(c.user_company_phone)}` : ''
                                    ].filter(Boolean)));

                                    return `
                                <div class="list-group-item list-group-item-action" style="cursor: pointer;" 
                                     onclick="addContact(${caseId}, ${c.id}, '${fullName.replace(/'/g, "\\'")}')">
                                    <strong>${fullName}</strong>
                                    <div class="small text-muted">${[email, company ? '(' + company + ')' : ''].filter(Boolean).join(' ')}</div>
                                    <div class="small mt-1">
                                        ${phones.join(' · ') || '<span class="text-muted">Intet telefonnummer</span>'}
                                    </div>
                                </div>
                                    `;
                                })()}
                            `).join('');
                        }
                    } catch (err) {
                        console.error('Error searching contacts:', err);
                    }
                }, 300);
            });
        }

        async function addContact(caseId, contactId, contactName) {
            try {
                const response = await fetch(`/api/v1/sag/${caseId}/contacts`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({contact_id: contactId, role: 'Kontakt'})
                });
                
                if (response.ok) {
                    contactSearchModal.hide();
                    window.location.reload();
                } else {
                    const error = await response.json();
                    alert(`Fejl: ${error.detail}`);
                }
            } catch (err) {
                alert('Fejl ved tilføjelse af kontakt: ' + err.message);
            }
        }

        async function removeContact(caseId, contactId) {
            if (confirm('Fjern denne kontakt fra sagen?')) {
                const response = await fetch(`/api/v1/sag/${caseId}/contacts/${contactId}`, {method: 'DELETE'});
                if (response.ok) {
                    window.location.reload();
                } else {
                    alert('Fejl ved fjernelse af kontakt');
                }
            }
        }

        // Customer Search
        function setupCustomerSearch() {
            const customerSearchInput = document.getElementById('customerSearch');
            customerSearchInput.addEventListener('input', function(e) {
                clearTimeout(customerSearchTimeout);
                const query = e.target.value.trim();
                
                if (query.length < 2) {
                    document.getElementById('customerSearchResults').innerHTML = '';
                    return;
                }
                
                customerSearchTimeout = setTimeout(async () => {
                    try {
                        const response = await fetch(`/api/v1/search/customers?q=${encodeURIComponent(query)}`);
                        const customers = await response.json();
                        
                        const resultsDiv = document.getElementById('customerSearchResults');
                        if (customers.length === 0) {
                            resultsDiv.innerHTML = '<div class="p-3 text-muted">Ingen kunder fundet</div>';
                        } else {
                            resultsDiv.innerHTML = customers.map(c => `
                                <div class="list-group-item list-group-item-action" style="cursor: pointer;" 
                                     onclick="selectCustomerFromSearch(${caseId}, ${c.id})">
                                    <strong>${c.name}</strong>
                                    <div class="small text-muted">${c.email || ''} ${c.cvr_number ? '(CVR: ' + c.cvr_number + ')' : ''}</div>
                                </div>
                            `).join('');
                        }
                    } catch (err) {
                        console.error('Error searching customers:', err);
                    }
                }, 300);
            });
        }

        async function selectCustomerFromSearch(caseId, customerId, customerName = '') {
            if (customerSearchMode === 'replace') {
                await replaceCaseCustomer(caseId, customerId, customerName);
                return;
            }
            await addCustomer(caseId, customerId, customerName);
        }

        async function replaceCaseCustomer(caseId, customerId, customerName) {
            try {
                let response = await fetch(`/api/v1/sag/${caseId}/customer/replace`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({customer_id: customerId})
                });

                // Backwards compatibility with older API nodes.
                if (response.status === 404 || response.status === 405) {
                    response = await fetch(`/api/v1/sag/${caseId}`, {
                        method: 'PATCH',
                        headers: {'Content-Type': 'application/json'},
                        body: JSON.stringify({customer_id: customerId})
                    });
                }

                if (response.ok) {
                    customerSearchModal.hide();
                    window.location.reload();
                } else {
                    const error = await response.json().catch(() => ({}));
                    alert(`Fejl ved skift af kunde: ${error.detail || response.statusText || 'Ukendt fejl'}`);
                }
            } catch (err) {
                alert('Fejl ved skift af kunde: ' + err.message);
            }
        }

        async function addCustomer(caseId, customerId, customerName) {
            try {
                const response = await fetch(`/api/v1/sag/${caseId}/customers`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({customer_id: customerId, role: 'Kunde'})
                });
                
                if (response.ok) {
                    customerSearchModal.hide();
                    window.location.reload();
                } else {
                    const error = await response.json();
                    alert(`Fejl: ${error.detail}`);
                }
            } catch (err) {
                alert('Fejl ved tilføjelse af kunde: ' + err.message);
            }
        }

        async function removeCustomer(caseId, customerId) {
            if (confirm('Fjern denne kunde fra sagen?')) {
                const response = await fetch(`/api/v1/sag/${caseId}/customers/${customerId}`, {method: 'DELETE'});
                if (response.ok) {
                    window.location.reload();
                } else {
                    alert('Fejl ved fjernelse af kunde');
                }
            }
        }

        // Relation Search - Enhanced version
        let currentFocusIndex = -1;
        let searchResults = [];
        
        function setupRelationSearch() {
            const relationSearchInput = document.getElementById('relationCaseSearch');
            
            // Input handler
            relationSearchInput.addEventListener('input', function(e) {
                clearTimeout(relationSearchTimeout);
                const query = e.target.value.trim();
                currentFocusIndex = -1;
                
                if (query.length < 2) {
                    document.getElementById('relationSearchResults').innerHTML = '';
                    document.getElementById('relationSearchResults').style.display = 'none';
                    return;
                }
                
                relationSearchTimeout = setTimeout(async () => {
                    try {
                        const response = await fetch(`/api/v1/search/sag?q=${encodeURIComponent(query)}`);
                        const cases = await response.json();
                        searchResults = cases.filter(c => c.id !== caseId);
                        
                        renderRelationSearchResults(searchResults);
                    } catch (err) {
                        console.error('Error searching cases:', err);
                    }
                }, 200);
            });
            
            // Keyboard navigation
            relationSearchInput.addEventListener('keydown', function(e) {
                const resultsDiv = document.getElementById('relationSearchResults');
                const items = resultsDiv.querySelectorAll('.relation-search-item');
                
                if (e.key === 'ArrowDown') {
                    e.preventDefault();
                    currentFocusIndex = (currentFocusIndex + 1) % items.length;
                    updateFocusedItem(items);
                } else if (e.key === 'ArrowUp') {
                    e.preventDefault();
                    currentFocusIndex = currentFocusIndex <= 0 ? items.length - 1 : currentFocusIndex - 1;
                    updateFocusedItem(items);
                } else if (e.key === 'Enter') {
                    e.preventDefault();
                    if (currentFocusIndex >= 0 && currentFocusIndex < items.length) {
                        items[currentFocusIndex].click();
                    }
                }
            });
        }
        
        function updateFocusedItem(items) {
            items.forEach((item, index) => {
                if (index === currentFocusIndex) {
                    item.classList.add('active');
                    item.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
                } else {
                    item.classList.remove('active');
                }
            });
        }
        
        function renderRelationSearchResults(cases) {
            const resultsDiv = document.getElementById('relationSearchResults');
            
            if (cases.length === 0) {
                resultsDiv.innerHTML = '<div class="p-3 text-muted text-center"><i class="bi bi-search me-2"></i>Ingen sager fundet</div>';
                resultsDiv.style.display = 'block';
                return;
            }
            
            // Group by status
            const grouped = {};
            cases.forEach(c => {
                const status = c.status || 'ukendt';
                if (!grouped[status]) grouped[status] = [];
                grouped[status].push(c);
            });
            
            let html = '<div class="list-group list-group-flush">';
            
            // Sort status groups: åben first, then others
            const statusOrder = ['åben', 'under behandling', 'afventer', 'løst', 'lukket'];
            const sortedStatuses = Object.keys(grouped).sort((a, b) => {
                const aIndex = statusOrder.indexOf(a);
                const bIndex = statusOrder.indexOf(b);
                if (aIndex === -1 && bIndex === -1) return a.localeCompare(b);
                if (aIndex === -1) return 1;
                if (bIndex === -1) return -1;
                return aIndex - bIndex;
            });
            
            sortedStatuses.forEach(status => {
                const statusCases = grouped[status];
                
                // Status group header
                html += `
                    <div class="list-group-item bg-light" style="padding: 0.5rem 1rem; font-weight: 600; font-size: 0.85rem; color: var(--text-secondary);">
                        <span class="status-badge status-${status}">${status}</span>
                        <span class="badge bg-secondary float-end">${statusCases.length}</span>
                    </div>
                `;
                
                statusCases.forEach(c => {
                    const createdDate = c.created_at ? new Date(c.created_at).toLocaleDateString('da-DK') : 'N/A';
                    const beskrivelse = c.beskrivelse ? c.beskrivelse.substring(0, 80) + '...' : '';
                    const customerName = c.customer_name || '';
                    const safeTitle = (c.titel || '').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
                    const safeCustomer = customerName.replace(/"/g, '&quot;').replace(/'/g, '&#39;');
                    
                    html += `
                        <div class="list-group-item list-group-item-action relation-search-item" 
                             style="cursor: pointer; padding: 0.75rem 1rem;"
                             onclick="selectRelationCase(${c.id}, '${safeTitle}', '${safeCustomer}', '${status}');"
                             data-case-id="${c.id}">
                            <div class="d-flex justify-content-between align-items-start">
                                <div style="flex: 1;">
                                    <div class="d-flex align-items-center gap-2 mb-1">
                                        <span class="badge bg-primary" style="font-size: 0.75rem;">#${c.id}</span>
                                        <strong style="font-size: 0.95rem;">${escapeHtml(c.titel)}</strong>
                                    </div>
                                    ${c.customer_name ? `
                                        <div class="small text-muted mb-1">
                                            <i class="bi bi-building me-1"></i>${escapeHtml(c.customer_name)}
                                        </div>
                                    ` : ''}
                                    ${beskrivelse ? `
                                        <div class="small text-muted" style="font-size: 0.8rem;">${escapeHtml(beskrivelse)}</div>
                                    ` : ''}
                                </div>
                                <div class="text-end" style="min-width: 100px;">
                                    <div class="small text-muted">${createdDate}</div>
                                </div>
                            </div>
                        </div>
                    `;
                });
            });
            
            html += '</div>';
            resultsDiv.innerHTML = html;
            resultsDiv.style.display = 'block';
        }
        
        function escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

        function selectRelationCase(caseIdValue, caseTitel, customerName, status) {
            selectedRelationCaseId = caseIdValue;
            
            // Update preview
            const previewDiv = document.getElementById('selectedCasePreview');
            const titleDiv = document.getElementById('selectedCaseTitle');
            
            titleDiv.innerHTML = `
                <div class="d-flex align-items-center gap-2 mb-1">
                    <span class="badge bg-primary">#${caseIdValue}</span>
                    <strong>${escapeHtml(caseTitel)}</strong>
                    <span class="status-badge status-${status}">${status}</span>
                </div>
                ${customerName ? `<div class="small"><i class="bi bi-building me-1"></i>${escapeHtml(customerName)}</div>` : ''}
            `;
            
            previewDiv.style.display = 'block';
            document.getElementById('relationSearchResults').innerHTML = '';
            document.getElementById('relationSearchResults').style.display = 'none';
            document.getElementById('relationCaseSearch').value = '';
            
            // Enable add button
            updateAddRelationButton();
        }
        
        function clearSelectedRelationCase() {
            selectedRelationCaseId = null;
            document.getElementById('selectedCasePreview').style.display = 'none';
            document.getElementById('relationCaseSearch').value = '';
            document.getElementById('relationCaseSearch').focus();
            updateAddRelationButton();
        }
        
        function updateAddRelationButton() {
            const btn = document.getElementById('addRelationBtn');
            const relationType = document.getElementById('relationTypeSelect').value;
            btn.disabled = !selectedRelationCaseId || !relationType;
        }

        async function addRelation() {
            const relationType = document.getElementById('relationTypeSelect').value;
            const btn = document.getElementById('addRelationBtn');
            
            if (!selectedRelationCaseId) {
                alert('Vælg en sag først');
                return;
            }
            
            if (!relationType) {
                alert('Vælg en relationstype');
                return;
            }
            
            // Disable button during request
            btn.disabled = true;
            btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Tilføjer...';
            
            try {
                const response = await fetch(`/api/v1/sag/${caseId}/relationer`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({
                        målsag_id: selectedRelationCaseId,
                        relationstype: relationType
                    })
                });
                
                if (response.ok) {
                    selectedRelationCaseId = null;
                    relationModal.hide();
                    window.location.reload();
                } else {
                    const error = await response.json();
                    alert(`Fejl: ${error.detail}`);
                    btn.disabled = false;
                    btn.innerHTML = '<i class="bi bi-plus-circle me-1"></i> Tilføj relation';
                }
            } catch (err) {
                alert('Fejl ved tilføjelse af relation: ' + err.message);
                btn.disabled = false;
                btn.innerHTML = '<i class="bi bi-plus-circle me-1"></i> Tilføj relation';
            }
        }

        async function deleteRelation(relationId) {
            if (confirm('Fjern denne relation?')) {
                const response = await fetch(`/api/v1/sag/${caseId}/relationer/${relationId}`, {method: 'DELETE'});
                if (response.ok) {
                    window.location.reload();
                } else {
                    alert('Fejl ved fjernelse af relation');
                }
            }
        }

        // ============ Hardware Handling ============
        async function loadCaseHardware() {
            try {
                const res = await fetch(`/api/v1/sag/{{ case.id }}/hardware`);
                if (!res.ok) {
                    let message = 'Kunne ikke hente hardware.';
                    try {
                        const err = await res.json();
                        if (err?.detail) {
                            message = err.detail;
                        }
                    } catch (_) {
                    }
                    throw new Error(message);
                }
                const hardware = await res.json();
                if (!Array.isArray(hardware)) {
                    throw new Error('Uventet svar fra serveren ved hardware-hentning.');
                }
                const container = document.getElementById('hardware-list');
                
                if (hardware.length === 0) {
                    container.innerHTML = '<div class="p-3 text-center text-muted small">Ingen hardware tilknyttet</div>';
                    setModuleContentState('hardware', false);
                    return;
                }
                
                container.innerHTML = `
                    <div class="hardware-list-header">
                        <span>Enhed</span>
                        <span>SN</span>
                        <span>Label</span>
                        <span>Slet</span>
                    </div>
                    ${hardware.map(h => `
                        <div class="hardware-row">
                            <div>
                                <a href="/hardware/${h.id}" class="text-decoration-none fw-semibold">
                                    ${h.brand} ${h.model}
                                </a>
                            </div>
                            <small>${h.serial_number || '-'}</small>
                            <button class="btn btn-sm btn-outline-primary" onclick="sendCaseHardwareLabelsToPrinter(${h.id})" title="Print label for denne hardware">
                                <i class="bi bi-printer"></i>
                            </button>
                            <button class="btn btn-sm btn-delete" onclick="unlinkHardware(${h.id})" title="Slet">
                                ✕
                            </button>
                        </div>
                    `).join('')}
                `;
                setModuleContentState('hardware', true);
            } catch (e) {
                console.error("Error loading hardware:", e);
                const message = (e?.message || '').trim() || 'Fejl ved hentning';
                document.getElementById('hardware-list').innerHTML = `<div class="p-3 text-danger text-center">${escapeHtml(message)}</div>`;
                setModuleContentState('hardware', true);
            }
        }

        async function promptLinkHardware() {
            const id = prompt("Indtast Hardware ID:");
            if (!id) return;
            
            try {
                const res = await fetch(`/api/v1/sag/{{ case.id }}/hardware`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ hardware_id: parseInt(id) })
                });
                
                if (!res.ok) throw await res.json();
                loadCaseHardware();
            } catch (e) {
                alert("Fejl: " + (e.detail || e.message));
            }
        }

        async function unlinkHardware(hwId) {
            if(!confirm("Fjern link til dette hardware?")) return;
            try {
                await fetch(`/api/v1/sag/{{ case.id }}/hardware/${hwId}`, { method: 'DELETE' });
                loadCaseHardware();
            } catch (e) {
                alert("Fejl ved sletning");
            }
        }

        // ============ Location Handling ============
        async function loadCaseLocations() {
            try {
                const res = await fetch(`/api/v1/sag/{{ case.id }}/locations`);
                if (!res.ok) {
                    let message = 'Kunne ikke hente lokationer.';
                    try {
                        const err = await res.json();
                        if (err?.detail) {
                            message = err.detail;
                        }
                    } catch (_) {
                    }
                    throw new Error(message);
                }
                const locations = await res.json();
                if (!Array.isArray(locations)) {
                    throw new Error('Uventet svar fra serveren ved lokations-hentning.');
                }
                const container = document.getElementById('locations-list');
                
                if (locations.length === 0) {
                    container.innerHTML = '<div class="p-3 text-center text-muted small">Ingen lokationer tilknyttet</div>';
                    setModuleContentState('locations', false);
                    return;
                }
                
                container.innerHTML = `
                    <div class="location-list-header">
                        <span>Navn</span>
                        <span>Type</span>
                        <span>Slet</span>
                    </div>
                    ${locations.map(l => `
                        <div class="location-row">
                            <div class="fw-semibold">
                                <i class="bi bi-geo-alt me-1 text-secondary"></i>
                                ${l.name}
                            </div>
                            <small>${l.location_type || '-'}</small>
                            <button class="btn btn-sm btn-delete" onclick="unlinkLocation(${l.relation_id || l.id})" title="Slet">
                                ✕
                            </button>
                        </div>
                    `).join('')}
                `;
                setModuleContentState('locations', true);
            } catch (e) {
                console.error("Error loading locations:", e);
                const message = (e?.message || '').trim() || 'Fejl ved hentning';
                document.getElementById('locations-list').innerHTML = `<div class="p-3 text-danger text-center">${escapeHtml(message)}</div>`;
                setModuleContentState('locations', true);
            }
        }

        // ============ Wiki Handling ============
        async function loadCaseWiki(searchValue = '') {
            const container = document.getElementById('wiki-list');
            if (!container) return;

            if (!wikiCustomerId) {
                container.innerHTML = '<div class="p-3 text-center text-muted small">Ingen kunde tilknyttet</div>';
                setModuleContentState('wiki', false);
                return;
            }

            container.innerHTML = '<div class="p-3 text-center text-muted small">Henter wiki...</div>';

            const params = new URLSearchParams();
            const trimmed = (searchValue || '').trim();
            if (trimmed) {
                params.set('query', trimmed);
            } else {
                params.set('tag', wikiDefaultTag);
            }

            try {
                const res = await fetch(`/api/v1/wiki/customers/${wikiCustomerId}/pages?${params.toString()}`);
                if (!res.ok) {
                    throw new Error('Kunne ikke hente Wiki');
                }
                const payload = await res.json();
                if (payload.errors && payload.errors.length) {
                    container.innerHTML = '<div class="p-3 text-center text-danger small">Wiki API fejlede</div>';
                    setModuleContentState('wiki', true);
                    return;
                }

                const pages = Array.isArray(payload.pages) ? payload.pages : [];

                if (!pages.length) {
                    container.innerHTML = '<div class="p-3 text-center text-muted small">Ingen sider fundet</div>';
                    setModuleContentState('wiki', false);
                    return;
                }

                container.innerHTML = pages.map(page => {
                    const title = page.title || page.path || 'Wiki side';
                    const url = page.url || page.path || '#';
                    const safeUrl = url ? encodeURI(url) : '#';
                    return `
                        <a class="list-group-item list-group-item-action" href="${safeUrl}" target="_blank" rel="noopener">
                            <div class="fw-semibold">${escapeHtml(title)}</div>
                            <small class="text-muted">${escapeHtml(page.path || '')}</small>
                        </a>
                    `;
                }).join('');
                setModuleContentState('wiki', true);
            } catch (e) {
                console.error('Error loading Wiki:', e);
                container.innerHTML = '<div class="p-3 text-center text-danger small">Fejl ved hentning</div>';
                setModuleContentState('wiki', true);
            }
        }

        async function loadCaseTagsModule() {
            const moduleContainer = document.getElementById('case-tags-module');
            if (!moduleContainer) return;

            try {
                let tags = [];
                let usingLegacyCaseTags = false;

                const normalizeLegacyTags = (legacyTags) => (
                    Array.isArray(legacyTags)
                        ? legacyTags.map((row) => ({
                            id: row.id || row.tag_id,
                            name: row.tag_navn || row.name || 'Tag',
                            color: row.color || '#0f4c75',
                            icon: row.icon || 'bi-tag'
                        }))
                        : []
                );

                const loadLegacyTags = async () => {
                    const legacyResponse = await fetch(`/api/v1/sag/${caseId}/tags`, { credentials: 'include' });
                    if (!legacyResponse.ok) {
                        throw new Error('Kunne ikke hente tags');
                    }
                    const legacyTags = await legacyResponse.json();
                    usingLegacyCaseTags = true;
                    return normalizeLegacyTags(legacyTags);
                };

                const response = await fetch(`/api/v1/tags/entity/case/${caseId}`, { credentials: 'include' });
                if (response.ok) {
                    const genericTags = await response.json();
                    tags = Array.isArray(genericTags) ? genericTags : [];
                    // Some hubs still store case tags via legacy sag endpoint.
                    if (tags.length === 0) {
                        tags = await loadLegacyTags();
                    }
                } else {
                    tags = await loadLegacyTags();
                }

                // Final fallback: use server-rendered tags from page context when API calls return empty.
                if ((!Array.isArray(tags) || tags.length === 0) && Array.isArray(initialCaseTagsSnapshot) && initialCaseTagsSnapshot.length > 0) {
                    tags = normalizeLegacyTags(initialCaseTagsSnapshot);
                    usingLegacyCaseTags = true;
                }

                if (!Array.isArray(tags) || tags.length === 0) {
                    moduleContainer.innerHTML = '<div class="p-3 text-center text-muted small">Ingen tags paaa sagen endnu</div>';
                    setModuleContentState('tags', false);
                    return;
                }

                moduleContainer.innerHTML = tags.map((tag) => `
                    <span class="badge me-1 mb-1" style="background-color: ${tag.color};">
                        ${tag.icon ? `<i class="bi ${tag.icon}"></i> ` : ''}${escapeHtml(tag.name)}
                        ${tag.id ? `<button type="button" class="btn-close btn-close-white btn-sm ms-1"
                                onclick="removeCaseTagAndSync(${tag.id})"
                                style="font-size: 0.6rem; vertical-align: middle;"></button>` : ''}
                    </span>
                `).join('');

                if (usingLegacyCaseTags) {
                    moduleContainer.insertAdjacentHTML(
                        'beforeend',
                        '<div class="small text-muted mt-2">Viser tags via sag-endpoint</div>'
                    );
                }

                setModuleContentState('tags', true);
            } catch (error) {
                console.error('Error loading case tags module:', error);
                moduleContainer.innerHTML = '<div class="p-3 text-center text-danger small">Fejl ved hentning af tags</div>';
                setModuleContentState('tags', true);
            }
        }

        async function loadCaseTagSuggestions() {
            const suggestionsContainer = document.getElementById('case-tag-suggestions');
            if (!suggestionsContainer) return;

            try {
                const response = await fetch(`/api/v1/tags/entity/case/${caseId}/suggestions`, { credentials: 'include' });
                if (!response.ok) throw new Error('Kunne ikke hente forslag');

                const suggestions = await response.json();
                if (!Array.isArray(suggestions) || suggestions.length === 0) {
                    suggestionsContainer.innerHTML = '<div class="text-muted small">Ingen nye forslag lige nu</div>';
                    return;
                }

                suggestionsContainer.innerHTML = `<div class="d-flex flex-wrap gap-1">${suggestions.slice(0, 8).map((item) => {
                    const tag = item.tag || {};
                    const matched = Array.isArray(item.matched_words) ? item.matched_words.join(', ') : '';
                    const hint = matched ? `Match: ${escapeHtml(matched)}` : 'Tilfoej tag';
                    return `
                        <button class="btn btn-sm btn-outline-primary d-inline-flex align-items-center gap-1 px-2 py-0"
                                type="button"
                                onclick="applySuggestedCaseTag(${Number(tag.id)})"
                                title="${hint}"
                                aria-label="${hint}"
                                style="height: 22px; line-height: 1; font-size: 0.72rem; border-radius: 999px; max-width: 100%;">
                            <span class="text-truncate" style="max-width: 150px;">${tag.icon ? `<i class="bi ${tag.icon}"></i> ` : ''}${escapeHtml(tag.name || 'Tag')}</span>
                            <span class="d-inline-flex align-items-center justify-content-center rounded-circle" style="width: 14px; height: 14px; background: ${tag.color || '#0f4c75'}; color: #fff; font-size: 0.6rem;">
                                <i class="bi bi-plus-lg"></i>
                            </span>
                        </button>
                    `;
                }).join('')}</div>`;
            } catch (error) {
                console.error('Error loading tag suggestions:', error);
                suggestionsContainer.innerHTML = '<div class="text-danger small">Fejl ved forslag</div>';
            }
        }

        async function applySuggestedCaseTag(tagId) {
            if (!tagId) return;
            try {
                const response = await fetch('/api/v1/tags/entity', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    credentials: 'include',
                    body: JSON.stringify({ entity_type: 'case', entity_id: caseId, tag_id: tagId })
                });

                if (!response.ok) {
                    const error = await response.json().catch(() => ({}));
                    throw new Error(error.detail || 'Kunne ikke tilfoeje tag');
                }

                const addResult = await response.json().catch(() => ({}));
                if (addResult && addResult.action) {
                    window.dispatchEvent(new CustomEvent('hub:tag-action', {
                        detail: {
                            action: addResult.action,
                            entity_type: 'case',
                            entity_id: caseId,
                        }
                    }));
                }

                await syncCaseTagsUi();
                if (typeof showNotification === 'function') {
                    showNotification('Tag tilfoejet', 'success');
                }
            } catch (error) {
                alert('Fejl: ' + error.message);
            }
        }

        async function removeCaseTagAndSync(tagId) {
            try {
                if (window.removeEntityTag) {
                    await window.removeEntityTag('case', caseId, tagId, 'case-tags-module');
                } else {
                    const legacyResponse = await fetch(`/api/v1/sag/${caseId}/tags/${tagId}`, {
                        method: 'DELETE',
                        credentials: 'include'
                    });
                    if (!legacyResponse.ok) {
                        throw new Error('Kunne ikke slette tag');
                    }
                }
            } catch (error) {
                const legacyResponse = await fetch(`/api/v1/sag/${caseId}/tags/${tagId}`, {
                    method: 'DELETE',
                    credentials: 'include'
                });
                if (!legacyResponse.ok) {
                    throw error;
                }
            }
            await syncCaseTagsUi();
        }

        async function syncCaseTagsUi() {
            if (window.renderEntityTags && document.getElementById('case-tags')) {
                await window.renderEntityTags('case', caseId, 'case-tags');
            }
            await loadCaseTagsModule();
            await loadCaseTagSuggestions();
        }

        async function createCaseBuzzwordFromText(rawText) {
            const text = String(rawText || '').trim();
            if (!text) {
                throw new Error('Ingen tekst at oprette buzzword fra');
            }

            const response = await fetch(`/api/v1/sag/${caseId}/buzzwords`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                credentials: 'include',
                body: JSON.stringify({ buzzword: text })
            });

            if (!response.ok) {
                const error = await response.json().catch(() => ({}));
                throw new Error(error.detail || 'Kunne ikke oprette buzzword');
            }

            await loadCaseBuzzwordsModule();
        }

        async function loadCaseBuzzwordsModule() {
            const moduleContainer = document.getElementById('case-buzzwords-module');
            if (!moduleContainer) return;

            try {
                let items = [];
                const response = await fetch(`/api/v1/sag/${caseId}/buzzwords`, { credentials: 'include' });
                if (response.ok) {
                    const payload = await response.json();
                    items = Array.isArray(payload) ? payload : [];
                }

                if ((!Array.isArray(items) || items.length === 0) && Array.isArray(initialCaseBuzzwordsSnapshot) && initialCaseBuzzwordsSnapshot.length > 0) {
                    items = initialCaseBuzzwordsSnapshot;
                }

                if (!Array.isArray(items) || items.length === 0) {
                    moduleContainer.innerHTML = '<div class="p-2 text-muted small">Ingen buzzwords paa sagen endnu</div>';
                    setModuleContentState('buzzwords', false);
                    return;
                }

                moduleContainer.innerHTML = items.map((item) => `
                    <span class="badge bg-warning text-dark me-1 mb-1">
                        <i class="bi bi-lightbulb"></i> ${escapeHtml(item.word || '')}
                        <button type="button" class="btn-close btn-close-black btn-sm ms-1"
                                onclick="removeCaseBuzzwordAndSync(${Number(item.buzzword_id || 0)})"
                                style="font-size: 0.6rem; vertical-align: middle;"
                                title="Fjern buzzword"></button>
                    </span>
                `).join('');

                setModuleContentState('buzzwords', true);
            } catch (error) {
                console.error('Error loading case buzzwords:', error);
                moduleContainer.innerHTML = '<div class="p-2 text-danger small">Fejl ved hentning af buzzwords</div>';
                setModuleContentState('buzzwords', true);
            }
        }

        async function createCaseBuzzwordFromInput() {
            const input = document.getElementById('case-buzzword-input');
            if (!input) return;

            try {
                await createCaseBuzzwordFromText(input.value);
                input.value = '';
                if (typeof showNotification === 'function') {
                    showNotification('Buzzword tilfoejet', 'success');
                }
            } catch (error) {
                if (typeof showNotification === 'function') {
                    showNotification(error.message || 'Kunne ikke oprette buzzword', 'error');
                }
            }
        }

        function getCurrentBuzzwordSelectionText() {
            const liveSelection = String(window.getSelection ? window.getSelection().toString() : '').trim();
            if (liveSelection) {
                return liveSelection;
            }

            const descTextarea = document.getElementById('beskrivelse-textarea');
            if (descTextarea) {
                const start = Number(descTextarea.selectionStart);
                const end = Number(descTextarea.selectionEnd);
                if (Number.isFinite(start) && Number.isFinite(end) && end > start) {
                    return String(descTextarea.value || '').slice(start, end).trim();
                }
            }

            return '';
        }

        async function createCaseBuzzwordFromCurrentSelection() {
            const selectedText = getCurrentBuzzwordSelectionText();
            if (!selectedText) {
                if (typeof showNotification === 'function') {
                    showNotification('Marker tekst foerst, og tryk derefter Opret markering', 'warning');
                }
                return;
            }

            try {
                await createCaseBuzzwordFromText(selectedText);
                if (typeof showNotification === 'function') {
                    showNotification('Buzzword oprettet fra markering', 'success');
                }
            } catch (error) {
                if (typeof showNotification === 'function') {
                    showNotification(error.message || 'Kunne ikke oprette buzzword', 'error');
                }
            }
        }

        async function removeCaseBuzzwordAndSync(buzzwordId) {
            const numericBuzzwordId = Number(buzzwordId || 0);
            if (!numericBuzzwordId) return;

            try {
                const response = await fetch(`/api/v1/sag/${caseId}/buzzwords/${numericBuzzwordId}`, {
                    method: 'DELETE',
                    credentials: 'include'
                });
                if (!response.ok) {
                    const error = await response.json().catch(() => ({}));
                    throw new Error(error.detail || 'Kunne ikke fjerne buzzword');
                }

                await loadCaseBuzzwordsModule();
            } catch (error) {
                if (typeof showNotification === 'function') {
                    showNotification(error.message || 'Kunne ikke fjerne buzzword', 'error');
                }
            }
        }

        window.syncCaseTagsUi = syncCaseTagsUi;
        window.createCaseBuzzwordFromInput = createCaseBuzzwordFromInput;
        window.createCaseBuzzwordFromCurrentSelection = createCaseBuzzwordFromCurrentSelection;
        window.removeCaseBuzzwordAndSync = removeCaseBuzzwordAndSync;

        let todoUserId = null;

        function getTodoUserId() {
            if (todoUserId) return todoUserId;
            const token = localStorage.getItem('access_token') || sessionStorage.getItem('access_token');
            if (token) {
                try {
                    const payload = JSON.parse(atob(token.split('.')[1]));
                    todoUserId = payload.sub || payload.user_id;
                    return todoUserId;
                } catch (e) {
                    console.warn('Could not decode token for todo user_id');
                }
            }
            const metaTag = document.querySelector('meta[name="user-id"]');
            if (metaTag) {
                todoUserId = metaTag.getAttribute('content');
            }
            return todoUserId;
        }

        function formatTodoDate(value) {
            if (!value) return '-';
            const date = new Date(value);
            if (Number.isNaN(date.getTime())) return '-';
            return date.toLocaleDateString('da-DK');
        }

        function formatTodoDateTime(value) {
            if (!value) return '-';
            const date = new Date(value);
            if (Number.isNaN(date.getTime())) return '-';
            return date.toLocaleString('da-DK', { hour: '2-digit', minute: '2-digit', hour12: false });
        }

        function getNextTodoOverrideStorageKey() {
            return `case:${caseId}:nextTodoStepId`;
        }

        function getNextTodoOverrideId() {
            const raw = localStorage.getItem(getNextTodoOverrideStorageKey());
            const parsed = Number(raw);
            return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
        }

        function setNextTodoOverrideId(stepIdOrNull) {
            const key = getNextTodoOverrideStorageKey();
            if (stepIdOrNull === null || stepIdOrNull === undefined) {
                localStorage.removeItem(key);
                return;
            }
            localStorage.setItem(key, String(stepIdOrNull));
        }

        function renderTodoSteps(steps) {
            const list = document.getElementById('todo-steps-list');
            if (!list) return;

            updateTopbarNextTodo(steps || []);

            const escapeAttr = (value) => String(value ?? '')
                .replace(/&/g, '&amp;')
                .replace(/"/g, '&quot;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;');

            if (!steps || steps.length === 0) {
                list.innerHTML = '<div class="p-3 text-center text-muted">Ingen opgaver endnu</div>';
                setModuleContentState('todo-steps', false);
                return;
            }

            const openSteps = steps.filter(step => !step.is_done);
            const doneSteps = steps.filter(step => step.is_done);
            const nextOverrideId = getNextTodoOverrideId();

            const renderStep = (step) => {
                const createdBy = step.created_by_name || 'Ukendt';
                const completedBy = step.completed_by_name || 'Ukendt';
                const dueLabel = step.due_date ? formatTodoDate(step.due_date) : '-';
                const createdLabel = formatTodoDateTime(step.created_at);
                const completedLabel = step.completed_at ? formatTodoDateTime(step.completed_at) : null;
                const isNextEffective = !step.is_done && (!!step.is_next || (nextOverrideId !== null && step.id === nextOverrideId));
                const statusBadge = step.is_done
                    ? '<span class="badge bg-success">Færdig</span>'
                    : `<span class="badge ${isNextEffective ? 'bg-primary' : 'bg-warning text-dark'}">${isNextEffective ? 'Næste' : 'Åben'}</span>`;
                const toggleLabel = step.is_done ? 'Genåbn' : 'Færdig';
                const toggleClass = step.is_done ? 'btn-outline-secondary' : 'btn-outline-success';
                const nextLabel = isNextEffective ? 'Fjern som næste' : 'Sæt som næste';
                const nextClass = isNextEffective ? 'btn-primary' : 'btn-outline-primary';
                const tooltipText = [
                    `Oprettet af: ${createdBy}`,
                    `Oprettet: ${createdLabel}`,
                    `Forfald: ${dueLabel}`,
                    isNextEffective ? 'Markeret som næste opgave' : null,
                    step.is_done && completedLabel ? `Færdiggjort af: ${completedBy}` : null,
                    step.is_done && completedLabel ? `Færdiggjort: ${completedLabel}` : null
                ].filter(Boolean).join('<br>');

                return `
                    <div class="list-group-item todo-step-item">
                        <div class="todo-step-title todo-step-header">
                            <div class="todo-step-left">
                                <span>${step.title}</span>
                                <button type="button" class="btn btn-outline-secondary todo-info-btn" data-bs-toggle="tooltip" data-bs-html="true" title="${escapeAttr(tooltipText)}" aria-label="Vis detaljer">
                                    <i class="bi bi-info"></i>
                                </button>
                            </div>
                            <div class="todo-step-right">
                                ${statusBadge}
                                <div class="todo-step-actions">
                                    ${!step.is_done ? `
                                    <button class="btn btn-sm ${nextClass}" onclick="setNextTodoStep(${step.id}, ${isNextEffective ? 'false' : 'true'})" title="${nextLabel}" aria-label="${nextLabel}">
                                        <i class="bi bi-arrow-up"></i>
                                    </button>
                                    ` : ''}
                                    <button class="btn btn-sm ${toggleClass}" onclick="toggleTodoStep(${step.id}, ${step.is_done ? 'false' : 'true'})" title="${toggleLabel}" aria-label="${toggleLabel}">
                                        <i class="bi ${step.is_done ? 'bi-arrow-counterclockwise' : 'bi-check2'}"></i>
                                    </button>
                                    <button class="btn btn-sm btn-outline-danger" onclick="deleteTodoStep(${step.id})" title="Slet" aria-label="Slet">
                                        <i class="bi bi-trash"></i>
                                    </button>
                                </div>
                            </div>
                        </div>
                        ${step.description ? `<div class="small text-muted">${step.description}</div>` : ''}
                        <div class="todo-step-meta">
                            <span class="meta-pill">Forfald: ${dueLabel}</span>
                        </div>
                    </div>
                `;
            };

            const sections = [];
            if (openSteps.length) {
                sections.push(`
                    <div class="todo-section-header">Åbne (${openSteps.length})</div>
                    ${openSteps.map(renderStep).join('')}
                `);
            }
            if (doneSteps.length) {
                sections.push(`
                    <div class="todo-section-header">Færdige (${doneSteps.length})</div>
                    ${doneSteps.map(renderStep).join('')}
                `);
            }

            list.innerHTML = sections.join('');
            if (window.bootstrap) {
                list.querySelectorAll('[data-bs-toggle="tooltip"]').forEach((el) => {
                    bootstrap.Tooltip.getOrCreateInstance(el, {
                        trigger: 'hover focus',
                        placement: 'left',
                        container: 'body',
                        html: true
                    });
                });
            }
            setModuleContentState('todo-steps', true);
        }

        function updateTopbarNextTodo(steps) {
            const valueEl = document.getElementById('topbarNextTodoValue');
            const metaEl = document.getElementById('topbarNextTodoMeta');
            if (!valueEl || !metaEl) return;

            const openSteps = Array.isArray(steps) ? steps.filter((step) => !step.is_done) : [];
            if (!openSteps.length) {
                valueEl.textContent = 'Ingen åbne todo-opgaver';
                metaEl.textContent = 'Alt er færdigt';
                setNextTodoOverrideId(null);
                applyTopbarImportanceBubbles();
                return;
            }

            const nextOverrideId = getNextTodoOverrideId();
            const overrideStep = nextOverrideId ? openSteps.find((step) => step.id === nextOverrideId) : null;
            const nextStep = overrideStep || openSteps.find((step) => !!step.is_next) || openSteps[0];

            if (!overrideStep && nextOverrideId) {
                setNextTodoOverrideId(null);
            }

            valueEl.textContent = nextStep.title || 'Untitled todo';
            metaEl.textContent = nextStep.due_date
                ? `Forfald: ${formatTodoDate(nextStep.due_date)}`
                : 'Ingen forfaldsdato';

            applyTopbarImportanceBubbles();
        }

        function parseIsoDateToDay(value) {
            const str = String(value || '').trim();
            if (!str) return null;
            const d = new Date(str + 'T00:00:00');
            if (Number.isNaN(d.getTime())) return null;
            return d;
        }

        function dayDiffFromToday(dateObj) {
            if (!dateObj) return null;
            const today = new Date();
            today.setHours(0, 0, 0, 0);
            return Math.round((dateObj.getTime() - today.getTime()) / 86400000);
        }

        function bubbleSeverityFromDate(rawValue, opts = {}) {
            const dateObj = parseIsoDateToDay(rawValue);
            if (!dateObj) return opts.empty || 'sev-neutral';
            const diff = dayDiffFromToday(dateObj);
            const warnDays = Number(opts.warnDays || 2);
            if (diff < 0) return 'sev-critical';
            if (diff <= warnDays) return 'sev-warn';
            return 'sev-ok';
        }

        function applyTopbarImportanceBubbles() {
            const statusValue = String(document.getElementById('topbarStatusSelect')?.value || '').toLowerCase();
            const assigneeValue = String(document.getElementById('tabsAssignmentUserSelect')?.value || '').trim();
            const groupValue = String(document.getElementById('tabsAssignmentGroupSelect')?.value || '').trim();
            const typeValue = String(document.getElementById('topbarTypeSelect')?.value || '').toLowerCase();
            const priorityValue = String(document.getElementById('topbarPrioritySelect')?.value || '').toLowerCase();
            const startValue = String(document.getElementById('topbarStartDateInput')?.value || '').trim();
            const startBeforeValue = String(document.getElementById('topbarDeferredInput')?.value || '').trim();
            const deadlineValue = String(document.getElementById('topbarDeadlineInput')?.value || '').trim();

            const nextValue = String(document.getElementById('topbarNextTodoValue')?.textContent || '').trim().toLowerCase();
            const nextMeta = String(document.getElementById('topbarNextTodoMeta')?.textContent || '').trim().toLowerCase();

            const createdText = String(document.querySelector('.field-created .case-tabs-topbar-value')?.textContent || '').trim();
            let createdSeverity = 'sev-neutral';
            const createdMatch = createdText.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
            if (createdMatch) {
                const createdDate = new Date(Number(createdMatch[3]), Number(createdMatch[2]) - 1, Number(createdMatch[1]));
                const age = Math.abs(dayDiffFromToday(createdDate));
                if (age > 120) createdSeverity = 'sev-critical';
                else if (age > 45) createdSeverity = 'sev-warn';
                else createdSeverity = 'sev-ok';
            }

            let statusSeverity = 'sev-neutral';
            if (!statusValue) statusSeverity = 'sev-critical';
            else if (['lukket', 'løst', 'closed', 'resolved'].includes(statusValue)) statusSeverity = 'sev-ok';
            else if (['afventer', 'under behandling'].includes(statusValue)) statusSeverity = 'sev-warn';
            else statusSeverity = 'sev-warn';

            let nextSeverity = 'sev-neutral';
            if (nextValue.includes('henter')) {
                nextSeverity = 'sev-neutral';
            } else if (nextValue.includes('ingen åbne')) {
                nextSeverity = 'sev-warn';
            } else if (nextMeta.includes('forfald:')) {
                const metaDateMatch = nextMeta.match(/(\d{2})[./-](\d{2})[./-](\d{4})/);
                if (metaDateMatch) {
                    const due = new Date(Number(metaDateMatch[3]), Number(metaDateMatch[2]) - 1, Number(metaDateMatch[1]));
                    const diff = dayDiffFromToday(due);
                    if (diff < 0) nextSeverity = 'sev-critical';
                    else if (diff <= 2) nextSeverity = 'sev-warn';
                    else nextSeverity = 'sev-ok';
                } else {
                    nextSeverity = 'sev-warn';
                }
            } else {
                nextSeverity = 'sev-ok';
            }

            const fieldSeverity = {
                status: statusSeverity,
                assignee: assigneeValue ? 'sev-ok' : 'sev-critical',
                group: groupValue ? 'sev-ok' : 'sev-warn',
                next: nextSeverity,
                type: typeValue ? 'sev-ok' : 'sev-neutral',
                priority: priorityValue === 'urgent' ? 'sev-critical' : (priorityValue === 'high' ? 'sev-warn' : 'sev-ok'),
                created: createdSeverity,
                start: bubbleSeverityFromDate(startValue, { empty: 'sev-warn', warnDays: 0 }),
                start_before: bubbleSeverityFromDate(startBeforeValue, { empty: 'sev-neutral', warnDays: 2 }),
                deadline: bubbleSeverityFromDate(deadlineValue, { empty: 'sev-neutral', warnDays: 2 })
            };

            document.querySelectorAll('[data-field-bubble]').forEach((bubble) => {
                const key = String(bubble.getAttribute('data-field-bubble') || '').trim();
                const sev = fieldSeverity[key] || 'sev-neutral';
                bubble.classList.remove('sev-neutral', 'sev-ok', 'sev-warn', 'sev-critical');
                bubble.classList.add(sev);
            });
        }

        async function setNextTodoStep(stepId, isNext) {
            try {
                const res = await fetch(`/api/v1/sag/todo-steps/${stepId}`, {
                    method: 'PATCH',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ is_next: isNext, is_done: false })
                });
                if (!res.ok) {
                    const error = await res.json().catch(() => ({}));
                    throw new Error(error.detail || 'Kunne ikke opdatere næste-opgave');
                }

                setNextTodoOverrideId(isNext ? stepId : null);
                await loadTodoSteps();
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        async function loadTodoSteps() {
            const list = document.getElementById('todo-steps-list');
            if (!list) return;
            list.innerHTML = '<div class="p-3 text-center text-muted">Henter opgaver...</div>';

            try {
                const res = await fetch(`/api/v1/sag/${caseId}/todo-steps`);
                if (!res.ok) throw new Error('Kunne ikke hente steps');
                const steps = await res.json();
                renderTodoSteps(steps || []);
            } catch (e) {
                console.error('Error loading todo steps:', e);
                list.innerHTML = '<div class="p-3 text-center text-danger">Fejl ved hentning</div>';
                setModuleContentState('todo-steps', true);
            }
        }

        function toggleTodoStepForm(forceOpen = null) {
            const form = document.getElementById('todoStepForm');
            const moduleCard = document.querySelector('[data-module="todo-steps"]');
            if (!form) return;

            const shouldOpen = forceOpen === null ? form.classList.contains('d-none') : Boolean(forceOpen);

            if (shouldOpen) {
                form.classList.remove('d-none');
                if (moduleCard) {
                    moduleCard.classList.remove('module-empty-compact');
                }
                const titleInput = document.getElementById('todoStepTitle');
                if (titleInput) {
                    titleInput.focus();
                }
            } else {
                form.classList.add('d-none');
                applyViewLayout(currentCaseView);
            }
        }

        async function createTodoStep(event) {
            event.preventDefault();
            const titleInput = document.getElementById('todoStepTitle');
            const descInput = document.getElementById('todoStepDescription');
            const dueInput = document.getElementById('todoStepDueDate');
            if (!titleInput) return;

            const title = titleInput.value.trim();
            if (!title) {
                alert('Titel er paakraevet');
                return;
            }

            const userId = getTodoUserId();
            if (!userId) {
                alert('Mangler bruger-id. Log ind igen.');
                return;
            }

            try {
                const res = await fetch(`/api/v1/sag/${caseId}/todo-steps?user_id=${userId}`,
                    {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({
                            title,
                            description: descInput.value.trim() || null,
                            due_date: dueInput.value || null
                        })
                    }
                );
                if (!res.ok) {
                    const err = await res.json();
                    throw new Error(err.detail || 'Kunne ikke oprette step');
                }
                titleInput.value = '';
                descInput.value = '';
                dueInput.value = '';
                await loadTodoSteps();
                toggleTodoStepForm(false);
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        async function toggleTodoStep(stepId, isDone) {
            const userId = getTodoUserId();
            if (!userId) {
                alert('Mangler bruger-id. Log ind igen.');
                return;
            }
            try {
                const res = await fetch(`/api/v1/sag/todo-steps/${stepId}?user_id=${userId}`,
                    {
                        method: 'PATCH',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ is_done: isDone })
                    }
                );
                if (!res.ok) throw new Error('Kunne ikke opdatere step');
                await loadTodoSteps();
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        async function deleteTodoStep(stepId) {
            if (!confirm('Slet dette step?')) return;
            try {
                const res = await fetch(`/api/v1/sag/todo-steps/${stepId}`, { method: 'DELETE' });
                if (!res.ok) throw new Error('Kunne ikke slette step');
                await loadTodoSteps();
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        async function promptLinkLocation() {
            const id = prompt("Indtast Lokations ID:");
            if (!id) return;
            
            try {
                const res = await fetch(`/api/v1/sag/{{ case.id }}/locations`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ location_id: parseInt(id) })
                });
                
                if (!res.ok) throw await res.json();
                loadCaseLocations();
            } catch (e) {
                alert("Fejl: " + (e.detail || e.message));
            }
        }

        async function unlinkLocation(locId) {
            if(!confirm("Fjern link til denne lokation?")) return;
            try {
                const res = await fetch(`/api/v1/sag/{{ case.id }}/locations/${locId}`, { method: 'DELETE' });
                if (!res.ok) {
                    const err = await res.json().catch(() => ({}));
                    throw new Error(err.detail || 'Kunne ikke fjerne lokation');
                }
                loadCaseLocations();
            } catch (e) {
                alert("Fejl ved sletning: " + (e.message || 'Ukendt fejl'));
            }
        }


        // Initialize relation search when DOM is ready
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', setupRelationSearch);
        } else {
            setupRelationSearch();
        }

        // Kontakt Modal functions
        function showKontaktModal() {
            const modal = new bootstrap.Modal(document.getElementById('kontaktModal'));
            modal.show();
        }

        // Afdeling Modal functions
        function showAfdelingModal() {
            const modal = new bootstrap.Modal(document.getElementById('afdelingModal'));
            modal.show();
        }

        async function updateAfdeling() {
            const newAfdeling = document.getElementById('afdelingInput').value.trim();
            
            try {
                const response = await fetch('/api/v1/customers/{{ customer.id if customer else 0 }}', {
                    method: 'PATCH',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ department: newAfdeling })
                });
                
                if (!response.ok) throw await response.json();
                
                // Reload page to show updated data
                window.location.reload();
            } catch (e) {
                alert("Fejl ved opdatering: " + (e.detail || e.message));
            }
        }
    </script>

    <!-- Tid & Fakturering Section (Moved from Right Column) -->
    <div class="card mt-3 right-module-card module-priority-high" data-module="time" data-has-content="{{ 'true' if time_entries else 'false' }}">
        <div class="card-header d-flex justify-content-between align-items-center">
            <div class="d-flex align-items-center">
                <h5 class="module-title"><i class="bi bi-clock-history module-icon"></i>Tid & Fakturering</h5>
            </div>
            <button class="btn btn-sm btn-outline-primary" onclick="showAddTimeModal()">
                <i class="bi bi-fullscreen me-1"></i>Fuld Formular
            </button>
        </div>
        <div class="card-body">
            <!-- Quick Add Time Entry Form -->
            <div class="border rounded p-2 mb-2 bg-light" id="quickTimeFormContainer">
                <form id="quickAddTimeForm" onsubmit="quickAddTime(event); return false;">
                    <div class="row g-1 align-items-end">
                        <div class="col-md-2 col-6">
                            <label for="quickTimeDate" class="form-label small mb-1">Dato</label>
                            <input type="date" class="form-control form-control-sm" id="quickTimeDate" name="date"
                                   value="{{ today or '' }}" required>
                        </div>
                        <div class="col-md-1 col-3">
                            <label for="quickTimeHours" class="form-label small mb-1">Timer</label>
                            <input type="number" class="form-control form-control-sm" id="quickTimeHours" name="hours"
                                   min="0" max="23" value="0" required>
                        </div>
                        <div class="col-md-1 col-3">
                            <label for="quickTimeMinutes" class="form-label small mb-1">Min</label>
                            <input type="number" class="form-control form-control-sm" id="quickTimeMinutes" name="minutes"
                                   min="0" max="59" step="15" value="0" required>
                        </div>
                        <div class="col-md-3 col-6">
                            <label for="quickTimeBillingMethod" class="form-label small mb-1">Afregning</label>
                            <select class="form-select form-select-sm" id="quickTimeBillingMethod" name="billing_method">
                                <option value="invoice" selected>Faktura</option>
                                {% if prepaid_cards %}
                                <optgroup label="Klippekort">
                                    {% for card in prepaid_cards %}
                                    <option value="card_{{ card.id }}">💳 Kort #{{ card.card_number or card.id }} ({{ '%.2f' % card.remaining_hours }}t)</option>
                                    {% endfor %}
                                </optgroup>
                                {% endif %}
                                {% if fixed_price_agreements %}
                                <optgroup label="Fastpris">
                                    {% for agr in fixed_price_agreements %}
                                    <option value="fpa_{{ agr.id }}">📋 #{{ agr.agreement_number }} ({{ '%.1f' % agr.remaining_hours_this_month }}t)</option>
                                    {% endfor %}
                                </optgroup>
                                {% endif %}
                                <option value="internal">Internt</option>
                                <option value="warranty">Garanti</option>
                            </select>
                        </div>
                        <div class="col-md-4 col-12">
                            <label for="quickTimeDescription" class="form-label small mb-1">Beskrivelse</label>
                            <input type="text" class="form-control form-control-sm" id="quickTimeDescription" name="description"
                                   placeholder="Hvad har du lavet?" required>
                        </div>
                        <div class="col-md-1 col-12 d-flex align-items-end">
                            <button type="submit" class="btn btn-primary btn-sm w-100">
                                <i class="bi bi-plus-lg me-0"></i>
                            </button>
                        </div>
                    </div>
                </form>
            </div>

            <!-- Time Entries Table -->
            <div class="table-responsive">
                <table class="table table-hover mb-0">
                    <thead class="table-light">
                        <tr>
                            <th>Dato</th>
                            <th>Beskrivelse</th>
                            <th>Bruger</th>
                            <th class="text-end">Timer</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for entry in time_entries %}
                        <tr>
                            <td>{{ entry.worked_date }}</td>
                            <td>{{ entry.description or '-' }}</td>
                            <td>{{ entry.user_name }}</td>
                            <td class="text-end fw-bold">{{ entry.original_hours }}</td>
                        </tr>
                        {% else %}
                        <tr>
                            <td colspan="4" class="text-center py-3 text-muted">
                                <i class="bi bi-inbox me-2"></i>Ingen tid registreret endnu
                            </td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>

            <!-- Prepaid Cards Info -->
            {% if prepaid_cards %}
            <div class="border-top mt-3 pt-3">
                <h6 class="mb-2"><i class="bi bi-credit-card me-1"></i>Aktive Klippekort</h6>
                <div class="row g-2">
                    {% for card in prepaid_cards %}
                    <div class="col-md-3">
                        <div class="border rounded p-2 bg-light">
                            <div class="small text-muted">Kort #{{ card.card_number or card.id }}</div>
                            <div class="fw-bold text-primary">{{ '%.2f' % card.remaining_hours }} timer tilbage</div>
                        </div>
                    </div>
                    {% endfor %}
                </div>
            </div>
            {% endif %}
        </div>
    </div>
    
    </div> <!-- /#inner-center-col -->
</div> <!-- /.row.g-4 (inner) -->
</div> <!-- /#case-left-column -->
<div class="col-xl-4 col-lg-4" id="case-right-column">
        <div class="right-modules-grid">
            <div class="card h-100 d-flex flex-column right-module-card module-priority-normal" data-module="locations" data-has-content="unknown">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="module-title"><i class="bi bi-geo-alt-fill module-icon"></i>Lokationer</h6>
                    <button class="btn btn-sm btn-outline-primary" onclick="openSearchModal('location')">
                        <i class="bi bi-plus-lg"></i>
                    </button>
                </div>
                <div class="card-body flex-grow-1 overflow-auto p-0" style="max-height: 180px;">
                    <div class="list-group list-group-flush" id="locations-list">
                        <div class="p-3 text-center text-muted">Henter lokationer...</div>
                    </div>
                </div>
            </div>

                <div class="card h-100 d-flex flex-column right-module-card module-priority-low" data-module="tags" data-has-content="unknown">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="module-title"><i class="bi bi-tags-fill module-icon"></i>TAGS</h6>
                        <button type="button" class="btn btn-sm btn-outline-primary"
                            onclick="event.stopPropagation(); window.showTagPicker('case', {{ case.id }}, (tag, addResult) => { syncCaseTagsUi(); const actionType = addResult && addResult.action ? addResult.action.type : null; const shouldOpenTemplateModal = actionType === 'open_task_template_modal' || String((tag && tag.name) || '').toLowerCase() === 'opgave_template'; if (shouldOpenTemplateModal && typeof window.openTaskTemplateSelectorModal === 'function') { window.openTaskTemplateSelectorModal({ action: addResult ? addResult.action : null, entity_type: 'case', entity_id: {{ case.id }} }); } }); return false;"
                            title="Tilføj tag">
                        <i class="bi bi-plus-lg"></i>
                    </button>
                </div>
                <div class="card-body" style="max-height: 240px; overflow: auto;">
                    <div id="case-tags-module" class="mb-2">
                        {% if tags and tags|length > 0 %}
                            {% for tag in tags %}
                            <span class="badge me-1 mb-1" style="background-color: #0f4c75;">
                                <i class="bi bi-tag"></i> {{ tag.tag_navn or tag.name or 'Tag' }}
                            </span>
                            {% endfor %}
                        {% else %}
                            <div class="p-2 text-muted small">Ingen tags paa sagen endnu</div>
                        {% endif %}
                    </div>
                    <div class="border-top pt-1">
                        <div class="small text-muted fw-semibold mb-1">Forslag</div>
                        <div id="case-tag-suggestions" style="max-height: 72px; overflow: auto;">
                            <div class="text-muted small">Indlaeser forslag...</div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="card h-100 d-flex flex-column right-module-card module-priority-normal" data-module="customers" data-has-content="{{ 'true' if customers else 'false' }}">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="module-title"><i class="bi bi-building-fill module-icon"></i>Kunder</h6>
                    <button class="btn btn-sm btn-outline-primary" onclick="openSearchModal('customer')">
                        <i class="bi bi-plus-lg"></i>
                    </button>
                </div>
                <div class="card-body flex-grow-1 overflow-auto" id="customers-container" style="max-height: 180px;">
                    {% if customers %}
                    <div class="customer-list-header">
                        <span>Navn</span>
                        <span>Rolle</span>
                        <span>E-mail</span>
                        <span>Slet</span>
                    </div>
                    {% for customer in customers %}
                    <div class="customer-row">
                        <div>
                            <a href="/customers/{{ customer.customer_id }}" class="text-decoration-none fw-semibold">
                                {{ customer.customer_name }}
                            </a>
                        </div>
                        <small>{{ customer.role or '-' }}</small>
                        <small>{{ customer.customer_email or '-' }}</small>
                        <button onclick="removeCustomer({{ case.id }}, {{ customer.customer_id }})" class="btn btn-sm btn-delete" title="Slet">✕</button>
                    </div>
                    {% endfor %}
                    {% else %}
                    <p class="text-muted text-center">Ingen kunder</p>
                    {% endif %}
                </div>
            </div>

            <div class="card h-100 d-flex flex-column right-module-card module-priority-low" data-module="buzzwords" data-has-content="{{ 'true' if buzzwords and buzzwords|length > 0 else 'false' }}">
                <div class="card-header d-flex justify-content-between align-items-start gap-2 flex-wrap">
                    <h6 class="module-title mb-0"><i class="bi bi-lightbulb-fill module-icon"></i>Buzzwords</h6>
                    <div class="d-flex align-items-center gap-1 flex-nowrap" style="max-width: 100%;">
                        <input
                            type="text"
                            id="case-buzzword-input"
                            class="form-control form-control-sm"
                            maxlength="120"
                            placeholder="Buzzword"
                            aria-label="Tilfoej buzzword"
                            style="width: 140px; height: 26px; min-height: 26px; padding-top: 0.1rem; padding-bottom: 0.1rem;"
                        >
                        <button class="btn btn-sm btn-outline-primary" type="button" onclick="createCaseBuzzwordFromInput()" title="Opret buzzword" aria-label="Opret buzzword" style="height: 26px; min-height: 26px; padding: 0.1rem 0.35rem; line-height: 1;">
                            <i class="bi bi-plus-lg"></i>
                        </button>
                        <button class="btn btn-sm btn-outline-warning" type="button" onclick="createCaseBuzzwordFromCurrentSelection()" title="Opret fra markering" aria-label="Opret fra markering" style="height: 26px; min-height: 26px; padding: 0.1rem 0.35rem; line-height: 1;">
                            <i class="bi bi-highlighter"></i>
                        </button>
                    </div>
                </div>
                <div class="card-body" style="max-height: 240px; overflow: auto;">
                    <div id="case-buzzwords-module">
                        {% if buzzwords and buzzwords|length > 0 %}
                            {% for item in buzzwords %}
                            <span class="badge bg-warning text-dark me-1 mb-1">
                                <i class="bi bi-lightbulb"></i> {{ item.word }}
                                <button type="button" class="btn-close btn-close-black btn-sm ms-1"
                                    onclick="removeCaseBuzzwordAndSync({{ item.buzzword_id }})"
                                    style="font-size: 0.6rem; vertical-align: middle;"
                                    title="Fjern buzzword"></button>
                            </span>
                            {% endfor %}
                        {% else %}
                            <div class="p-2 text-muted small">Ingen buzzwords paa sagen endnu</div>
                        {% endif %}
                    </div>
                </div>
            </div>

            <div class="card h-100 d-flex flex-column right-module-card module-priority-normal" data-module="contacts" data-has-content="{{ 'true' if contacts else 'false' }}">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="module-title"><i class="bi bi-people-fill module-icon"></i>Kontakter</h6>
                    <button class="btn btn-sm btn-outline-primary" onclick="openSearchModal('contact')">
                        <i class="bi bi-plus-lg"></i>
                    </button>
                </div>
                <div class="card-body flex-grow-1 overflow-auto" id="contacts-container" style="max-height: 180px;">
                    {% if contacts %}
                    <div class="contact-list-header">
                        <span>Navn</span>
                        <span>Titel</span>
                        <span>Kunde</span>
                        <span>Slet</span>
                    </div>
                    {% for contact in contacts %}
                    <div
                        class="contact-row"
                        role="button"
                        tabindex="0"
                        onclick="showContactInfoModal(this)"
                        data-contact-id="{{ contact.contact_id }}"
                        data-name="{{ contact.contact_name|replace('"', '&quot;') }}"
                        data-title="{{ contact.title|default('', true)|replace('"', '&quot;') }}"
                        data-company="{{ contact.customer_name|default('', true)|replace('"', '&quot;') }}"
                        data-email="{{ contact.contact_email|default('', true)|replace('"', '&quot;') }}"
                        data-phone="{{ contact.phone|default('', true)|replace('"', '&quot;') }}"
                        data-mobile="{{ contact.mobile|default('', true)|replace('"', '&quot;') }}"
                        data-role="{{ contact.role|default('Kontakt')|replace('"', '&quot;') }}"
                        data-is-primary="{{ 'true' if contact.is_primary else 'false' }}"
                    >
                        <div class="contact-name">{{ contact.contact_name }}</div>
                        <small>{{ contact.title or '-' }}</small>
                        <small>{{ contact.customer_name or '-' }}</small>
                        <button
                            class="btn btn-sm btn-delete"
                            onclick="event.stopPropagation(); removeContact({{ case.id }}, {{ contact.contact_id }})"
                            title="Slet"
                        >
                            ✕
                        </button>
                    </div>
                    {% endfor %}
                    {% else %}
                    <p class="text-muted text-center">Ingen kontakter</p>
                    {% endif %}
                </div>
            </div>

            <div class="card d-flex flex-column h-100 right-module-card module-priority-normal" data-module="hardware" data-has-content="unknown">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="module-title"><i class="bi bi-pc-display-horizontal module-icon"></i>Hardware</h6>
                    <div class="d-flex gap-2 align-items-center">
                        <button class="btn btn-sm btn-outline-secondary" onclick="sendCaseHardwareLabelsToPrinter()" title="Print labels for alt hardware på sagen">
                            <i class="bi bi-printer"></i>
                        </button>
                        <button class="btn btn-sm btn-outline-primary" onclick="openSearchModal('hardware')" title="Tilknyt hardware">
                            <i class="bi bi-link-45deg"></i>
                        </button>
                    </div>
                </div>
                <div class="card-body flex-grow-1 overflow-auto p-0" style="max-height: 180px;">
                    <div class="list-group list-group-flush" id="hardware-list">
                        <div class="p-3 text-center text-muted">Henter hardware...</div>
                    </div>
                </div>
            </div>

            <div class="card h-100 d-flex flex-column right-module-card module-priority-high" data-module="pipeline" data-has-content="{{ 'true' if case.pipeline_stage_id or case.pipeline_amount or case.pipeline_probability else 'false' }}">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="module-title"><i class="bi bi-graph-up-arrow module-icon"></i>Salgspipeline</h6>
                    <div class="d-flex gap-2">
                        <button id="pipelineCollapseToggle" class="btn btn-sm btn-outline-secondary" onclick="togglePipelineModule()" title="Vis/skjul pipeline">
                            <i id="pipelineCollapseIcon" class="bi bi-chevron-down"></i>
                        </button>
                        <button id="pipelineEditToggle" class="btn btn-sm btn-outline-primary" onclick="togglePipelineEdit()">
                            <i class="bi bi-pencil"></i>
                        </button>
                    </div>
                </div>
                <div id="pipelineCardBody" class="card-body d-none">
                    <div id="pipelineViewMode">
                        <div class="row g-3">
                            <div class="col-12">
                                <div class="summary-item h-100">
                                    <div class="summary-label">Stage</div>
                                    <div class="summary-value">
                                        {% set ns = namespace(selected_stage=None) %}
                                        {% for stage in pipeline_stages or [] %}
                                            {% if case.pipeline_stage_id == stage.id %}
                                                {% set ns.selected_stage = stage %}
                                            {% endif %}
                                        {% endfor %}
                                        {% if ns.selected_stage %}
                                            <span class="badge" style="background: {{ ns.selected_stage.color or '#0f4c75' }};">{{ ns.selected_stage.name }}</span>
                                        {% else %}
                                            <span class="text-muted">Ikke sat</span>
                                        {% endif %}
                                    </div>
                                </div>
                            </div>
                            <div class="col-6">
                                <div class="summary-item h-100">
                                    <div class="summary-label">Sandsynlighed</div>
                                    <div class="summary-value">{{ case.pipeline_probability if case.pipeline_probability is not none else 0 }}%</div>
                                </div>
                            </div>
                            <div class="col-6">
                                <div class="summary-item h-100">
                                    <div class="summary-label">Beløb</div>
                                    <div class="summary-value">
                                        {% if case.pipeline_amount is not none %}
                                            {{ "{:,.2f}".format(case.pipeline_amount|float).replace(',', 'X').replace('.', ',').replace('X', '.') }} kr.
                                        {% else %}
                                            <span class="text-muted">Ikke sat</span>
                                        {% endif %}
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="mt-3">
                            <div class="summary-item">
                                <div class="summary-label">Beskrivelse</div>
                                <div class="summary-value" style="white-space: pre-wrap;">{{ case.pipeline_description or 'Ingen beskrivelse' }}</div>
                            </div>
                        </div>
                    </div>

                    <div id="pipelineEditMode" class="d-none">
                        <div class="row g-3">
                            <div class="col-12">
                                <label class="form-label small text-muted">Stage</label>
                                <select id="pipelineStageSelect" class="form-select form-select-sm">
                                    <option value="">Ikke sat</option>
                                    {% for stage in pipeline_stages or [] %}
                                        <option value="{{ stage.id }}" {% if case.pipeline_stage_id == stage.id %}selected{% endif %}>{{ stage.name }}</option>
                                    {% endfor %}
                                </select>
                            </div>
                            <div class="col-6">
                                <label class="form-label small text-muted">Sandsynlighed (%)</label>
                                <input id="pipelineProbabilityInput" type="number" min="0" max="100" class="form-control form-control-sm" value="{{ case.pipeline_probability if case.pipeline_probability is not none else '' }}">
                            </div>
                            <div class="col-6">
                                <label class="form-label small text-muted">Beløb (kr.)</label>
                                <input id="pipelineAmountInput" type="number" min="0" step="0.01" class="form-control form-control-sm" value="{{ case.pipeline_amount if case.pipeline_amount is not none else '' }}">
                            </div>
                            <div class="col-12">
                                <label class="form-label small text-muted">Beskrivelse</label>
                                <textarea id="pipelineDescriptionInput" rows="3" class="form-control form-control-sm" placeholder="Skriv kort note for denne pipeline-entry...">{{ case.pipeline_description or '' }}</textarea>
                            </div>
                        </div>
                        <div class="d-flex justify-content-end gap-2 mt-3">
                            <button class="btn btn-sm btn-outline-secondary" onclick="togglePipelineEdit(false)">Annuller</button>
                            <button class="btn btn-sm btn-primary" onclick="savePipeline()">Gem pipeline</button>
                        </div>
                    </div>
                </div>
            </div>

            <div class="card h-100 d-flex flex-column right-module-card module-priority-critical" data-module="call-history" data-has-content="{{ 'true' if call_history else 'false' }}">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="module-title"><i class="bi bi-telephone-inbound-fill module-icon"></i>Opkaldshistorik</h6>
                    <a href="/telefoni" class="btn btn-sm btn-outline-primary">
                        <i class="bi bi-telephone"></i>
                    </a>
                </div>
                <div class="card-body p-0">
                    {% if call_history and call_history|length > 0 %}
                    <div class="table-responsive">
                        <table class="table table-sm table-hover mb-0 align-middle">
                            <thead>
                                <tr>
                                    <th class="ps-3">Dato</th>
                                    <th>Retning</th>
                                    <th>Nummer</th>
                                    <th>Bruger</th>
                                    <th class="text-end pe-3">Varighed</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for call in call_history %}
                                <tr>
                                    <td class="ps-3">{{ call.started_at.strftime('%d/%m/%Y %H:%M') if call.started_at else '-' }}</td>
                                    <td>{{ 'Udgående' if call.direction == 'outbound' else 'Indgående' }}</td>
                                    <td>
                                        {% if call.ekstern_nummer %}
                                        <div class="d-flex gap-2 align-items-center flex-wrap">
                                            <span>{{ call.ekstern_nummer }}</span>
                                            <button type="button" class="btn btn-sm btn-outline-success" onclick='ringOutFromCase({{ (call.ekstern_nummer or "")|tojson }})'>
                                                Ring op
                                            </button>
                                        </div>
                                        {% else %}
                                        -
                                        {% endif %}
                                    </td>
                                    <td>{{ call.full_name or call.username or '-' }}</td>
                                    <td class="text-end pe-3">
                                        {% if call.duration_sec is not none %}
                                            {{ (call.duration_sec // 60)|int }}:{{ '%02d'|format((call.duration_sec % 60)|int) }}
                                        {% elif call.ended_at %}
                                            -
                                        {% else %}
                                            I gang
                                        {% endif %}
                                    </td>
                                </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                    {% else %}
                    <div class="p-3 text-muted text-center">Ingen opkald linket til denne sag</div>
                    {% endif %}
                </div>
            </div>

            <div class="card h-100 d-flex flex-column right-module-card module-priority-high" data-module="todo-steps" data-has-content="unknown">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="module-title"><i class="bi bi-check2-square module-icon"></i>Todo-opgaver</h6>
                    <button class="btn btn-sm btn-outline-primary" type="button" onclick="toggleTodoStepForm()" title="Tilføj opgave">
                        <i class="bi bi-plus-lg"></i>
                    </button>
                </div>
                <div class="card-body p-0 d-flex flex-column" style="max-height: 260px;">
                    <form id="todoStepForm" class="p-3 border-bottom d-none">
                        <input type="text" class="form-control form-control-sm mb-2" id="todoStepTitle" placeholder="Opgavetitel" required>
                        <textarea class="form-control form-control-sm mb-2" id="todoStepDescription" rows="2" placeholder="Kort note (valgfri)"></textarea>
                        <div class="d-flex gap-2">
                            <input type="date" class="form-control form-control-sm" id="todoStepDueDate">
                            <button class="btn btn-sm btn-outline-primary" type="submit">Tilføj</button>
                        </div>
                    </form>
                    <div class="list-group list-group-flush flex-grow-1 overflow-auto" id="todo-steps-list">
                        <div class="p-3 text-center text-muted">Ingen opgaver endnu</div>
                    </div>
                </div>
            </div>

            <div class="card h-100 d-flex flex-column right-module-card module-priority-low" data-module="wiki" data-has-content="unknown">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="module-title"><i class="bi bi-journal-richtext module-icon"></i>Kunde-wiki</h6>
                </div>
                <div class="card-body flex-grow-1 p-0" style="max-height: 220px; overflow: auto;">
                    <div class="p-2 border-bottom">
                        <input type="text" class="form-control form-control-sm" id="wikiSearchInput" placeholder="Soeg i Wiki (tom = guide)" style="font-size: 0.8rem;">
                    </div>
                    <div class="list-group list-group-flush" id="wiki-list">
                        <div class="p-3 text-center text-muted">Henter wiki...</div>
                    </div>
                </div>
            </div>

        </div>
    </div>
    </div>
    </div> <!-- End Details Tab -->

    <script>
        (function () {
            function normalizeDetailsColumns() {
                const detailsPane = document.getElementById('details');
                if (!detailsPane) return;

                let detailsRow = null;
                try {
                    detailsRow = detailsPane.querySelector(':scope > .row.g-4');
                } catch (e) {
                    detailsRow = detailsPane.querySelector('.row.g-4');
                }
                const leftCol = detailsPane.querySelector('#case-left-column');
                const rightCol = detailsPane.querySelector('#case-right-column');

                if (!detailsRow || !leftCol || !rightCol) return;

                // Defensive: ensure right column is a direct sibling inside the outer details row.
                if (rightCol.parentElement !== detailsRow) {
                    detailsRow.appendChild(rightCol);
                }

                if (!leftCol.classList.contains('col-xl-8')) leftCol.classList.add('col-xl-8');
                if (!leftCol.classList.contains('col-lg-8')) leftCol.classList.add('col-lg-8');
                if (!rightCol.classList.contains('col-xl-4')) rightCol.classList.add('col-xl-4');
                if (!rightCol.classList.contains('col-lg-4')) rightCol.classList.add('col-lg-4');
            }

            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', normalizeDetailsColumns);
            } else {
                normalizeDetailsColumns();
            }
        })();
    </script>

    <!-- E-mail Tab -->
    <div class="tab-pane fade" id="emails" role="tabpanel" tabindex="0" data-module="emails" data-has-content="unknown" style="display:none;">
        <div class="card mb-3">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h6 class="mb-0 text-primary"><i class="bi bi-envelope me-2"></i>E-mail på sagen</h6>
                <div class="d-flex gap-2 align-items-center">
                    <button class="btn btn-sm btn-primary" type="button" onclick="startNewEmailThread()">
                        <i class="bi bi-envelope-plus me-1"></i>Ny email
                    </button>
                    <input type="file" id="emailImportInput" accept=".eml,.msg" style="display:none" onchange="if(this.files?.length){ uploadEmailFile(this.files[0]); this.value=''; }">
                    <button class="btn btn-sm btn-outline-primary" type="button" onclick="document.getElementById('emailImportInput').click()">
                        <i class="bi bi-cloud-upload me-1"></i>Importér .eml/.msg
                    </button>
                </div>
            </div>
            <div class="card-body" id="emailDropZone">
                <div class="row g-3">
                    <div class="col-12">
                        <div class="row g-2">
                            <div class="col-lg-4 position-relative">
                                <input type="text" class="form-control form-control-sm" id="emailSearchInput" placeholder="Søg og link e-mail..." autocomplete="off">
                                <div class="list-group position-absolute shadow-sm" id="emailSearchResults" style="z-index: 1000; display: none; top: 100%; left: 0; right: 0; max-height: 300px; overflow-y: auto;"></div>
                            </div>
                            <div class="col-lg-4">
                                <input type="text" class="form-control form-control-sm" id="emailFilterInput" placeholder="Filtrer i linkede e-mails...">
                            </div>
                            <div class="col-lg-2">
                                <select id="emailAttachmentFilter" class="form-select form-select-sm">
                                    <option value="all">Alle vedhæftninger</option>
                                    <option value="with">Med vedhæftning</option>
                                    <option value="without">Uden vedhæftning</option>
                                </select>
                            </div>
                            <div class="col-lg-2">
                                <select id="emailReadFilter" class="form-select form-select-sm">
                                    <option value="all">Alle læsestatus</option>
                                    <option value="unread">Ulæste</option>
                                    <option value="read">Læste</option>
                                </select>
                            </div>
                        </div>
                        <div class="small text-muted fst-italic mt-2">Tip: Træk .msg/.eml fil hertil for at importere direkte på sagen.</div>
                    </div>

                    <div class="col-lg-3 col-xl-2">
                        <div class="email-column-shell h-100 d-flex flex-column">
                            <div class="column-header p-2 border-bottom d-flex justify-content-between align-items-center">
                                <span class="small fw-semibold text-secondary">Mail tråd</span>
                                <span class="badge bg-light text-dark border" id="linkedEmailThreadsCount">0</span>
                            </div>
                            <div class="list-group list-group-flush flex-grow-1 overflow-auto" id="email-threads-list" style="min-height: 420px; max-height: 65vh;">
                                <div class="p-3 text-center text-muted">Ingen tråde fundet...</div>
                            </div>
                        </div>
                    </div>

                    <div class="col-lg-3 col-xl-3">
                        <div class="email-column-shell h-100 d-flex flex-column">
                            <div class="column-header p-2 border-bottom d-flex justify-content-between align-items-center">
                                <span class="small fw-semibold text-secondary">Mails i tråden</span>
                                <span class="badge bg-light text-dark border" id="threadEmailsCount">0</span>
                            </div>
                            <div class="list-group list-group-flush flex-grow-1 overflow-auto" id="linked-emails-list" style="min-height: 420px; max-height: 65vh;">
                                <div class="p-3 text-center text-muted">Ingen e-mails linket...</div>
                            </div>
                        </div>
                    </div>

                    <div class="col-lg-6 col-xl-7">
                        <div class="email-column-shell h-100 d-flex flex-column" id="email-preview-panel" style="min-height: 420px;">
                            <div class="p-3 text-center text-muted d-flex align-items-center justify-content-center flex-grow-1">
                                Vælg en e-mail i listen for at se indhold og vedhæftninger
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="caseEmailComposeModal" tabindex="-1" aria-labelledby="caseEmailComposeModalLabel" aria-hidden="true">
        <div class="modal-dialog modal-xl modal-dialog-scrollable">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="caseEmailComposeModalLabel"><i class="bi bi-envelope me-2"></i>Ny email</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <div class="d-flex flex-column gap-2">
                        <div class="row g-2">
                            <div class="col-lg-6">
                                <label for="caseEmailTo" class="form-label form-label-sm mb-1">Til</label>
                                <input type="text" class="form-control form-control-sm" id="caseEmailTo" placeholder="modtager@eksempel.dk">
                            </div>
                            <div class="col-lg-3">
                                <label for="caseEmailCc" class="form-label form-label-sm mb-1">Cc</label>
                                <input type="text" class="form-control form-control-sm" id="caseEmailCc" placeholder="cc@eksempel.dk">
                            </div>
                            <div class="col-lg-3">
                                <label for="caseEmailBcc" class="form-label form-label-sm mb-1">Bcc</label>
                                <input type="text" class="form-control form-control-sm" id="caseEmailBcc" placeholder="bcc@eksempel.dk">
                            </div>
                        </div>
                        <div class="row g-2">
                            <div class="col-lg-8">
                                <label for="caseEmailSubject" class="form-label form-label-sm mb-1">Emne</label>
                                <input type="text" class="form-control form-control-sm" id="caseEmailSubject" placeholder="Emne">
                            </div>
                            <div class="col-lg-4">
                                <label for="caseEmailAttachmentIds" class="form-label form-label-sm mb-1">Vedhæft sagsfiler</label>
                                <select id="caseEmailAttachmentIds" class="form-select form-select-sm" multiple>
                                    <option disabled>Ingen sagsfiler tilgængelige</option>
                                </select>
                            </div>
                        </div>
                        <div>
                            <div class="d-flex justify-content-between align-items-center mb-1">
                                <label for="caseEmailBody" class="form-label form-label-sm mb-0">Besked</label>
                                <button id="caseEmailRewriteBtn" type="button" class="btn btn-outline-primary btn-sm">
                                    <i class="bi bi-magic me-1"></i>Renskriv med AI
                                </button>
                            </div>
                            <textarea class="form-control form-control-sm" id="caseEmailBody" rows="10" placeholder="Skriv besked..."></textarea>
                        </div>
                    </div>
                </div>
                <div class="modal-footer d-flex justify-content-between">
                    <small id="caseEmailSendStatus" class="text-muted"></small>
                    <div class="d-flex gap-2">
                        <button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">Luk</button>
                        <button type="button" id="caseEmailSendBtn" class="btn btn-primary btn-sm">Send email</button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="rewritePreviewModal" tabindex="-1" aria-labelledby="rewritePreviewModalLabel" aria-hidden="true">
        <div class="modal-dialog modal-xl modal-dialog-scrollable">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="rewritePreviewModalLabel"><i class="bi bi-pencil-square me-2"></i>AI forslag til renskrivning</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <div id="rewritePreviewSummary" class="small text-muted mb-3"></div>
                    <div id="rewritePreviewNoChanges" class="alert alert-info d-none mb-3">AI fandt ingen ændringer.</div>
                    <div id="rewritePreviewList" class="d-flex flex-column gap-2"></div>
                </div>
                <div class="modal-footer d-flex justify-content-between">
                    <small id="rewritePreviewSelectionInfo" class="text-muted">Ingen ændringer valgt</small>
                    <div class="d-flex gap-2">
                        <button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">Annuller</button>
                        <button type="button" id="rewriteApplySelectedBtn" class="btn btn-outline-primary btn-sm">Godkend valgte</button>
                        <button type="button" id="rewriteApplyAllBtn" class="btn btn-primary btn-sm">Godkend alle</button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Solution Tab -->
    <div class="tab-pane fade" id="solution" role="tabpanel" tabindex="0" data-module="solution" data-has-content="{{ 'true' if solution or is_nextcloud else 'false' }}" style="display:none;">
            <!-- Nextcloud Integration Box -->
            {% if is_nextcloud %}
            <div class="card mb-3">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="mb-0" style="color: var(--accent);">☁️ Nextcloud Integration</h6>
                    {% if nextcloud_instance %}
                    <span class="badge bg-success" style="background: var(--accent) !important;">Aktiv</span>
                    {% else %}
                    <span class="badge bg-warning text-dark">Ingen instans</span>
                    {% endif %}
                </div>
                <div class="card-body">
                    {% if nextcloud_instance %}
                    <!-- Info Row -->
                    <div class="d-flex flex-wrap gap-4 mb-3 border-bottom pb-3">
                        <div>
                             <span class="text-muted small d-block">Instans</span>
                             <a href="{{ nextcloud_instance.base_url }}" target="_blank" style="color: var(--accent); text-decoration: none; font-weight: 500;">
                                {{ nextcloud_instance.base_url }} <i class="bi bi-box-arrow-up-right small"></i>
                             </a>
                        </div>
                        <div>
                            <span class="text-muted small d-block">Admin Konto</span>
                            <span class="font-monospace text-dark">{{ nextcloud_instance.username }}</span>
                        </div>
                    </div>
                    
                    <!-- Actions -->
                    <div>
                        <span class="text-muted small d-block mb-2">Handlinger</span>
                        <div class="d-flex flex-wrap gap-2">
                            <button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#ncCreateUserModal">
                                <i class="bi bi-person-plus me-1"></i> Opret bruger
                            </button>
                            <button class="btn btn-sm btn-outline-danger" data-bs-toggle="modal" data-bs-target="#ncDisableUserModal">
                                <i class="bi bi-person-lock me-1"></i> Luk bruger
                            </button>
                            <button class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#ncResetPasswordModal">
                                <i class="bi bi-key me-1"></i> Reset kode
                            </button>
                            <button class="btn btn-sm btn-outline-info" data-bs-toggle="modal" data-bs-target="#ncSendGuideModal">
                                <i class="bi bi-envelope me-1"></i> Send guide
                            </button>
                        </div>
                    </div>
                    {% else %}
                    <div class="text-center py-2 text-muted">
                        <i class="bi bi-exclamation-triangle me-2 text-warning"></i>
                        Kunden mangler Nextcloud konfiguration
                    </div>
                    {% endif %}
                </div>
            </div>
            {% endif %}
        <div class="card mb-3">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h6 class="mb-0 text-primary"><i class="bi bi-lightbulb me-2"></i>Løsning</h6>
                {% if not solution or request.query_params.get('edit_solution') %}
                   <!-- button to create/edit -->
                {% endif %}
            </div>
            <div class="card-body">
                {% if solution %}
                    <div class="mb-3">
                        <label class="small text-muted">Titel</label>
                        <div class="fw-bold">{{ solution.title }}</div>
                    </div>
                    <div class="row mb-3">
                        <div class="col-md-6">
                            <label class="small text-muted">Type</label>
                            <div><span class="badge bg-secondary">{{ solution.solution_type }}</span></div>
                        </div>
                        <div class="col-md-6">
                            <label class="small text-muted">Resultat</label>
                            <div><span class="badge {{ 'bg-success' if solution.result == 'Løst' else 'bg-warning' }}">{{ solution.result }}</span></div>
                        </div>
                    </div>
                    <div>
                        <label class="small text-muted">Beskrivelse</label>
                        <div class="p-3 bg-light rounded" style="white-space: pre-wrap;">{{ solution.description }}</div>
                    </div>
                {% else %}
                    <div class="text-center py-5 text-muted">
                        <i class="bi bi-lightbulb display-4 mb-3 d-block opacity-25"></i>
                        <p>Ingen løsning registreret endnu.</p>
                        <button class="btn btn-primary" onclick="showCreateSolutionModal()">
                            <i class="bi bi-plus-lg me-2"></i>Opret Løsning
                        </button>
                    </div>
                {% endif %}
            </div>
        </div>
    </div>

    <!-- Varekøb & Salg Tab -->
    <div class="tab-pane fade" id="sales" role="tabpanel" tabindex="0" data-module="sales" data-has-content="unknown" style="display:none;">
        <div class="row g-3 mb-3">
            <div class="col-lg-8">
                <div class="card mb-3">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h6 class="mb-0 text-primary"><i class="bi bi-bag-check me-2"></i>Salgslinjer</h6>
                        <span class="badge bg-light text-dark border" id="salesLinesSubtotal">-</span>
                        <button class="btn btn-sm btn-outline-primary" onclick="openSaleItemModal({ type: 'sale' })">
                            <i class="bi bi-plus-lg me-1"></i>Tilføj salgslinje
                        </button>
                    </div>
                    <div class="card-body p-0">
                        <div class="table-responsive">
                            <table class="table table-hover mb-0" style="vertical-align: middle;">
                                <thead class="bg-light">
                                    <tr>
                                        <th class="ps-4">Dato</th>
                                        <th>Beskrivelse</th>
                                        <th>Antal</th>
                                        <th>Enhed</th>
                                        <th>Enhedspris</th>
                                        <th>Linjesum</th>
                                        <th>Kilde-sag</th>
                                        <th>Status</th>
                                        <th class="text-end pe-4">Handlinger</th>
                                    </tr>
                                </thead>
                                <tbody id="saleItemsSalesBody">
                                    <tr>
                                        <td colspan="9" class="text-center py-4 text-muted">Indlæser salgslinjer...</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
                <div class="card">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h6 class="mb-0 text-primary"><i class="bi bi-cart-x me-2"></i>Indkøbslinjer</h6>
                        <span class="badge bg-light text-dark border" id="purchaseLinesSubtotal">-</span>
                        <button class="btn btn-sm btn-outline-primary" onclick="openSaleItemModal({ type: 'purchase' })">
                            <i class="bi bi-plus-lg me-1"></i>Tilføj indkøbslinje
                        </button>
                    </div>
                    <div class="card-body p-0">
                        <div class="table-responsive">
                            <table class="table table-hover mb-0" style="vertical-align: middle;">
                                <thead class="bg-light">
                                    <tr>
                                        <th class="ps-4">Dato</th>
                                        <th>Beskrivelse</th>
                                        <th>Antal</th>
                                        <th>Enhed</th>
                                        <th>Enhedspris</th>
                                        <th>Linjesum</th>
                                        <th>Formål</th>
                                        <th>Kilde-sag</th>
                                        <th>Status</th>
                                        <th class="text-end pe-4">Handlinger</th>
                                    </tr>
                                </thead>
                                <tbody id="saleItemsPurchaseBody">
                                    <tr>
                                        <td colspan="10" class="text-center py-4 text-muted">Indlæser indkøbslinjer...</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-lg-4">
                <div class="card mb-3">
                    <div class="card-header">
                        <h6 class="mb-0 text-primary"><i class="bi bi-graph-up-arrow me-2"></i>Salg (samlet)</h6>
                    </div>
                    <div class="card-body">
                        <div class="d-flex justify-content-between align-items-center mb-2">
                            <span class="text-muted">Total salg</span>
                            <strong id="salesTotalSale">-</strong>
                        </div>
                        <div class="d-flex justify-content-between align-items-center">
                            <span class="text-muted">Netto</span>
                            <strong id="salesTotalNet">-</strong>
                        </div>
                    </div>
                </div>
                <div class="card mb-3">
                    <div class="card-header">
                        <h6 class="mb-0 text-primary"><i class="bi bi-bag-check me-2"></i>Indkøb (samlet)</h6>
                    </div>
                    <div class="card-body">
                        <div class="d-flex justify-content-between align-items-center">
                            <span class="text-muted">Total køb</span>
                            <strong id="salesTotalPurchase">-</strong>
                        </div>
                    </div>
                </div>
                <div class="card mb-3">
                    <div class="card-header">
                        <h6 class="mb-0 text-primary"><i class="bi bi-clock-history me-2"></i>Tid (samlet)</h6>
                    </div>
                    <div class="card-body">
                        <div class="d-flex justify-content-between align-items-center mb-2">
                            <span class="text-muted">Timer (total)</span>
                            <strong id="salesTotalHours">-</strong>
                        </div>
                        <div class="d-flex justify-content-between align-items-center">
                            <span class="text-muted">Timer (fakturerbar)</span>
                            <strong id="salesBillableHours">-</strong>
                        </div>
                        <div class="small text-muted mt-3">
                            Inkluderer alle under-sager
                        </div>
                    </div>
                </div>
                <div class="card">
                    <div class="card-header">
                        <h6 class="mb-0 text-primary"><i class="bi bi-clock-history me-2"></i>Tid (samlet)</h6>
                    </div>
                    <div class="card-body p-0">
                        <div class="table-responsive">
                            <table class="table table-hover mb-0" style="vertical-align: middle;">
                                <thead class="bg-light">
                                    <tr>
                                        <th class="ps-3">Dato</th>
                                        <th>Timer</th>
                                        <th>Kilde-sag</th>
                                    </tr>
                                </thead>
                                <tbody id="salesTimeBody">
                                    <tr>
                                        <td colspan="3" class="text-center py-4 text-muted">Indlæser tid...</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Leverandør Tab -->
    <div class="tab-pane fade" id="supplier" role="tabpanel" tabindex="0" data-module="supplier" data-has-content="unknown" style="display:none;">
        <div class="row g-3 mb-3">
            <div class="col-xl-8 col-12">
                <div class="card mb-3">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h6 class="mb-0 text-primary"><i class="bi bi-diagram-3 me-2"></i>Leverandørflow Type</h6>
                        <button class="btn btn-sm btn-outline-primary" onclick="saveSupplierFlowType()">
                            <i class="bi bi-save me-1"></i>Gem type
                        </button>
                    </div>
                    <div class="card-body">
                        <div class="row g-2 align-items-end">
                            <div class="col-md-4">
                                <label class="form-label">Type</label>
                                <select class="form-select" id="supplierFlowTypeSelect" onchange="toggleSupplierTypePanels()">
                                    <option value="">Vælg type...</option>
                                    <option value="varekob" {% if case.supplier_flow_type == 'varekob' %}selected{% endif %}>Varekøb</option>
                                    <option value="ydelse" {% if case.supplier_flow_type == 'ydelse' %}selected{% endif %}>Købt ydelse</option>
                                </select>
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">AI confidence</label>
                                <input type="number" class="form-control" id="supplierFlowConfidenceInput" min="0" max="1" step="0.01" value="{{ case.supplier_flow_confidence if case.supplier_flow_confidence is not none else '' }}" placeholder="0.00 - 1.00">
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">Forslag</label>
                                <div id="supplierFlowSuggestion" class="small text-muted border rounded p-2">Ingen forslag endnu</div>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="card mb-3" id="supplierVarekobPanel" style="display:none;">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h6 class="mb-0 text-primary"><i class="bi bi-box-seam me-2"></i>VAREKØB handlinger pr. linje</h6>
                        <span class="badge bg-light text-dark border" id="supplierPurchaseLinesCount">0 linjer</span>
                    </div>
                    <div class="card-body p-0">
                        <div class="table-responsive">
                            <table class="table table-hover mb-0" style="vertical-align: middle;">
                                <thead class="bg-light">
                                    <tr>
                                        <th class="ps-3">Beskrivelse</th>
                                        <th>Beløb</th>
                                        <th>Handling</th>
                                        <th class="text-end pe-3">Gem</th>
                                    </tr>
                                </thead>
                                <tbody id="supplierPurchaseLinesBody">
                                    <tr><td colspan="4" class="text-center py-4 text-muted">Indlæser...</td></tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>

                <div class="card mb-3" id="supplierYdelsePanel" style="display:none;">
                    <div class="card-header">
                        <h6 class="mb-0 text-primary"><i class="bi bi-tools me-2"></i>YDELSE handling</h6>
                    </div>
                    <div class="card-body">
                        <div class="row g-2">
                            <div class="col-md-4">
                                <label class="form-label">Ydelsestype</label>
                                <select class="form-select" id="supplierServiceType">
                                    <option value="husleje">Husleje</option>
                                    <option value="rengoering">Rengøring</option>
                                    <option value="konsulent">Konsulent</option>
                                    <option value="abonnement">Abonnement</option>
                                </select>
                            </div>
                            <div class="col-md-3">
                                <label class="form-label">Periode fra</label>
                                <input type="date" class="form-control" id="supplierServiceFrom">
                            </div>
                            <div class="col-md-3">
                                <label class="form-label">Periode til</label>
                                <input type="date" class="form-control" id="supplierServiceTo">
                            </div>
                            <div class="col-md-2">
                                <label class="form-label">Beløb</label>
                                <input type="number" min="0" step="0.01" class="form-control" id="supplierServiceAmount" placeholder="0,00">
                            </div>
                        </div>
                        <div class="d-flex gap-2 mt-3 flex-wrap">
                            <button class="btn btn-sm btn-outline-primary" onclick="registerSupplierServiceHandling('direkte_omkostning')">
                                <i class="bi bi-cash-stack me-1"></i>Direkte omkostning
                            </button>
                            <button class="btn btn-sm btn-outline-primary" onclick="registerSupplierServiceHandling('fordel_kunder')">
                                <i class="bi bi-diagram-2 me-1"></i>Fordel på kunder
                            </button>
                            <button class="btn btn-sm btn-outline-primary" onclick="registerSupplierServiceHandling('gentagende_ydelse')">
                                <i class="bi bi-arrow-repeat me-1"></i>Gentagende ydelse
                            </button>
                        </div>
                    </div>
                </div>
            </div>

            <div class="col-xl-4 col-12">
                <div class="card">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h6 class="mb-0 text-primary"><i class="bi bi-receipt me-2"></i>Leverandørfakturaer</h6>
                        <button class="btn btn-sm btn-outline-secondary" onclick="loadSupplierModule()">
                            <i class="bi bi-arrow-clockwise"></i>
                        </button>
                    </div>
                    <div class="card-body p-0">
                        <div class="table-responsive">
                            <table class="table table-sm table-hover mb-0">
                                <thead class="bg-light">
                                    <tr>
                                        <th class="ps-3">Faktura</th>
                                        <th>Beløb</th>
                                        <th>Status</th>
                                        <th class="text-end pe-3">Actions</th>
                                    </tr>
                                </thead>
                                <tbody id="supplierInvoicesBody">
                                    <tr><td colspan="4" class="text-center py-4 text-muted">Indlæser...</td></tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Tidsforbrug Tab -->
    <div class="tab-pane fade" id="timetracking" role="tabpanel" tabindex="0"  data-has-content="unknown" style="display:none;">
        <div id="timeActiveBanner" class="alert alert-warning d-none d-flex justify-content-between align-items-center" role="alert">
            <div>
                <strong>Aktiv timer:</strong>
                <span id="timeActiveBannerText">Du har en aktiv timer.</span>
            </div>
            <div class="d-flex gap-2">
                <button class="btn btn-sm btn-outline-secondary" onclick="stopLiveTimerV1({ entry_status: 'kladde' })">Pause</button>
                <button class="btn btn-sm btn-primary" onclick="stopLiveTimerV1({ entry_status: 'afventer' })">Stop og registrer</button>
            </div>
        </div>

        <div class="card mb-3">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h6 class="mb-0 text-primary"><i class="bi bi-stopwatch me-2"></i>Live tracking</h6>
                <div class="d-flex gap-2">
                    <button class="btn btn-sm btn-outline-primary" onclick="startLiveTimerV1()">
                        <i class="bi bi-play-fill me-1"></i>Start timer
                    </button>
                    <button class="btn btn-sm btn-outline-danger" onclick="stopLiveTimerV1({ entry_status: 'afventer' })">
                        <i class="bi bi-stop-fill me-1"></i>Stop timer
                    </button>
                </div>
            </div>
            <div class="card-body">
                <form id="timeManualFormV1" class="row g-2 align-items-end" onsubmit="createManualTimeV1(event); return false;">
                    <div class="col-xl-2 col-md-3 col-12">
                        <label class="form-label small mb-1">Medarbejder</label>
                        <select class="form-select form-select-sm" id="timeV1EmployeeId">
                            <option value="">Mig (nuværende bruger)</option>
                            {% for user in assignment_users %}
                            <option value="{{ user.user_id }}">{{ user.display_name }}</option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="col-xl-2 col-md-3 col-6">
                        <label class="form-label small mb-1">Dato</label>
                        <input type="date" class="form-control form-control-sm" id="timeV1Date">
                    </div>
                    <div class="col-xl-1 col-md-2 col-3">
                        <label class="form-label small mb-1">Start</label>
                        <input type="time" class="form-control form-control-sm" id="timeV1Start">
                    </div>
                    <div class="col-xl-1 col-md-2 col-3">
                        <label class="form-label small mb-1">Slut</label>
                        <input type="time" class="form-control form-control-sm" id="timeV1End">
                    </div>
                    <div class="col-xl-1 col-md-2 col-6">
                        <label class="form-label small mb-1">Minutt.</label>
                        <input type="number" min="1" class="form-control form-control-sm" id="timeV1Minutes" placeholder="45" required>
                    </div>
                    <div class="col-xl-2 col-md-6 col-6">
                        <label class="form-label small mb-1">Beskrivelse</label>
                        <input type="text" class="form-control form-control-sm" id="timeV1Description" placeholder="Hvad er udført?">
                    </div>
                    <div class="col-xl-2 col-md-4 col-12 d-flex gap-1">
                        <div class="w-50">
                            <label class="form-label small mb-1">Type</label>
                            <select class="form-select form-select-sm px-1" id="timeV1Type">
                                <option value="ukendt">Ukendt</option>
                                <option value="manuel" selected>Manuel</option>
                                <option value="opkald">Opkald</option>
                                <option value="mail">Mail</option>
                                <option value="anydesk">AnyDesk</option>
                            </select>
                        </div>
                        <div class="w-50">
                            <label class="form-label small mb-1">Status</label>
                            <select class="form-select form-select-sm px-1" id="timeV1Status">
                                <option value="kladde">Kladde</option>
                                <option value="afventer" selected>Afventer</option>
                                <option value="godkendt">Godkendt</option>
                            </select>
                        </div>
                    </div>
                    <div class="col-xl-1 col-md-2 col-12 d-grid">
                        <button class="btn btn-sm btn-primary" type="submit" title="Tilføj registrering"><i class="bi bi-plus-lg fs-6"></i></button>
                    </div>
                </form>
                <div class="small text-muted mt-2">
                    Faktisk tid gemmes internt. Fakturerbar tid afrundes per blok (standard 30 min).
                </div>
            </div>
        </div>

        <div class="row g-3">
            <div class="col-lg-9">
                <div class="card">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h6 class="mb-0 text-primary"><i class="bi bi-diagram-3 me-2"></i>Timeline per medarbejder</h6>
                        <button class="btn btn-sm btn-outline-secondary" onclick="loadTimeTrackingTab()">
                            <i class="bi bi-arrow-clockwise me-1"></i>Opdater
                        </button>
                    </div>
                    <div class="card-body" id="timeTimelineColumns">
                        <div class="text-muted text-center py-3">Indlæser tidslinje...</div>
                    </div>
                </div>
            </div>
            <div class="col-lg-3">
                <div class="card">
                    <div class="card-header">
                        <h6 class="mb-0 text-primary"><i class="bi bi-clipboard-data me-2"></i>Tids sammendrag</h6>
                    </div>
                    <div class="card-body" id="timeSummaryEntries">
                        <div class="text-muted small">Indlæser sammendrag...</div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="timeV1EditModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-lg modal-dialog-scrollable">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="bi bi-pencil-square me-2"></i>Detaljeret redigering af tid</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <input type="hidden" id="timeV1EditId">
                    <div class="row g-3">
                        <div class="col-md-4">
                            <label class="form-label">Dato</label>
                            <input type="date" class="form-control" id="timeV1EditDate">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Start</label>
                            <input type="time" class="form-control" id="timeV1EditStart">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Slut</label>
                            <input type="time" class="form-control" id="timeV1EditEnd">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Minutter</label>
                            <input type="number" class="form-control" id="timeV1EditMinutes" min="1" step="1">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Medarbejder</label>
                            <select class="form-select" id="timeV1EditEmployeeId">
                                <option value="">Mig (nuværende bruger)</option>
                            </select>
                        </div>
                        <div class="col-md-4 d-flex align-items-end">
                            <div class="form-check form-switch">
                                <input class="form-check-input" type="checkbox" id="timeV1EditBillable">
                                <label class="form-check-label" for="timeV1EditBillable">Fakturerbar</label>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">Type</label>
                            <select class="form-select" id="timeV1EditType">
                                <option value="ukendt">Ukendt</option>
                                <option value="manuel">Manuel</option>
                                <option value="opkald">Opkald</option>
                                <option value="mail">Mail</option>
                                <option value="anydesk">AnyDesk</option>
                            </select>
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">Status</label>
                            <select class="form-select" id="timeV1EditStatus">
                                <option value="kladde">Kladde</option>
                                <option value="afventer">Afventer</option>
                                <option value="godkendt">Godkendt</option>
                            </select>
                        </div>
                        <div class="col-12">
                            <label class="form-label">Beskrivelse</label>
                            <textarea class="form-control" id="timeV1EditDescription" rows="3" placeholder="Hvad er udført?"></textarea>
                        </div>
                    </div>
                    <div class="small text-muted mt-3">Tip: Dobbeltklik på en blok i timeline eller en entry under "Uden tidsrum" for at åbne denne redigering.</div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Luk</button>
                    <button type="button" class="btn btn-primary" onclick="saveTimeV1DetailedEdit()">
                        <i class="bi bi-save me-1"></i>Gem ændringer
                    </button>
                </div>
            </div>
        </div>
    </div>

    <!-- Subscription Tab -->
    <div class="tab-pane fade" id="subscription" role="tabpanel" tabindex="0" data-module="subscription" data-has-content="unknown" style="display:none;">
        <div class="row g-3">
            <div class="col-lg-8">
                <div class="card mb-3">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h6 class="mb-0 text-primary"><i class="bi bi-repeat me-2"></i>Abonnement</h6>
                        <span id="subscriptionStatusBadge" class="badge bg-light text-dark">Ingen</span>
                    </div>
                    <div class="card-body">
                        <div id="subscriptionEmpty" class="text-center text-muted py-3">
                            <i class="bi bi-receipt-cutoff display-6 mb-3 d-block opacity-25"></i>
                            <p>Ingen abonnement oprettet endnu.</p>
                        </div>

                        <div id="subscriptionDetails" class="d-none">
                            <div class="row g-3 mb-3">
                                <div class="col-md-4">
                                    <label class="small text-muted">Abonnement</label>
                                    <div class="fw-semibold" id="subscriptionNumber">-</div>
                                </div>
                                <div class="col-md-4">
                                    <label class="small text-muted">Produkt</label>
                                    <div class="fw-semibold" id="subscriptionProduct">-</div>
                                </div>
                                <div class="col-md-4">
                                    <label class="small text-muted">Status</label>
                                    <div class="fw-semibold" id="subscriptionStatusText">-</div>
                                </div>
                                <div class="col-md-4">
                                    <label class="small text-muted">Interval</label>
                                    <div class="fw-semibold" id="subscriptionInterval">-</div>
                                </div>
                                <div class="col-md-4">
                                    <label class="small text-muted">Pris</label>
                                    <div class="fw-semibold" id="subscriptionPrice">-</div>
                                </div>
                                <div class="col-md-4">
                                    <label class="small text-muted">Startdato</label>
                                    <div class="fw-semibold" id="subscriptionStartDate">-</div>
                                </div>
                                <div class="col-md-6">
                                    <label class="small text-muted">Periode start <i class="bi bi-info-circle" title="Nuværende faktureringsperiode"></i></label>
                                    <div class="fw-semibold" id="subscriptionPeriodStart">-</div>
                                </div>
                                <div class="col-md-6">
                                    <label class="small text-muted">Næste faktura <i class="bi bi-info-circle" title="Dato for næste automatiske faktura"></i></label>
                                    <div class="fw-semibold" id="subscriptionNextInvoice">-</div>
                                </div>
                            </div>
                            <div class="table-responsive mb-3">
                                <table class="table table-sm align-middle">
                                    <thead class="bg-light">
                                        <tr>
                                            <th>Produkt</th>
                                            <th>Beskrivelse</th>
                                            <th class="text-end">Antal</th>
                                            <th class="text-end">Enhedspris</th>
                                            <th class="text-end">Linjesum</th>
                                        </tr>
                                    </thead>
                                    <tbody id="subscriptionItemsBody">
                                        <tr>
                                            <td colspan="5" class="text-center text-muted">Ingen linjer</td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                            <div class="d-flex justify-content-end mb-3">
                                <div class="fw-semibold">Total: <span id="subscriptionItemsTotal">0,00 kr</span></div>
                            </div>
                            <div class="d-flex flex-wrap gap-2" id="subscriptionActions"></div>
                        </div>

                        <form id="subscriptionCreateForm" class="row g-3 d-none">
                            <div class="col-md-3">
                                <label class="form-label">Interval *</label>
                                <select class="form-select" id="subscriptionIntervalInput" required>
                                    <option value="daily">Daglig</option>
                                    <option value="biweekly">Hver 14. dag</option>
                                    <option value="monthly" selected>Maaned</option>
                                    <option value="quarterly">Kvartal</option>
                                    <option value="yearly">Aar</option>
                                </select>
                            </div>
                            <div class="col-md-3">
                                <label class="form-label">Faktura dag *</label>
                                <input type="number" class="form-control" id="subscriptionBillingDayInput" min="1" max="31" value="1" required>
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">Startdato *</label>
                                <input type="date" class="form-control" id="subscriptionStartDateInput" required>
                            </div>
                            <div class="col-12">
                                <label class="form-label">Varelinjer *</label>
                                <div class="table-responsive">
                                    <table class="table table-sm align-middle mb-2">
                                        <thead>
                                            <tr>
                                                <th style="width: 220px;">Produkt</th>
                                                <th>Beskrivelse</th>
                                                <th style="width: 120px;">Antal</th>
                                                <th style="width: 140px;">Enhedspris</th>
                                                <th style="width: 140px;">Linjesum</th>
                                                <th style="width: 60px;"></th>
                                            </tr>
                                        </thead>
                                        <tbody id="subscriptionLineItemsBody">
                                            <tr>
                                                <td>
                                                    <select class="form-select form-select-sm subscriptionProductSelect" onchange="applySubscriptionProduct(this)">
                                                        <option value="">Vælg produkt</option>
                                                    </select>
                                                </td>
                                                <td><input type="text" class="form-control form-control-sm" placeholder="Managed Backup"></td>
                                                <td><input type="number" class="form-control form-control-sm" min="0.01" step="0.01" value="1" oninput="updateSubscriptionLineTotals()"></td>
                                                <td><input type="number" class="form-control form-control-sm" min="0" step="0.01" value="0" oninput="updateSubscriptionLineTotals()"></td>
                                                <td class="text-end"><span class="subscriptionLineTotal">0,00 kr</span></td>
                                                <td class="text-end">
                                                    <button type="button" class="btn btn-sm btn-outline-danger" onclick="removeSubscriptionLine(this)"><i class="bi bi-x"></i></button>
                                                </td>
                                            </tr>
                                        </tbody>
                                    </table>
                                </div>
                                <div class="d-flex justify-content-between align-items-center">
                                    <button type="button" class="btn btn-sm btn-outline-primary" onclick="addSubscriptionLine()">
                                        <i class="bi bi-plus-lg me-1"></i>Tilfoej linje
                                    </button>
                                    <button type="button" class="btn btn-sm btn-outline-secondary" onclick="openSubscriptionProductModal()">
                                        <i class="bi bi-box me-1"></i>Opret produkt
                                    </button>
                                    <div class="fw-semibold">Total: <span id="subscriptionLinesTotal">0,00 kr</span></div>
                                </div>
                            </div>
                            <div class="col-md-12">
                                <label class="form-label">Noter</label>
                                <textarea class="form-control" id="subscriptionNotesInput" rows="2"></textarea>
                            </div>
                            <div class="col-12">
                                <button type="button" class="btn btn-primary" onclick="createSubscription()">
                                    <i class="bi bi-plus-circle me-1"></i>Opret abonnement
                                </button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Subscription Product Modal -->
    <div class="modal fade" id="subscriptionProductModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="bi bi-box"></i> Opret produkt</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="subscriptionProductForm">
                        <div class="row g-3">
                            <div class="col-12">
                                <label class="form-label">Navn *</label>
                                <input type="text" class="form-control" id="subscriptionProductName" required>
                            </div>
                            <div class="col-12">
                                <label class="form-label">Type</label>
                                <input type="text" class="form-control" id="subscriptionProductType" placeholder="subscription, service">
                            </div>
                            <div class="col-6">
                                <label class="form-label">Status</label>
                                <select class="form-select" id="subscriptionProductStatus">
                                    <option value="active" selected>Aktiv</option>
                                    <option value="inactive">Inaktiv</option>
                                </select>
                            </div>
                            <div class="col-6">
                                <label class="form-label">Salgspris</label>
                                <input type="number" class="form-control" id="subscriptionProductSalesPrice" step="0.01" min="0">
                            </div>
                            <div class="col-12">
                                <label class="form-label">Faktureringsinterval</label>
                                <select class="form-select" id="subscriptionProductBillingPeriod">
                                    <option value="">-</option>
                                    <option value="daily">Daglig</option>
                                    <option value="biweekly">Hver 14. dag</option>
                                    <option value="monthly">Maaned</option>
                                    <option value="quarterly">Kvartal</option>
                                    <option value="yearly">Aar</option>
                                    <option value="one_time">Engang</option>
                                </select>
                            </div>
                            <div class="col-12">
                                <label class="form-label">Kort beskrivelse</label>
                                <input type="text" class="form-control" id="subscriptionProductDescription">
                            </div>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Luk</button>
                    <button type="button" class="btn btn-primary" onclick="createSubscriptionProduct()">
                        <i class="bi bi-save me-1"></i>Gem produkt
                    </button>
                </div>
            </div>
        </div>
    </div>

    <!-- Reminders Tab -->
    <div class="tab-pane fade" id="reminders" role="tabpanel" tabindex="0" data-module="reminders" data-has-content="unknown" style="display:none;">
        <div class="row g-3">
            <div class="col-lg-8">
                <div class="card mb-3">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h6 class="mb-0 text-primary"><i class="bi bi-bell me-2"></i>Reminders</h6>
                        <button class="btn btn-sm btn-outline-primary" onclick="openCreateReminderModal()">
                            <i class="bi bi-plus-lg me-1"></i>Opret reminder
                        </button>
                    </div>
                    <div class="card-body p-0">
                        <div class="list-group list-group-flush" id="remindersList">
                            <div class="p-4 text-center text-muted">Indlæser reminders...</div>
                        </div>
                    </div>
                </div>
                <div class="card mb-3" id="caseCalendarCard" data-module="calendar" data-has-content="unknown">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h6 class="mb-0 text-primary"><i class="bi bi-calendar3 me-2"></i>Kalenderaftaler</h6>
                        <button class="btn btn-sm btn-outline-primary" onclick="openCreateReminderModal('meeting')">
                            <i class="bi bi-plus-lg me-1"></i>Opret aftale
                        </button>
                    </div>
                    <div class="card-body">
                        <div class="mb-3">
                            <div class="small text-muted mb-2">Denne sag</div>
                            <div class="list-group" id="caseCalendarCurrent">
                                <div class="text-muted small">Indlæser aftaler...</div>
                            </div>
                        </div>
                        <div>
                            <div class="small text-muted mb-2">Børnesager</div>
                            <div id="caseCalendarChildren">
                                <div class="text-muted small">Indlæser børnesager...</div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-lg-4">
                <div class="card mb-3">
                    <div class="card-header">
                        <h6 class="mb-0 text-primary"><i class="bi bi-sliders me-2"></i>Indstillinger</h6>
                    </div>
                    <div class="card-body">
                        <p class="text-muted small mb-2">Reminders følger brugerens standardindstillinger (email, Mattermost og popup), medmindre du vælger at overskrive dem på reminderen.</p>
                        <div class="small text-muted">
                            Tip: Brug "Status ændring" hvis reminderen skal trigges af status.
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>


    </div> <!-- End Tab Content -->

    <!-- Create Reminder Modal -->
    <div class="modal fade" id="createReminderModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Opret reminder</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="createReminderForm">
                        <div class="row g-3">
                            <div class="col-md-8">
                                <label class="form-label">Titel *</label>
                                <input type="text" class="form-control" id="rem_title" required>
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">Prioritet</label>
                                <select class="form-select" id="rem_priority">
                                    <option value="low">Lav</option>
                                    <option value="normal" selected>Normal</option>
                                    <option value="high">Høj</option>
                                    <option value="urgent">Kritisk</option>
                                </select>
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">Aftaletype</label>
                                <select class="form-select" id="rem_event_type">
                                    <option value="reminder" selected>Reminder</option>
                                    <option value="meeting">Moede</option>
                                    <option value="technician_visit">Teknikerbesoeg</option>
                                    <option value="obs">OBS</option>
                                    <option value="deadline">Deadline</option>
                                </select>
                            </div>
                            <div class="col-12">
                                <label class="form-label">Besked</label>
                                <textarea class="form-control" id="rem_message" rows="3"></textarea>
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">Trigger type</label>
                                <select class="form-select" id="rem_trigger_type" onchange="updateReminderTriggerFields()">
                                    <option value="time_based" selected>Tidspunkt</option>
                                    <option value="status_change">Status ændring</option>
                                </select>
                            </div>
                            <div class="col-md-6" id="rem_trigger_time_wrap">
                                <label class="form-label">Tidspunkt</label>
                                <input type="datetime-local" class="form-control" id="rem_scheduled_at">
                            </div>
                            <div class="col-md-6 d-none" id="rem_trigger_status_wrap">
                                <label class="form-label">Status (target)</label>
                                <select class="form-select" id="rem_target_status">
                                    <option value="">Vælg status</option>
                                    {% for status in status_options %}
                                    <option value="{{ status }}">{{ status }}</option>
                                    {% endfor %}
                                </select>
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">Gentagelse</label>
                                <select class="form-select" id="rem_recurrence_type" onchange="updateReminderRecurrenceFields()">
                                    <option value="once" selected>Kun én gang</option>
                                    <option value="daily">Dagligt</option>
                                    <option value="weekly">Ugentligt</option>
                                    <option value="monthly">Månedligt</option>
                                </select>
                            </div>
                            <div class="col-md-6 d-none" id="rem_recurrence_dow_wrap">
                                <label class="form-label">Ugedag</label>
                                <select class="form-select" id="rem_recurrence_dow">
                                    <option value="0">Mandag</option>
                                    <option value="1">Tirsdag</option>
                                    <option value="2">Onsdag</option>
                                    <option value="3">Torsdag</option>
                                    <option value="4">Fredag</option>
                                    <option value="5">Lørdag</option>
                                    <option value="6">Søndag</option>
                                </select>
                            </div>
                            <div class="col-md-6 d-none" id="rem_recurrence_dom_wrap">
                                <label class="form-label">Dag i måned</label>
                                <input type="number" class="form-control" id="rem_recurrence_dom" min="1" max="31" placeholder="Fx 15">
                            </div>
                            <div class="col-12">
                                <label class="form-label">Kanaler</label>
                                <div class="d-flex flex-wrap gap-3">
                                    <div class="form-check">
                                        <input class="form-check-input" type="checkbox" id="rem_notify_frontend" checked>
                                        <label class="form-check-label" for="rem_notify_frontend">Popup</label>
                                    </div>
                                    <div class="form-check">
                                        <input class="form-check-input" type="checkbox" id="rem_notify_email">
                                        <label class="form-check-label" for="rem_notify_email">E-mail</label>
                                    </div>
                                    <div class="form-check">
                                        <input class="form-check-input" type="checkbox" id="rem_notify_mattermost">
                                        <label class="form-check-label" for="rem_notify_mattermost">Mattermost</label>
                                    </div>
                                </div>
                            </div>
                            <div class="col-12">
                                <div class="form-check">
                                    <input class="form-check-input" type="checkbox" id="rem_override_prefs">
                                    <label class="form-check-label" for="rem_override_prefs">Overskriv brugerens standardindstillinger</label>
                                </div>
                            </div>
                            <div class="col-12">
                                <div class="alert alert-warning small mb-0 d-none" id="rem_user_warning">
                                    Mangler bruger-id. Log ind igen eller opdater siden.
                                </div>
                            </div>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Luk</button>
                    <button type="button" class="btn btn-primary" onclick="saveReminder()">Gem reminder</button>
                </div>
            </div>
        </div>
    </div>

    <script>
        function _escapeCommentHtml(value) {
            return String(value || '')
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#39;');
        }

        function _removeQuotedMailLines(text) {
            const source = String(text || '').replace(/\r\n/g, '\n').replace(/\r/g, '\n');
            const lines = source.split('\n');
            const kept = [];

            const headerRe = /^(fra|from|sent|date|dato|to|til|emne|subject|cc):\s*/i;
            const originalMessageRe = /^(original message|oprindelig besked|videresendt besked)/i;

            for (let i = 0; i < lines.length; i += 1) {
                const line = lines[i];
                const trimmed = line.trim();

                if (trimmed.startsWith('>')) break;
                if (originalMessageRe.test(trimmed)) break;

                if (/^[-_]{3,}$/.test(trimmed)) {
                    const lookahead = lines.slice(i + 1, i + 4);
                    if (lookahead.some((candidate) => headerRe.test(String(candidate || '').trim()))) {
                        break;
                    }
                }

                if (i > 0 && headerRe.test(trimmed) && String(lines[i - 1] || '').trim() === '') {
                    break;
                }

                kept.push(line);
            }

            while (kept.length > 0 && String(kept[kept.length - 1] || '').trim() === '') {
                kept.pop();
            }

            return kept.join('\n').trim();
        }

        function _parseEmailComment(rawText) {
            const normalized = String(rawText || '').replace(/\r\n/g, '\n').replace(/\r/g, '\n');
            const emailIdMatch = normalized.match(/^Email-ID:\s*(\d+)\s*$/m);
            const emailId = emailIdMatch ? Number(emailIdMatch[1]) : null;
            const withoutMeta = normalized.replace(/^Email-ID:\s*\d+\s*\n?/m, '').trim();
            return {
                emailId,
                visibleText: _removeQuotedMailLines(withoutMeta)
            };
        }

        function _formatEmailHeaderTimestamp(value) {
            if (!value) return '';
            const parsed = new Date(value);
            if (Number.isNaN(parsed.getTime())) return String(value);
            return parsed.toLocaleString('da-DK');
        }

        function _buildEmailHeaderAndBody(visibleText) {
            const text = String(visibleText || '').replace(/\r\n/g, '\n').replace(/\r/g, '\n').trim();
            const lines = text.split('\n');

            let idx = 0;
            let typeLabel = 'Indgaaende email';
            const firstLine = String(lines[0] || '').trim();
            if (/^📧\s*Indgående email/i.test(firstLine)) {
                typeLabel = 'Indgaaende email';
                idx = 1;
            } else if (/^📧\s*Udgående email/i.test(firstLine)) {
                typeLabel = 'Udgaaende email';
                idx = 1;
            }

            let fra = '';
            let til = '';
            let cc = '';
            let emne = '';
            let modtaget = '';

            while (idx < lines.length) {
                const line = String(lines[idx] || '').trim();
                if (!line) {
                    idx += 1;
                    break;
                }
                if (/^Fra:\s*/i.test(line)) fra = line.replace(/^Fra:\s*/i, '').trim();
                else if (/^Til:\s*/i.test(line)) til = line.replace(/^Til:\s*/i, '').trim();
                else if (/^Cc:\s*/i.test(line)) cc = line.replace(/^Cc:\s*/i, '').trim();
                else if (/^Emne:\s*/i.test(line)) emne = line.replace(/^Emne:\s*/i, '').trim();
                else if (/^Modtaget:\s*/i.test(line)) modtaget = line.replace(/^Modtaget:\s*/i, '').trim();
                else break;
                idx += 1;
            }

            const bodyText = lines.slice(idx).join('\n').trim();
            const summaryParts = [typeLabel];
            if (fra) summaryParts.push(`Fra: ${fra}`);
            if (til) summaryParts.push(`Til: ${til}`);
            if (cc) summaryParts.push(`Cc: ${cc}`);
            if (emne) summaryParts.push(`Emne: ${emne}`);
            if (modtaget) summaryParts.push(`Modtaget: ${_formatEmailHeaderTimestamp(modtaget)}`);

            return {
                summary: summaryParts.join('  •  '),
                bodyText
            };
        }

        function _extractEmailHeaderFields(visibleText) {
            const text = String(visibleText || '').replace(/\r\n/g, '\n').replace(/\r/g, '\n').trim();
            const lines = text.split('\n');
            let idx = 0;

            const firstLine = String(lines[0] || '').trim();
            const isOutgoing = /^📧\s*Udgående email/i.test(firstLine);
            if (/^📧\s*(Indgående|Udgående)\s+email/i.test(firstLine)) {
                idx = 1;
            }

            let fra = '';
            let til = '';
            let emne = '';
            let modtaget = '';

            while (idx < lines.length) {
                const line = String(lines[idx] || '').trim();
                if (!line) break;
                if (/^Fra:\s*/i.test(line)) fra = line.replace(/^Fra:\s*/i, '').trim();
                else if (/^Til:\s*/i.test(line)) til = line.replace(/^Til:\s*/i, '').trim();
                else if (/^Emne:\s*/i.test(line)) emne = line.replace(/^Emne:\s*/i, '').trim();
                else if (/^Modtaget:\s*/i.test(line)) modtaget = line.replace(/^Modtaget:\s*/i, '').trim();
                else break;
                idx += 1;
            }

            return { fra, til, emne, modtaget, isOutgoing };
        }

        function _normalizeReplySubject(value) {
            const subject = String(value || '').trim();
            return subject.replace(/^(re|fw|fwd)\s*:\s*/ig, '').toLowerCase();
        }

        function _findBestLinkedEmailByHeader(header) {
            const targetSubject = _normalizeReplySubject(header?.emne || '');
            const targetFrom = String(header?.fra || '').trim().toLowerCase();
            const targetTo = String(header?.til || '').trim().toLowerCase();

            const candidates = (linkedEmailsCache || []).filter((email) => {
                const emailSubject = _normalizeReplySubject(email?.subject || '');
                if (targetSubject && emailSubject !== targetSubject) {
                    return false;
                }

                const sender = String(email?.sender_email || email?.sender_name || '').toLowerCase();
                const recipient = String(email?.recipient_email || '').toLowerCase();

                if (targetFrom && sender && sender.includes(targetFrom)) {
                    return true;
                }
                if (targetTo && recipient && recipient.includes(targetTo)) {
                    return true;
                }

                return !targetFrom && !targetTo;
            });

            if (!candidates.length) {
                return null;
            }

            candidates.sort((a, b) => {
                const aTs = a?.received_date ? new Date(a.received_date).getTime() : 0;
                const bTs = b?.received_date ? new Date(b.received_date).getTime() : 0;
                return bTs - aTs;
            });

            return Number(candidates[0]?.id) || null;
        }

        function _extractEmailAddress(value) {
            const raw = String(value || '').trim();
            const match = raw.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i);
            return match ? match[0] : raw;
        }

        function _commentInitials(name) {
            const clean = String(name || '').trim();
            if (!clean) return 'EM';
            const parts = clean.split(/\s+/).filter(Boolean);
            if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
            return `${parts[0][0] || ''}${parts[1][0] || ''}`.toUpperCase();
        }

        function _formatCommentTime(value) {
            const parsed = new Date(value || Date.now());
            if (Number.isNaN(parsed.getTime())) return '';
            const pad = (n) => String(n).padStart(2, '0');
            return `${pad(parsed.getDate())}/${pad(parsed.getMonth() + 1)}-${parsed.getFullYear()} ${pad(parsed.getHours())}:${pad(parsed.getMinutes())}`;
        }

        function _refreshCommentCountBadge() {
            const container = document.getElementById('comments-container');
            const badge = document.getElementById('commentsTotalCountBadge')
                || document.querySelector('#beskrivelse-comments-wrap .badge.bg-secondary');
            if (!container || !badge) return;
            badge.textContent = String(container.querySelectorAll('.comment-item').length);
        }

        function prependCommentToThread(comment) {
            const container = document.getElementById('comments-container');
            if (!container || !comment || !comment.indhold) return;

            const emptyState = container.querySelector('p.text-center.text-muted.my-3');
            if (emptyState) emptyState.remove();

            const author = String(comment.forfatter || 'Email Bot');
            const createdAtIso = String(comment.created_at || new Date().toISOString());
            const createdAtMs = new Date(createdAtIso).getTime();
            const createdAtUnix = Number.isFinite(createdAtMs) ? Math.floor(createdAtMs / 1000) : Math.floor(Date.now() / 1000);

            const item = document.createElement('div');
            item.className = 'comment-item comment-system';
            item.dataset.createdAt = String(createdAtUnix);

            const meta = document.createElement('div');
            meta.className = 'comment-meta';
            meta.innerHTML = `
                <span class="comment-avatar">${_escapeCommentHtml(_commentInitials(author))}</span>
                <b>${_escapeCommentHtml(author)}</b>
                <span class="comment-time">${_escapeCommentHtml(_formatCommentTime(createdAtIso))}</span>
            `;

            const body = document.createElement('div');
            body.className = 'comment-body';
            body.setAttribute('data-comment-raw', String(comment.indhold));
            body.textContent = String(comment.indhold);

            item.appendChild(meta);
            item.appendChild(body);
            container.insertBefore(item, container.firstChild);

            processCommentBodies();
            sortCommentsNewestFirst();
            _refreshCommentCountBadge();
        }

        let activeCommentQuickReply = null;

        window.closeInlineCommentQuickReply = function() {
            const host = document.getElementById('comment-quick-reply-host');
            if (host) host.innerHTML = '';
            activeCommentQuickReply = null;
        }

        window.sendInlineCommentQuickReply = async function() {
            const host = document.getElementById('comment-quick-reply-host');
            const textarea = document.getElementById('commentQuickReplyText');
            const sendBtn = document.getElementById('commentQuickReplySendBtn');
            const statusEl = document.getElementById('commentQuickReplyStatus');
            if (!host || !textarea || !sendBtn || !statusEl || !activeCommentQuickReply) return;

            const bodyText = String(textarea.value || '').trim();
            if (!bodyText) {
                statusEl.className = 'comment-quick-reply-status text-danger';
                statusEl.textContent = 'Skriv et svar';
                return;
            }

            const recipient = _extractEmailAddress(activeCommentQuickReply.recipient);
            if (!recipient || recipient.indexOf('@') === -1) {
                statusEl.className = 'comment-quick-reply-status text-danger';
                statusEl.textContent = 'Ingen gyldig modtager fundet i kommentaren';
                return;
            }

            sendBtn.disabled = true;
            statusEl.className = 'comment-quick-reply-status';
            statusEl.textContent = 'Sender...';

            try {
                await loadLinkedEmails();

                let threadEmailId = Number(activeCommentQuickReply.emailId) || null;
                if (!threadEmailId) {
                    threadEmailId = _findBestLinkedEmailByHeader(activeCommentQuickReply.header);
                }

                let threadKey = null;
                if (threadEmailId) {
                    const linked = linkedEmailsCache.find((entry) => Number(entry.id) === Number(threadEmailId));
                    threadKey = linked?.resolved_thread_key || linked?.thread_key || null;
                }

                const response = await fetch(`/api/v1/sag/${caseIds}/emails/send`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        to: [recipient],
                        subject: activeCommentQuickReply.subject,
                        body_text: bodyText,
                        thread_email_id: threadEmailId,
                        thread_key: threadKey
                    })
                });

                if (!response.ok) {
                    let message = `HTTP ${response.status}`;
                    try {
                        const payload = await response.json();
                        message = payload?.detail || payload?.message || message;
                    } catch (_) {
                    }
                    throw new Error(message);
                }

                const result = await response.json();
                if (result?.comment) {
                    prependCommentToThread(result.comment);
                }

                statusEl.className = 'comment-quick-reply-status text-success';
                statusEl.textContent = 'Svar sendt';
                textarea.value = '';
                await loadLinkedEmails();
                setTimeout(() => {
                    window.closeInlineCommentQuickReply();
                }, 500);
            } catch (error) {
                statusEl.className = 'comment-quick-reply-status text-danger';
                statusEl.textContent = error?.message || 'Kunne ikke sende svar';
            } finally {
                sendBtn.disabled = false;
            }
        }

        function openInlineCommentQuickReply(rawText, emailId) {
            const host = document.getElementById('comment-quick-reply-host');
            if (!host) return;

            const parsed = _parseEmailComment(rawText || '');
            const header = _extractEmailHeaderFields(parsed.visibleText || '');
            const fallbackRecipient = header.isOutgoing ? (header.til || header.fra) : (header.fra || header.til);
            const subject = /^re:\s*/i.test(header.emne || '')
                ? (header.emne || `Sag #${caseIds}`)
                : `Re: ${header.emne || `Sag #${caseIds}`}`;

            activeCommentQuickReply = {
                rawText,
                header,
                emailId: Number(emailId) || parsed.emailId || null,
                recipient: fallbackRecipient,
                subject
            };

            host.innerHTML = `
                <div class="comment-quick-reply-box">
                    <div class="small text-muted mb-1">Quick svar til ${_escapeCommentHtml(String(fallbackRecipient || 'ukendt modtager'))}</div>
                    <textarea id="commentQuickReplyText" class="form-control" rows="2" placeholder="Skriv hurtigt svar..."></textarea>
                    <div class="comment-quick-reply-actions">
                        <div id="commentQuickReplyStatus" class="comment-quick-reply-status"></div>
                        <div class="d-flex gap-2">
                            <button type="button" class="btn btn-sm btn-outline-secondary" onclick="closeInlineCommentQuickReply()">Annuller</button>
                            <button type="button" class="btn btn-sm btn-primary" id="commentQuickReplySendBtn" onclick="sendInlineCommentQuickReply()"><i class="bi bi-send me-1"></i>Send</button>
                        </div>
                    </div>
                </div>
            `;

            const textarea = document.getElementById('commentQuickReplyText');
            if (textarea) {
                textarea.focus();
            }
        }

        async function quickReplyToEmailFromCommentText(rawText) {
            openCaseEmailTab();

            const parsed = _parseEmailComment(rawText || '');
            const header = _extractEmailHeaderFields(parsed.visibleText || '');

            try {
                await loadLinkedEmails();

                const matchedEmailId = _findBestLinkedEmailByHeader(header);
                if (matchedEmailId) {
                    await loadLinkedEmailDetail(matchedEmailId);
                    openReplyToLinkedEmail();
                    return;
                }
            } catch (error) {
                console.error('Kunne ikke finde trådmail fra kommentar:', error);
            }

            const composeModalEl = document.getElementById('caseEmailComposeModal');
            if (!composeModalEl) return;

            const toInput = document.getElementById('caseEmailTo');
            const subjectInput = document.getElementById('caseEmailSubject');
            const bodyInput = document.getElementById('caseEmailBody');

            const fallbackRecipient = (header.isOutgoing ? header.til : header.fra) || header.fra || header.til || '';
            if (toInput && !toInput.value.trim() && fallbackRecipient) {
                toInput.value = fallbackRecipient;
            }

            if (subjectInput && !subjectInput.value.trim()) {
                subjectInput.value = escapeHtmlForInput(
                    /^re:\s*/i.test(header.emne || '')
                        ? (header.emne || `Sag #${caseIds}`)
                        : `Re: ${header.emne || `Sag #${caseIds}`}`
                );
            }

            if (bodyInput && !bodyInput.value.trim()) {
                bodyInput.value = `\n\n---\nFra: ${header.fra || '-'}\nDato: ${header.modtaget || '-'}\nEmne: ${header.emne || '(Ingen emne)'}\n`;
            }

            bootstrap.Modal.getOrCreateInstance(composeModalEl).show();
        }

        async function openEmailFromComment(emailId) {
            const parsedId = Number(emailId);
            if (!Number.isFinite(parsedId)) return;

            if (typeof openCaseEmailTab === 'function') {
                openCaseEmailTab();
            }

            try {
                if (typeof loadLinkedEmails === 'function') {
                    await loadLinkedEmails();
                }
                if (typeof loadLinkedEmailDetail === 'function') {
                    await loadLinkedEmailDetail(parsedId);
                }
                const emailTabPane = document.getElementById('emails');
                if (emailTabPane) {
                    emailTabPane.scrollIntoView({ behavior: 'smooth', block: 'start' });
                }
            } catch (error) {
                console.error('Kunne ikke åbne email fra kommentar:', error);
            }
        }

        function processCommentBodies() {
            const commentItems = Array.from(document.querySelectorAll('#comments-container .comment-item'));
            commentItems.forEach((item) => {
                const body = item.querySelector('.comment-body');
                if (!body) return;

                const rawText = body.dataset.commentRaw || body.textContent || '';
                if (!item.classList.contains('comment-system')) {
                    body.innerHTML = _escapeCommentHtml(String(rawText)).replace(/\n/g, '<br>');
                    return;
                }

                const hasEmailHeader = /(^|\n)\s*📧\s*(Indgående|Udgående)\s+email/i.test(String(rawText));
                if (!hasEmailHeader) {
                    body.innerHTML = _escapeCommentHtml(String(rawText)).replace(/\n/g, '<br>');
                    return;
                }

                const parsed = _parseEmailComment(rawText);
                const display = _buildEmailHeaderAndBody(parsed.visibleText || '');
                const safeHeader = _escapeCommentHtml(display.summary || 'Indgaaende email');
                const safeBody = _escapeCommentHtml(display.bodyText || '').replace(/\n/g, '<br>');
                body.innerHTML = `
                    <div class="comment-email-header" title="${safeHeader}">${safeHeader}</div>
                    ${display.bodyText ? `<div class="comment-email-text">${safeBody}</div>` : ''}
                `;

                const existingActions = item.querySelector('.comment-actions');
                if (existingActions) {
                    existingActions.remove();
                }

                if (parsed.emailId) {
                    const actions = document.createElement('div');
                    actions.className = 'comment-actions';
                    actions.innerHTML = `
                        <button type="button" class="btn btn-link btn-sm" onclick="openEmailFromComment(${parsed.emailId})"><i class="bi bi-envelope-open me-1"></i>Aabn fuld mail</button>
                        <button type="button" class="btn btn-link btn-sm" onclick="quickReplyToEmailFromComment(${parsed.emailId})"><i class="bi bi-reply me-1"></i>Svar</button>
                        <button type="button" class="btn btn-link btn-sm js-quick-inline-reply"><i class="bi bi-lightning-charge me-1"></i>Quick svar</button>
                    `;
                    item.appendChild(actions);
                    const quickInlineBtn = actions.querySelector('.js-quick-inline-reply');
                    if (quickInlineBtn) {
                        quickInlineBtn.addEventListener('click', () => {
                            openInlineCommentQuickReply(rawText, parsed.emailId);
                        });
                    }
                } else {
                    const actions = document.createElement('div');
                    actions.className = 'comment-actions';
                    actions.innerHTML = `
                        <button type="button" class="btn btn-link btn-sm" onclick="openCaseEmailTab()"><i class="bi bi-envelope me-1"></i>Aabn email-fane</button>
                        <button type="button" class="btn btn-link btn-sm js-reply-fallback"><i class="bi bi-reply me-1"></i>Svar</button>
                        <button type="button" class="btn btn-link btn-sm js-quick-reply-fallback"><i class="bi bi-lightning-charge me-1"></i>Quick svar</button>
                    `;
                    item.appendChild(actions);
                    const replyBtn = actions.querySelector('.js-reply-fallback');
                    if (replyBtn) {
                        replyBtn.addEventListener('click', () => {
                            quickReplyToEmailFromCommentText(rawText);
                        });
                    }
                    const quickReplyBtn = actions.querySelector('.js-quick-reply-fallback');
                    if (quickReplyBtn) {
                        quickReplyBtn.addEventListener('click', () => {
                            openInlineCommentQuickReply(rawText, null);
                        });
                    }
                }
            });
        }

        function sortCommentsNewestFirst() {
            const container = document.getElementById('comments-container');
            if (!container) return;

            const items = Array.from(container.querySelectorAll('.comment-item'));
            if (items.length < 2) return;

            items
                .sort((a, b) => Number(b.dataset.createdAt || 0) - Number(a.dataset.createdAt || 0))
                .forEach((item) => container.appendChild(item));
        }

        async function submitComment(event) {
            event.preventDefault();
            const form = event.target;
            const content = form.indhold.value;
            const btn = form.querySelector('button');
            const originalText = btn.innerHTML;
            
            btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span> Sender...';
            btn.disabled = true;
            
            try {
                const response = await fetch('/api/v1/sag/{{ case.id }}/kommentarer', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        indhold: content
                    })
                });

                if (response.ok) {
                    location.reload();
                } else {
                    alert('Fejl ved oprettelse af kommentar');
                    btn.innerHTML = originalText;
                    btn.disabled = false;
                }
            } catch (error) {
                console.error('Error:', error);
                alert('Der skete en fejl. Prøv igen.');
                btn.innerHTML = originalText;
                btn.disabled = false;
            }
        }
        
        // Keep newest comments visible at top
        document.addEventListener('DOMContentLoaded', function() {
            sortCommentsNewestFirst();
            processCommentBodies();
            const container = document.getElementById('comments-container');
            if(container) {
                container.scrollTop = 0;
            }
        });
    </script>

    <script>
        const salesCaseId = {{ case.id }};

        function formatCurrency(value) {
            const num = Number(value || 0);
            return new Intl.NumberFormat('da-DK', { style: 'currency', currency: 'DKK' }).format(num);
        }

        function formatNumber(value) {
            const num = Number(value || 0);
            return new Intl.NumberFormat('da-DK', { minimumFractionDigits: 0, maximumFractionDigits: 2 }).format(num);
        }

        let saleItemsCache = [];

        const purchasePurposeLabels = {
            salg: 'Salg',
            lager: 'Lager',
            asset: 'Asset',
            intern_brug: 'Intern brug',
            retur_reklamation: 'Retur/reklamation',
            projekt_omkostning: 'Projektomkostning'
        };

        function purchasePurposeLabel(value) {
            if (!value) return '-';
            return purchasePurposeLabels[value] || value;
        }

        async function loadVarekobSalg() {
            try {
                const res = await fetch(`/api/v1/sag/${salesCaseId}/varekob-salg?include_subcases=true`);
                if (!res.ok) throw new Error('Failed to load aggregated data');
                const data = await res.json();

                document.getElementById('salesTotalPurchase').textContent = formatCurrency(data?.totals?.purchase_total);
                document.getElementById('salesTotalSale').textContent = formatCurrency(data?.totals?.sale_total);
                document.getElementById('salesTotalNet').textContent = formatCurrency(data?.totals?.net_total);
                document.getElementById('salesTotalHours').textContent = formatNumber(data?.totals?.total_hours) + ' t';
                document.getElementById('salesBillableHours').textContent = formatNumber(data?.totals?.billable_hours) + ' t';

                saleItemsCache = data.sale_items || [];
                renderSaleItems(saleItemsCache);
                renderTimeEntries(data.time_entries || []);
                const hasSalesData = (data.sale_items || []).length > 0 || (data.time_entries || []).length > 0;
                setModuleContentState('sales', hasSalesData);
            } catch (error) {
                console.error(error);
                const saleBody = document.getElementById('saleItemsBody');
                if (saleBody) {
                    saleBody.innerHTML = '<tr><td colspan="10" class="text-center py-4 text-muted">Kunne ikke hente data</td></tr>';
                }
                const timeBody = document.getElementById('salesTimeBody');
                if (timeBody) {
                    timeBody.innerHTML = '<tr><td colspan="3" class="text-center py-4 text-muted">Kunne ikke hente data</td></tr>';
                }
                setModuleContentState('sales', true);
            }
        }

        function renderSaleItems(items) {
            const salesBody = document.getElementById('saleItemsSalesBody');
            const purchaseBody = document.getElementById('saleItemsPurchaseBody');
            const salesSubtotal = document.getElementById('salesLinesSubtotal');
            const purchaseSubtotal = document.getElementById('purchaseLinesSubtotal');
            if (!salesBody || !purchaseBody) return;

            const salesItems = items.filter(item => (item.type || '').toLowerCase() !== 'purchase');
            const purchaseItems = items.filter(item => (item.type || '').toLowerCase() === 'purchase');

            const renderRows = (list, isPurchase) => {
                if (!list.length) {
                    const columns = isPurchase ? 10 : 9;
                    return `<tr><td colspan="${columns}" class="text-center py-4 text-muted">Ingen linjer</td></tr>`;
                }

                return list.map(item => {
                    const statusLabel = item.status || 'draft';
                    const isSubcase = item.sag_id && item.sag_id !== salesCaseId;
                    const sourceBadge = isSubcase
                        ? `<span class="badge bg-warning text-dark ms-2">Under-sag</span>`
                        : `<span class="badge bg-light text-dark border ms-2">Denne sag</span>`;
                    const purposeCell = isPurchase
                        ? `<td><span class="badge bg-info-subtle text-dark border">${purchasePurposeLabel(item.purchase_purpose)}</span></td>`
                        : '';
                    return `
                        <tr>
                            <td class="ps-4">${item.line_date || '-'}</td>
                            <td>${item.description || '-'}</td>
                            <td>${item.quantity ?? '-'}</td>
                            <td>${item.unit || '-'}</td>
                            <td>${item.unit_price != null ? formatCurrency(item.unit_price) : '-'}</td>
                            <td class="fw-bold">${formatCurrency(item.amount)}</td>
                            ${purposeCell}
                            <td>${item.source_sag_titel || '-'}${sourceBadge}</td>
                            <td><span class="badge bg-light text-dark border">${statusLabel}</span></td>
                            <td class="text-end pe-4">
                                <div class="btn-group btn-group-sm" role="group">
                                    <button class="btn btn-outline-secondary" onclick='openSaleItemModalById(${item.id})'><i class="bi bi-pencil"></i></button>
                                    <button class="btn btn-outline-danger" onclick='deleteSaleItem(${item.id})'><i class="bi bi-trash"></i></button>
                                </div>
                            </td>
                        </tr>
                    `;
                }).join('');
            };

            salesBody.innerHTML = renderRows(salesItems, false);
            purchaseBody.innerHTML = renderRows(purchaseItems, true);

            const salesSum = salesItems.reduce((sum, item) => sum + Number(item.amount || 0), 0);
            const purchaseSum = purchaseItems.reduce((sum, item) => sum + Number(item.amount || 0), 0);
            if (salesSubtotal) salesSubtotal.textContent = formatCurrency(salesSum);
            if (purchaseSubtotal) purchaseSubtotal.textContent = formatCurrency(purchaseSum);
        }

        function renderTimeEntries(entries) {
            const tbody = document.getElementById('salesTimeBody');
            if (!tbody) return;
            if (!entries.length) {
                tbody.innerHTML = '<tr><td colspan="3" class="text-center py-4 text-muted">Ingen tid registreret</td></tr>';
                return;
            }

            tbody.innerHTML = entries.map(entry => {
                const hours = entry.approved_hours || entry.original_hours || 0;
                const isSubcase = entry.sag_id && entry.sag_id !== salesCaseId;
                const sourceBadge = isSubcase
                    ? `<span class="badge bg-warning text-dark ms-2">Under-sag</span>`
                    : `<span class="badge bg-light text-dark border ms-2">Denne sag</span>`;
                return `
                    <tr>
                        <td class="ps-3">${entry.worked_date || '-'}</td>
                        <td>${formatNumber(hours)} t</td>
                        <td>${entry.source_sag_titel || '-'}${sourceBadge}</td>
                    </tr>
                `;
            }).join('');
        }

        function openSaleItemModal(item = null) {
            document.getElementById('sale_item_id').value = item?.id || '';
            document.getElementById('sale_type').value = item?.type || 'sale';
            document.getElementById('sale_status').value = item?.status || 'draft';
            document.getElementById('sale_date').value = item?.line_date || '';
            document.getElementById('sale_description').value = item?.description || '';
            document.getElementById('sale_quantity').value = item?.quantity ?? '';
            document.getElementById('sale_unit').value = item?.unit || '';
            document.getElementById('sale_unit_price').value = item?.unit_price ?? '';
            document.getElementById('sale_amount').value = item?.amount ?? '';
            document.getElementById('sale_currency').value = item?.currency || 'DKK';
            document.getElementById('sale_external_ref').value = item?.external_ref || '';
            document.getElementById('sale_purchase_purpose').value = item?.purchase_purpose || '';
            document.getElementById('sale_supplier_invoice_id').value = item?.supplier_invoice_id || '';
            document.getElementById('sale_supplier_invoice_line_id').value = item?.supplier_invoice_line_id || '';

            togglePurchaseFields();

            new bootstrap.Modal(document.getElementById('saleItemModal')).show();
        }

        function togglePurchaseFields() {
            const type = document.getElementById('sale_type').value;
            const purchaseFields = document.getElementById('sale_purchase_fields');
            if (!purchaseFields) return;

            if (type === 'purchase') {
                purchaseFields.classList.remove('d-none');
            } else {
                purchaseFields.classList.add('d-none');
                document.getElementById('sale_purchase_purpose').value = '';
                document.getElementById('sale_supplier_invoice_id').value = '';
                document.getElementById('sale_supplier_invoice_line_id').value = '';
            }
        }

        function openSaleItemModalById(itemId) {
            const item = saleItemsCache.find((entry) => entry.id === itemId);
            openSaleItemModal(item || null);
        }

        function updateSaleAmount() {
            const qty = parseFloat(document.getElementById('sale_quantity').value || 0);
            const price = parseFloat(document.getElementById('sale_unit_price').value || 0);
            if (qty && price) {
                document.getElementById('sale_amount').value = (qty * price).toFixed(2);
            }
        }

        async function saveSaleItem() {
            const itemId = document.getElementById('sale_item_id').value;
            const payload = {
                type: document.getElementById('sale_type').value,
                status: document.getElementById('sale_status').value,
                line_date: document.getElementById('sale_date').value || null,
                description: document.getElementById('sale_description').value,
                quantity: document.getElementById('sale_quantity').value || null,
                unit: document.getElementById('sale_unit').value || null,
                unit_price: document.getElementById('sale_unit_price').value || null,
                amount: document.getElementById('sale_amount').value,
                currency: document.getElementById('sale_currency').value || 'DKK',
                external_ref: document.getElementById('sale_external_ref').value || null,
                purchase_purpose: document.getElementById('sale_purchase_purpose').value || null,
                supplier_invoice_id: document.getElementById('sale_supplier_invoice_id').value || null,
                supplier_invoice_line_id: document.getElementById('sale_supplier_invoice_line_id').value || null
            };

            if (payload.type !== 'purchase') {
                payload.purchase_purpose = null;
                payload.supplier_invoice_id = null;
                payload.supplier_invoice_line_id = null;
            }

            if (!payload.description || !payload.amount) {
                alert('Beskrivelse og linjesum er påkrævet.');
                return;
            }

            const method = itemId ? 'PATCH' : 'POST';
            const url = itemId
                ? `/api/v1/sag/${salesCaseId}/sale-items/${itemId}`
                : `/api/v1/sag/${salesCaseId}/sale-items`;

            const res = await fetch(url, {
                method,
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload)
            });

            if (!res.ok) {
                alert('Kunne ikke gemme varelinje');
                return;
            }

            bootstrap.Modal.getInstance(document.getElementById('saleItemModal')).hide();
            await loadVarekobSalg();
        }

        async function deleteSaleItem(itemId) {
            if (!confirm('Vil du slette denne varelinje?')) return;
            const res = await fetch(`/api/v1/sag/${salesCaseId}/sale-items/${itemId}`, { method: 'DELETE' });
            if (!res.ok) {
                alert('Kunne ikke slette varelinje');
                return;
            }
            await loadVarekobSalg();
        }

        document.addEventListener('DOMContentLoaded', function() {
            const qtyInput = document.getElementById('sale_quantity');
            const priceInput = document.getElementById('sale_unit_price');
            const typeInput = document.getElementById('sale_type');
            if (qtyInput) qtyInput.addEventListener('input', updateSaleAmount);
            if (priceInput) priceInput.addEventListener('input', updateSaleAmount);
            if (typeInput) typeInput.addEventListener('change', togglePurchaseFields);
            loadVarekobSalg();
        });
    </script>

    <script>
        const supplierCaseId = {{ case.id }};

        function supplierStatusBadge(status) {
            const value = String(status || '').toLowerCase();
            if (value === 'godkendt') return '<span class="badge bg-primary-subtle text-primary-emphasis">Godkendt</span>';
            if (value === 'betalt') return '<span class="badge bg-success-subtle text-success-emphasis">Betalt</span>';
            if (value === 'afvist') return '<span class="badge bg-danger-subtle text-danger-emphasis">Afvist</span>';
            return '<span class="badge bg-warning-subtle text-warning-emphasis">Modtaget</span>';
        }

        function inferSupplierFlowSuggestion() {
            const purchaseItems = (saleItemsCache || []).filter((item) => (item.type || '').toLowerCase() === 'purchase');
            if (purchaseItems.length > 0) {
                return { type: 'varekob', confidence: 0.87, reason: 'Sag har indkøbslinjer fra leverandørflow' };
            }

            const purchaseText = (saleItemsCache || [])
                .filter((item) => (item.type || '').toLowerCase() === 'purchase')
                .map((item) => String(item.description || '').toLowerCase())
                .join(' ');

            if (/(abonnement|hosting|licens|service|konsulent|rengoering|husleje)/.test(purchaseText)) {
                return { type: 'ydelse', confidence: 0.76, reason: 'Beskrivelser matcher ydelsesmønstre' };
            }

            return null;
        }

        function renderSupplierSuggestion() {
            const suggestionEl = document.getElementById('supplierFlowSuggestion');
            if (!suggestionEl) return;

            const suggestion = inferSupplierFlowSuggestion();
            if (!suggestion) {
                suggestionEl.innerHTML = '<span class="text-muted">Ingen sikker AI-indikation endnu</span>';
                return;
            }

            suggestionEl.innerHTML = `
                <div><strong>Forslag:</strong> ${suggestion.type === 'varekob' ? 'Varekøb' : 'Købt ydelse'}</div>
                <div class="small text-muted">Confidence: ${(suggestion.confidence * 100).toFixed(0)}% · ${suggestion.reason}</div>
                <button class="btn btn-sm btn-outline-primary mt-2" onclick="applySupplierSuggestion('${suggestion.type}', ${suggestion.confidence})">
                    <i class="bi bi-magic me-1"></i>Anvend forslag
                </button>
            `;
        }

        function applySupplierSuggestion(type, confidence) {
            const typeEl = document.getElementById('supplierFlowTypeSelect');
            const confEl = document.getElementById('supplierFlowConfidenceInput');
            if (typeEl) typeEl.value = type;
            if (confEl) confEl.value = Number(confidence).toFixed(2);
            toggleSupplierTypePanels();
        }

        function toggleSupplierTypePanels() {
            const type = document.getElementById('supplierFlowTypeSelect')?.value || '';
            const varekobPanel = document.getElementById('supplierVarekobPanel');
            const ydelsePanel = document.getElementById('supplierYdelsePanel');
            if (varekobPanel) varekobPanel.style.display = type === 'varekob' ? '' : 'none';
            if (ydelsePanel) ydelsePanel.style.display = type === 'ydelse' ? '' : 'none';
            if (type === 'varekob') {
                renderSupplierPurchasePurposeRows();
            }
        }

        async function saveSupplierFlowType() {
            const type = document.getElementById('supplierFlowTypeSelect')?.value || null;
            const confidenceRaw = document.getElementById('supplierFlowConfidenceInput')?.value || null;

            const payload = {
                supplier_flow_type: type,
                supplier_flow_confidence: confidenceRaw === null || confidenceRaw === '' ? null : Number(confidenceRaw)
            };

            const res = await fetch(`/api/v1/sag/${supplierCaseId}`, {
                method: 'PATCH',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload)
            });

            if (!res.ok) {
                alert('Kunne ikke gemme leverandørflow type');
                return;
            }

            alert('Leverandørflow type gemt');
            toggleSupplierTypePanels();
        }

        function renderSupplierPurchasePurposeRows() {
            const body = document.getElementById('supplierPurchaseLinesBody');
            const countBadge = document.getElementById('supplierPurchaseLinesCount');
            if (!body) return;

            const purchases = (saleItemsCache || []).filter((item) => (item.type || '').toLowerCase() === 'purchase');
            if (countBadge) countBadge.textContent = `${purchases.length} linjer`;

            if (!purchases.length) {
                body.innerHTML = '<tr><td colspan="4" class="text-center py-4 text-muted">Ingen indkøbslinjer fundet på denne sag</td></tr>';
                return;
            }

            body.innerHTML = purchases.map((item) => `
                <tr>
                    <td class="ps-3">${item.description || '-'}</td>
                    <td>${formatCurrency(item.amount || 0)}</td>
                    <td>
                        <select class="form-select form-select-sm" id="supplierPurpose-${item.id}">
                            <option value="">Vælg...</option>
                            <option value="salg" ${item.purchase_purpose === 'salg' ? 'selected' : ''}>Videresalg</option>
                            <option value="asset" ${item.purchase_purpose === 'asset' ? 'selected' : ''}>Opret som Asset</option>
                            <option value="intern_brug" ${item.purchase_purpose === 'intern_brug' ? 'selected' : ''}>Intern brug</option>
                            <option value="projekt_omkostning" ${item.purchase_purpose === 'projekt_omkostning' ? 'selected' : ''}>Forbrug/omkostning</option>
                            <option value="lager" ${item.purchase_purpose === 'lager' ? 'selected' : ''}>Lager</option>
                            <option value="retur_reklamation" ${item.purchase_purpose === 'retur_reklamation' ? 'selected' : ''}>Retur/reklamation</option>
                        </select>
                    </td>
                    <td class="text-end pe-3">
                        <button class="btn btn-sm btn-outline-primary" onclick="saveSupplierPurchasePurpose(${item.id})">
                            <i class="bi bi-save"></i>
                        </button>
                    </td>
                </tr>
            `).join('');
        }

        async function saveSupplierPurchasePurpose(itemId) {
            const purpose = document.getElementById(`supplierPurpose-${itemId}`)?.value || null;
            const res = await fetch(`/api/v1/sag/${supplierCaseId}/sale-items/${itemId}`, {
                method: 'PATCH',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    type: 'purchase',
                    purchase_purpose: purpose
                })
            });

            if (!res.ok) {
                alert('Kunne ikke gemme linjehandling');
                return;
            }

            await loadVarekobSalg();
            renderSupplierPurchasePurposeRows();
        }

        async function registerSupplierServiceHandling(actionCode) {
            const serviceType = document.getElementById('supplierServiceType')?.value || '';
            const fromDate = document.getElementById('supplierServiceFrom')?.value || '';
            const toDate = document.getElementById('supplierServiceTo')?.value || '';
            const amount = document.getElementById('supplierServiceAmount')?.value || '';

            const content = [
                'Supplier ydelse-handling registreret',
                `Handling: ${actionCode}`,
                `Type: ${serviceType}`,
                `Periode: ${fromDate || '-'} -> ${toDate || '-'}`,
                `Beløb: ${amount || '-'} DKK`,
            ].join('\n');

            const res = await fetch(`/api/v1/sag/${supplierCaseId}/kommentarer`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    indhold: content,
                    er_system_besked: true,
                    forfatter: 'Supplier Flow'
                })
            });

            if (!res.ok) {
                alert('Kunne ikke registrere ydelseshandling');
                return;
            }

            alert('Ydelseshandling registreret på sagen');
        }

        async function supplierApproveInvoice(invoiceId) {
            const approvedBy = prompt('Hvem godkender?', 'System');
            if (!approvedBy) return;

            const res = await fetch(`/api/v1/supplier-invoices/${invoiceId}/approve`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ approved_by: approvedBy })
            });
            if (!res.ok) {
                const msg = await res.text();
                alert(`Kunne ikke godkende faktura: ${msg}`);
                return;
            }
            await loadSupplierModule();
        }

        async function supplierRejectInvoice(invoiceId) {
            const rejectedBy = prompt('Hvem afviser?', 'System');
            if (!rejectedBy) return;
            const reason = prompt('Årsag til afvisning (valgfri):', '') || null;

            const res = await fetch(`/api/v1/supplier-invoices/${invoiceId}/reject`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ rejected_by: rejectedBy, reason })
            });
            if (!res.ok) {
                const msg = await res.text();
                alert(`Kunne ikke afvise faktura: ${msg}`);
                return;
            }
            await loadSupplierModule();
        }

        async function supplierMarkPaid(invoiceId) {
            const amountRaw = prompt('Betalingsbeløb (tom = restbeløb):', '');
            const amount = amountRaw && amountRaw.trim() !== '' ? Number(amountRaw) : null;
            if (amountRaw && (!Number.isFinite(amount) || amount <= 0)) {
                alert('Ugyldigt beløb');
                return;
            }

            const method = prompt('Betalingsmetode (fx bank):', '') || null;
            const reference = prompt('Betalingsreference (valgfri):', '') || null;
            const paidBy = prompt('Registreret af:', 'System') || 'System';

            const res = await fetch(`/api/v1/supplier-invoices/${invoiceId}/mark-paid`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    amount,
                    payment_method: method,
                    payment_reference: reference,
                    paid_by: paidBy
                })
            });

            if (!res.ok) {
                const msg = await res.text();
                alert(`Kunne ikke registrere betaling: ${msg}`);
                return;
            }

            await loadSupplierModule();
        }

        function renderSupplierInvoices(items) {
            const body = document.getElementById('supplierInvoicesBody');
            if (!body) return;

            if (!items || !items.length) {
                body.innerHTML = '<tr><td colspan="4" class="text-center py-4 text-muted">Ingen leverandørfakturaer på sagen</td></tr>';
                return;
            }

            body.innerHTML = items.map((inv) => {
                const statusV2 = inv.status_v2 || 'modtaget';
                return `
                    <tr>
                        <td class="ps-3">
                            <div class="fw-semibold">${inv.invoice_number || `ID-${inv.id}`}</div>
                            <div class="small text-muted">${inv.invoice_date || '-'}</div>
                        </td>
                        <td>${formatCurrency(inv.total_amount || 0)}</td>
                        <td>${supplierStatusBadge(statusV2)}</td>
                        <td class="text-end pe-3">
                            <div class="btn-group btn-group-sm">
                                <button class="btn btn-outline-primary" onclick="supplierApproveInvoice(${inv.id})" title="Godkend"><i class="bi bi-check2"></i></button>
                                <button class="btn btn-outline-danger" onclick="supplierRejectInvoice(${inv.id})" title="Afvis"><i class="bi bi-x"></i></button>
                                <button class="btn btn-outline-success" onclick="supplierMarkPaid(${inv.id})" title="Registrer betaling"><i class="bi bi-cash"></i></button>
                            </div>
                        </td>
                    </tr>
                `;
            }).join('');
        }

        async function loadSupplierModule() {
            const body = document.getElementById('supplierInvoicesBody');
            if (body) {
                body.innerHTML = '<tr><td colspan="4" class="text-center py-4 text-muted">Indlæser...</td></tr>';
            }

            try {
                const res = await fetch(`/api/v1/supplier-invoices?sag_id=${supplierCaseId}`);
                if (!res.ok) throw new Error('Kunne ikke hente leverandørfakturaer');
                const items = await res.json();
                renderSupplierInvoices(items || []);
                renderSupplierSuggestion();
                toggleSupplierTypePanels();
                setModuleContentState('supplier', (items || []).length > 0);
            } catch (error) {
                console.error(error);
                if (body) {
                    body.innerHTML = '<tr><td colspan="4" class="text-center py-4 text-muted">Kunne ikke hente leverandørfakturaer</td></tr>';
                }
                setModuleContentState('supplier', true);
            }
        }

        document.addEventListener('DOMContentLoaded', function() {
            loadSupplierModule();
            toggleSupplierTypePanels();
        });
    </script>

    <script>
        const timeCaseId = {{ case.id }};
        let timeV1EntriesById = {};

        function minutesToLabel(minutes) {
            const value = Number(minutes || 0);
            const h = Math.floor(value / 60);
            const m = value % 60;
            return `${h}t ${m}m`;
        }

        function timeStatusBadge(status) {
            if (status === 'godkendt') return '<span class="badge bg-success">Godkendt</span>';
            if (status === 'kladde') return '<span class="badge bg-secondary">Kladde</span>';
            return '<span class="badge bg-warning text-dark">Afventer</span>';
        }

        function renderTimeV1Timeline(entries) {
            const timeline = document.getElementById('timeTimelineColumns');
            if (!timeline) return;

            if (!entries || entries.length === 0) {
                timeline.innerHTML = '<div class="text-muted text-center p-4">Ingen tidsregistreringer endnu</div>';
                return;
            }

            const START_HOUR = 7;
            const TOTAL_HOURS = 10;
            const HOUR_HEIGHT = 60;

            const PALETTE = [
                { border: '#0f4c75', bg: 'rgba(15,76,117,0.09)',  header: 'rgba(15,76,117,0.08)'  },
                { border: '#ef4444', bg: 'rgba(239,68,68,0.09)',   header: 'rgba(239,68,68,0.08)'  },
                { border: '#10b981', bg: 'rgba(16,185,129,0.09)',  header: 'rgba(16,185,129,0.08)' },
                { border: '#f59e0b', bg: 'rgba(245,158,11,0.09)',  header: 'rgba(245,158,11,0.08)' },
                { border: '#8b5cf6', bg: 'rgba(139,92,246,0.09)', header: 'rgba(139,92,246,0.08)' },
                { border: '#ec4899', bg: 'rgba(236,72,153,0.09)', header: 'rgba(236,72,153,0.08)' },
                { border: '#06b6d4', bg: 'rgba(6,182,212,0.09)',   header: 'rgba(6,182,212,0.08)'  },
                { border: '#f97316', bg: 'rgba(249,115,22,0.09)',  header: 'rgba(249,115,22,0.08)' },
            ];

            const allUsers = [...new Set(entries.map(e => e.employee_display_name || e.bruger_navn || e.user_name || 'Ukendt'))].sort();
            const userColor = {};
            allUsers.forEach((u, i) => { userColor[u] = PALETTE[i % PALETTE.length]; });

            const groupedByDate = {};
            entries.forEach(entry => {
                let dateKey;
                if (entry.start_tid)        dateKey = entry.start_tid.substring(0, 10);
                else if (entry.worked_date) dateKey = entry.worked_date.substring(0, 10);
                else if (entry.created_at)  dateKey = entry.created_at.substring(0, 10);
                else                        dateKey = 'Ukendt dato';
                if (!groupedByDate[dateKey]) groupedByDate[dateKey] = [];
                groupedByDate[dateKey].push(entry);
            });

            const sortedDates = Object.keys(groupedByDate).sort((a, b) => new Date(b) - new Date(a));
            let html = '';

            sortedDates.forEach(dateStr => {
                const dayEntries = groupedByDate[dateStr];
                let dateLab = dateStr;
                try {
                    const d = new Date(dateStr);
                    if (!isNaN(d.getTime())) {
                        dateLab = d.toLocaleDateString('da-DK', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });
                        dateLab = dateLab.charAt(0).toUpperCase() + dateLab.slice(1);
                    }
                } catch(e) {}

                const techPlaced = {};
                const unplaced = [];
                const userTotals = {};
                const techMeta = {};

                dayEntries.forEach(entry => {
                    const tech = entry.employee_display_name || entry.bruger_navn || entry.user_name || 'Ukendt';
                    const mins = entry.faktisk_tid_min
                        ? parseInt(entry.faktisk_tid_min)
                        : Math.round(parseFloat(entry.original_hours || entry.timer || 0) * 60);
                    userTotals[tech] = (userTotals[tech] || 0) + mins;
                    if (!techMeta[tech]) {
                        techMeta[tech] = {
                            medarbejderId: entry.medarbejder_id || null,
                            userName: entry.user_name || null,
                        };
                    }
                    if (entry.start_tid) {
                        if (!techPlaced[tech]) techPlaced[tech] = [];
                        techPlaced[tech].push(entry);
                    } else {
                        unplaced.push(entry);
                    }
                });

                const techNames = Object.keys(userTotals).sort();

                html += `<div class="time-v1-calendar-container">
                    <div class="time-v1-calendar-header">
                        <i class="bi bi-calendar3 text-primary"></i> ${dateLab}
                    </div>
                    <div class="time-v1-calendar-grid">
                        <div class="time-v1-time-axis">`;

                for (let i = 0; i <= TOTAL_HOURS; i++) {
                    const h = START_HOUR + i;
                    html += `<div class="time-v1-hour-marker" style="top:${i * HOUR_HEIGHT}px">${String(h).padStart(2,'0')}:00</div>`;
                }
                html += `</div>`;

                techNames.forEach(tech => {
                    const c   = userColor[tech] || PALETTE[0];
                    const tot = userTotals[tech] || 0;
                    const techInfo = techMeta[tech] || {};
                    const techEmployeeId = techInfo.medarbejderId != null ? String(techInfo.medarbejderId) : '';
                    const totS = tot >= 60
                        ? `${Math.floor(tot/60)}t${tot%60 ? ' '+tot%60+'m' : ''}`
                        : `${tot}m`;

                    html += `<div class="time-v1-tech-col" style="border-top:3px solid ${c.border};">
                        <div class="time-v1-tech-header" style="background:${c.header};">
                            <i class="bi bi-person-fill" style="color:${c.border};"></i>
                            <span style="color:${c.border};font-weight:600;">${escapeHtml(tech)}</span>
                            <span class="ms-auto badge" style="background:${c.border};color:#fff;font-size:0.7rem;">${totS}</span>
                        </div>
                        <div class="time-v1-tech-body" data-date="${dateStr}" data-tech="${escapeHtml(tech)}" data-medarbejder-id="${techEmployeeId}">`;

                    const posEntries = [];
                    (techPlaced[tech] || []).forEach(entry => {
                        const desc = escapeHtml(entry.beskrivelse || entry.description || 'Ingen beskrivelse');
                        const startObj = new Date(entry.start_tid);
                        let durMin = 30;
                        if (entry.faktisk_tid_min)                    durMin = parseInt(entry.faktisk_tid_min);
                        else if (entry.original_hours || entry.timer) durMin = Math.round(parseFloat(entry.original_hours || entry.timer) * 60);

                        let sH = startObj.getHours(), sM = startObj.getMinutes();
                        if (sH < START_HOUR) { durMin -= (START_HOUR * 60 - sH * 60 - sM); sH = START_HOUR; sM = 0; }

                        let topPx    = ((sH - START_HOUR) + sM / 60) * HOUR_HEIGHT;
                        let heightPx = (durMin / 60) * HOUR_HEIGHT;
                        if (topPx < 0) topPx = 0;
                        if (topPx + heightPx > TOTAL_HOURS * HOUR_HEIGHT) heightPx = TOTAL_HOURS * HOUR_HEIGHT - topPx;

                        if (heightPx > 5 && topPx < TOTAL_HOURS * HOUR_HEIGHT) {
                            const endObj  = new Date(startObj.getTime() + durMin * 60000);
                            const timeStr = `${String(startObj.getHours()).padStart(2,'0')}:${String(startObj.getMinutes()).padStart(2,'0')} \u2013 ${String(endObj.getHours()).padStart(2,'0')}:${String(endObj.getMinutes()).padStart(2,'0')}`;
                            posEntries.push({
                                topPx,
                                heightPx,
                                desc,
                                timeStr,
                                startMin: topPx,
                                endMin: topPx + heightPx,
                                entryId: entry.id,
                                durationMin: Math.max(1, durMin || 0),
                                entryStatus: entry.entry_status || 'afventer',
                            });
                        }
                    });

                    posEntries.sort((a, b) => a.startMin - b.startMin);
                    const lanes = [];
                    posEntries.forEach(e => {
                        let placed = false;
                        for (let li = 0; li < lanes.length; li++) {
                            if (lanes[li] <= e.startMin) { e.lane = li; lanes[li] = e.endMin; placed = true; break; }
                        }
                        if (!placed) { e.lane = lanes.length; lanes.push(e.endMin); }
                    });
                    const numLanes = lanes.length || 1;

                    posEntries.forEach(e => {
                        e.laneSpan = 1;
                        for (let li = e.lane + 1; li < numLanes; li++) {
                            if (!posEntries.some(o => o !== e && o.lane === li && o.startMin < e.endMin && o.endMin > e.startMin)) e.laneSpan++;
                            else break;
                        }
                        const lW = 100 / numLanes;
                        html += `<div class="time-v1-entry-block time-v1-entry-${e.entryStatus}"
                             draggable="true"
                             data-entry-id="${e.entryId}"
                             data-duration-min="${e.durationMin}"
                             style="top:${e.topPx}px;height:${e.heightPx}px;left:${(e.lane*lW).toFixed(1)}%;width:calc(${(e.laneSpan*lW).toFixed(1)}% - 3px);border-left-color:${c.border};background:${c.bg};"
                                title="Dobbeltklik for detaljeret redigering\n${e.desc}">
                            <div class="time-v1-entry-time">${e.timeStr}</div>
                            <div class="time-v1-entry-desc">${e.desc}</div>
                        </div>`;
                    });

                    html += `</div></div>`;
                });

                html += `</div>`;

                if (unplaced.length > 0) {
                    html += `<div class="time-v1-unplaced-container">
                        <span class="text-muted small fw-semibold me-2"><i class="bi bi-clock-history"></i> Uden tidsrum:</span>`;
                    unplaced.forEach(u => {
                        const tech = u.employee_display_name || u.bruger_navn || u.user_name || 'Ukendt';
                        const c    = userColor[tech] || PALETTE[0];
                        const mins = u.faktisk_tid_min ? parseInt(u.faktisk_tid_min) : Math.round(parseFloat(u.original_hours || u.timer || 0) * 60);
                        const hStr = mins >= 60 ? `${Math.floor(mins/60)}t${mins%60?' '+mins%60+'m':''}` : `${mins}m`;
                        const desc = escapeHtml(u.beskrivelse || u.description || '');
                        html += `<div class="time-v1-unplaced-item"
                            draggable="true"
                            data-entry-id="${u.id}"
                            data-duration-min="${Math.max(1, mins || 0)}"
                            title="Dobbeltklik for detaljeret redigering"
                            style="border-color:${c.border};color:${c.border};">
                            <i class="bi bi-person-fill"></i> ${escapeHtml(tech)} &bull; ${hStr}${desc ? ' &middot; <em style="opacity:.7;font-size:.72rem">'+desc+'</em>' : ''}
                        </div>`;
                    });
                    html += `</div>`;
                }

                html += `</div>`;
            });

            timeline.innerHTML = html;
            initTimeV1DragAndDrop();
        }

        function renderTimeV1Summary(entries) {
            const summaryEl = document.getElementById('timeSummaryEntries');
            if (!summaryEl) return;

            if (!entries || entries.length === 0) {
                summaryEl.innerHTML = '<div class="text-muted small">Ingen tidsregistreringer på sagen endnu.</div>';
                return;
            }

            const statusLabel = (status) => {
                if (status === 'godkendt') return 'Godkendt';
                if (status === 'kladde') return 'Kladde';
                return 'Afventer';
            };

            const typeLabel = (type) => {
                const t = String(type || 'ukendt').toLowerCase();
                if (t === 'opkald') return 'Opkald';
                if (t === 'mail') return 'Mail';
                if (t === 'anydesk' || t === 'indedesk') return 'AnyDesk';
                if (t === 'manuel') return 'Manuel';
                return 'Ukendt';
            };

            const sorted = [...entries].sort((a, b) => {
                const aKey = a.start_tid || a.worked_date || a.created_at || '';
                const bKey = b.start_tid || b.worked_date || b.created_at || '';
                return String(bKey).localeCompare(String(aKey));
            });

            let totalActualMin = 0;
            let totalBillableMin = 0;
            const byStatus = { kladde: 0, afventer: 0, godkendt: 0 };
            const byType = {};

            sorted.forEach((entry) => {
                const actual = entry.faktisk_tid_min != null
                    ? Number(entry.faktisk_tid_min)
                    : Math.round(Number(entry.original_hours || entry.timer || 0) * 60);
                const billable = entry.fakturerbar_tid_min != null
                    ? Number(entry.fakturerbar_tid_min)
                    : actual;

                totalActualMin += Number.isFinite(actual) ? actual : 0;
                totalBillableMin += Number.isFinite(billable) ? billable : 0;

                const st = String(entry.entry_status || 'afventer').toLowerCase();
                if (Object.prototype.hasOwnProperty.call(byStatus, st)) {
                    byStatus[st] += 1;
                } else {
                    byStatus.afventer += 1;
                }

                const tp = String(entry.entry_type || 'ukendt').toLowerCase();
                byType[tp] = (byType[tp] || 0) + 1;
            });

            const typeRows = Object.entries(byType)
                .sort((a, b) => b[1] - a[1])
                .map(([key, count]) => `<span class="badge bg-light text-dark border">${escapeHtml(typeLabel(key))}: ${count}</span>`)
                .join(' ');

            const detailRows = sorted.map((entry) => {
                const tech = entry.employee_display_name || entry.bruger_navn || entry.user_name || 'Ukendt';
                const actual = entry.faktisk_tid_min != null
                    ? Number(entry.faktisk_tid_min)
                    : Math.round(Number(entry.original_hours || entry.timer || 0) * 60);
                const dateValue = entry.worked_date || (entry.start_tid ? String(entry.start_tid).slice(0, 10) : null) || '-';

                let timeLabel = 'Uden tidsrum';
                if (entry.start_tid) {
                    const start = new Date(entry.start_tid);
                    if (!Number.isNaN(start.getTime())) {
                        if (entry.slut_tid) {
                            const end = new Date(entry.slut_tid);
                            if (!Number.isNaN(end.getTime())) {
                                timeLabel = `${String(start.getHours()).padStart(2, '0')}:${String(start.getMinutes()).padStart(2, '0')} - ${String(end.getHours()).padStart(2, '0')}:${String(end.getMinutes()).padStart(2, '0')}`;
                            } else {
                                timeLabel = `${String(start.getHours()).padStart(2, '0')}:${String(start.getMinutes()).padStart(2, '0')}`;
                            }
                        } else {
                            timeLabel = `${String(start.getHours()).padStart(2, '0')}:${String(start.getMinutes()).padStart(2, '0')}`;
                        }
                    }
                }

                const desc = escapeHtml(entry.beskrivelse || entry.description || 'Ingen beskrivelse');
                return `
                    <div class="border rounded p-2 mb-2" data-time-summary-entry-id="${entry.id}">
                        <div class="d-flex justify-content-between align-items-start gap-2 mb-1">
                            <div class="small fw-semibold">${escapeHtml(tech)}</div>
                            <span class="badge bg-light text-dark border">${statusLabel(entry.entry_status)}</span>
                        </div>
                        <div class="small text-muted">${escapeHtml(dateValue)} • ${escapeHtml(timeLabel)} • ${minutesToLabel(actual)}</div>
                        <div class="small text-muted">Type: ${escapeHtml(typeLabel(entry.entry_type))}</div>
                        <div class="small mt-1">${desc}</div>
                    </div>
                `;
            }).join('');

            summaryEl.innerHTML = `
                <div class="small mb-3">
                    <div class="d-flex justify-content-between"><span class="text-muted">Registreringer</span><strong>${sorted.length}</strong></div>
                    <div class="d-flex justify-content-between"><span class="text-muted">Faktisk tid</span><strong>${minutesToLabel(totalActualMin)}</strong></div>
                    <div class="d-flex justify-content-between"><span class="text-muted">Fakturerbar tid</span><strong>${minutesToLabel(totalBillableMin)}</strong></div>
                </div>

                <div class="small mb-2 text-muted">Status</div>
                <div class="d-flex flex-wrap gap-1 mb-3">
                    <span class="badge bg-light text-dark border">Godkendt: ${byStatus.godkendt}</span>
                    <span class="badge bg-light text-dark border">Afventer: ${byStatus.afventer}</span>
                    <span class="badge bg-light text-dark border">Kladde: ${byStatus.kladde}</span>
                </div>

                <div class="small mb-2 text-muted">Typer</div>
                <div class="d-flex flex-wrap gap-1 mb-3">${typeRows || '<span class="badge bg-light text-dark border">Ingen</span>'}</div>

                <div class="small mb-2 text-muted">Detaljer (alle registreringer)</div>
                <div style="max-height: 54vh; overflow:auto;">
                    ${detailRows}
                </div>
            `;
        }

        let timeV1DragBusy = false;

        function parseTimeV1DragPayload(event) {
            const raw = event.dataTransfer?.getData('text/plain');
            if (!raw) return null;
            try {
                const parsed = JSON.parse(raw);
                if (!parsed || !parsed.entryId) return null;
                return {
                    entryId: Number(parsed.entryId),
                    durationMin: Math.max(1, Number(parsed.durationMin || 30)),
                };
            } catch (e) {
                return null;
            }
        }

        function toIsoLocalFromDateMinutes(dateStr, totalMinutes) {
            const mins = Math.max(0, Math.floor(totalMinutes));
            const hh = String(Math.floor(mins / 60)).padStart(2, '0');
            const mm = String(mins % 60).padStart(2, '0');
            return `${dateStr}T${hh}:${mm}:00`;
        }

        async function patchTimeV1EntryPlacement(entryId, payload) {
            const res = await fetch(`/api/v1/timetracking/time/${entryId}`, {
                method: 'PATCH',
                credentials: 'include',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload),
            });

            if (!res.ok) {
                let errorText = `${res.status}`;
                try {
                    const body = await res.json();
                    errorText = body?.detail || JSON.stringify(body);
                } catch (e) {
                    errorText = await res.text();
                }
                throw new Error(errorText || 'Kunne ikke gemme tidsplacering');
            }
        }

        function initTimeV1DragAndDrop() {
            const timeline = document.getElementById('timeTimelineColumns');
            if (!timeline) return;

            const draggables = timeline.querySelectorAll('.time-v1-unplaced-item[draggable="true"], .time-v1-entry-block[draggable="true"]');
            draggables.forEach((el) => {
                el.addEventListener('dragstart', (event) => {
                    const payload = {
                        entryId: Number(el.dataset.entryId || 0),
                        durationMin: Math.max(1, Number(el.dataset.durationMin || 30)),
                    };
                    if (!payload.entryId) {
                        event.preventDefault();
                        return;
                    }
                    event.dataTransfer.setData('text/plain', JSON.stringify(payload));
                    event.dataTransfer.effectAllowed = 'move';
                    el.classList.add('dragging');
                });
                el.addEventListener('dblclick', (event) => {
                    event.preventDefault();
                    event.stopPropagation();
                    const entryId = Number(el.dataset.entryId || 0);
                    if (entryId > 0) {
                        openTimeV1DetailedEdit(entryId);
                    }
                });
                el.addEventListener('dragend', () => {
                    el.classList.remove('dragging');
                    timeline.querySelectorAll('.time-v1-tech-body.time-v1-drop-target').forEach((target) => target.classList.remove('time-v1-drop-target'));
                });
            });

            const START_HOUR = 7;
            const TOTAL_HOURS = 10;
            const SNAP_MIN = 15;

            const dropTargets = timeline.querySelectorAll('.time-v1-tech-body[data-date]');
            dropTargets.forEach((target) => {
                target.addEventListener('dragenter', (event) => {
                    event.preventDefault();
                    target.classList.add('time-v1-drop-target');
                });
                target.addEventListener('dragover', (event) => {
                    event.preventDefault();
                    event.dataTransfer.dropEffect = 'move';
                    target.classList.add('time-v1-drop-target');
                });
                target.addEventListener('dragleave', (event) => {
                    if (!target.contains(event.relatedTarget)) {
                        target.classList.remove('time-v1-drop-target');
                    }
                });
                target.addEventListener('drop', async (event) => {
                    event.preventDefault();
                    target.classList.remove('time-v1-drop-target');

                    if (timeV1DragBusy) return;
                    const drag = parseTimeV1DragPayload(event);
                    if (!drag || !drag.entryId) return;

                    const dateStr = target.dataset.date;
                    if (!dateStr || !/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
                        alert('Kunne ikke bestemme dato for drop-felt');
                        return;
                    }

                    const rect = target.getBoundingClientRect();
                    const y = Math.max(0, Math.min(rect.height, event.clientY - rect.top));
                    const minutesFromTop = Math.round((y / rect.height) * (TOTAL_HOURS * 60));
                    const snapped = Math.round(minutesFromTop / SNAP_MIN) * SNAP_MIN;
                    const duration = Math.max(1, Number(drag.durationMin || 30));
                    const maxStart = Math.max(0, TOTAL_HOURS * 60 - duration);
                    const clamped = Math.max(0, Math.min(snapped, maxStart));

                    const startMinutes = (START_HOUR * 60) + clamped;
                    const endMinutes = startMinutes + duration;

                    const payload = {
                        start_tid: toIsoLocalFromDateMinutes(dateStr, startMinutes),
                        slut_tid: toIsoLocalFromDateMinutes(dateStr, endMinutes),
                        worked_date: dateStr,
                        ikke_placeret: false,
                    };

                    const medarbejderIdRaw = target.dataset.medarbejderId;
                    if (medarbejderIdRaw !== undefined && medarbejderIdRaw !== null && medarbejderIdRaw !== '') {
                        const medarbejderId = Number(medarbejderIdRaw);
                        if (!Number.isNaN(medarbejderId) && medarbejderId > 0) {
                            payload.medarbejder_id = medarbejderId;
                        }
                    }

                    timeV1DragBusy = true;
                    try {
                        await patchTimeV1EntryPlacement(drag.entryId, payload);
                        await loadTimeTrackingTab();
                    } catch (error) {
                        alert('Kunne ikke flytte tidsregistrering: ' + (error.message || 'ukendt fejl'));
                    } finally {
                        timeV1DragBusy = false;
                    }
                });
            });
        }

        function ensureTimeV1EditEmployeeOptions() {
            const source = document.getElementById('timeV1EmployeeId');
            const target = document.getElementById('timeV1EditEmployeeId');
            if (!source || !target) return;
            if (target.dataset.initialized === '1') return;
            target.innerHTML = source.innerHTML;
            target.dataset.initialized = '1';
        }

        function toLocalDateInputValue(value) {
            if (!value) return '';
            const d = new Date(value);
            if (Number.isNaN(d.getTime())) return '';
            const y = d.getFullYear();
            const m = String(d.getMonth() + 1).padStart(2, '0');
            const day = String(d.getDate()).padStart(2, '0');
            return `${y}-${m}-${day}`;
        }

        function toLocalTimeInputValue(value) {
            if (!value) return '';
            const d = new Date(value);
            if (Number.isNaN(d.getTime())) return '';
            return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;
        }

        function openTimeV1DetailedEdit(entryId) {
            const entry = timeV1EntriesById[Number(entryId)];
            if (!entry) {
                alert('Kunne ikke finde tidsregistreringen');
                return;
            }

            ensureTimeV1EditEmployeeOptions();

            const minutes = entry.faktisk_tid_min
                ? Number(entry.faktisk_tid_min)
                : Math.max(1, Math.round(Number(entry.original_hours || entry.timer || 0) * 60));

            document.getElementById('timeV1EditId').value = String(entry.id || '');
            document.getElementById('timeV1EditDate').value = entry.worked_date || toLocalDateInputValue(entry.start_tid) || toLocalDateInputValue(entry.created_at);
            document.getElementById('timeV1EditStart').value = toLocalTimeInputValue(entry.start_tid);
            document.getElementById('timeV1EditEnd').value = toLocalTimeInputValue(entry.slut_tid);
            document.getElementById('timeV1EditMinutes').value = String(minutes || 1);
            document.getElementById('timeV1EditDescription').value = entry.beskrivelse || entry.description || '';
            document.getElementById('timeV1EditType').value = entry.entry_type || 'manuel';
            document.getElementById('timeV1EditStatus').value = entry.entry_status || 'afventer';
            document.getElementById('timeV1EditBillable').checked = Boolean(entry.billable !== false);
            document.getElementById('timeV1EditEmployeeId').value = entry.medarbejder_id != null ? String(entry.medarbejder_id) : '';

            const modalEl = document.getElementById('timeV1EditModal');
            if (!modalEl) return;
            const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
            modal.show();
        }

        async function saveTimeV1DetailedEdit() {
            const entryId = Number(document.getElementById('timeV1EditId')?.value || 0);
            if (!entryId) {
                alert('Manglende entry-id');
                return;
            }

            const dateVal = document.getElementById('timeV1EditDate')?.value || null;
            const startVal = document.getElementById('timeV1EditStart')?.value || '';
            const endVal = document.getElementById('timeV1EditEnd')?.value || '';
            const minutes = Math.max(1, Number(document.getElementById('timeV1EditMinutes')?.value || 0));

            let startIso = null;
            let endIso = null;
            if (dateVal && startVal) {
                startIso = `${dateVal}T${startVal}:00`;
                if (endVal) {
                    endIso = `${dateVal}T${endVal}:00`;
                } else {
                    const startDate = new Date(startIso);
                    if (!Number.isNaN(startDate.getTime())) {
                        endIso = new Date(startDate.getTime() + (minutes * 60000)).toISOString();
                    }
                }
            }

            const rawEmployee = document.getElementById('timeV1EditEmployeeId')?.value || '';
            const parsedEmployee = rawEmployee ? Number(rawEmployee) : null;

            const payload = {
                worked_date: dateVal,
                description: document.getElementById('timeV1EditDescription')?.value || null,
                entry_type: document.getElementById('timeV1EditType')?.value || 'manuel',
                entry_status: document.getElementById('timeV1EditStatus')?.value || 'afventer',
                billable: Boolean(document.getElementById('timeV1EditBillable')?.checked),
                medarbejder_id: Number.isNaN(parsedEmployee) ? null : parsedEmployee,
                start_tid: startIso,
                slut_tid: endIso,
                ikke_placeret: !startIso,
            };

            if (!startIso) {
                payload.slut_tid = null;
            }

            try {
                await patchTimeV1EntryPlacement(entryId, payload);
                const modalEl = document.getElementById('timeV1EditModal');
                if (modalEl) {
                    bootstrap.Modal.getOrCreateInstance(modalEl).hide();
                }
                await loadTimeTrackingTab();
            } catch (error) {
                alert('Kunne ikke gemme detalje-redigering: ' + (error.message || 'ukendt fejl'));
            }
        }

        async function loadTimeTrackingTab() {
            try {
                const res = await fetch(`/api/v1/timetracking/time?sag_id=${timeCaseId}`);
                if (!res.ok) throw new Error('Kunne ikke hente tidsforbrug');
                const entries = await res.json();
                timeV1EntriesById = Object.fromEntries((entries || []).map((entry) => [Number(entry.id), entry]));
                window.initialCaseTabCounts = Object.assign({}, window.initialCaseTabCounts || {}, { timetracking: (entries || []).length });
                renderTimeV1Timeline(entries || []);
                renderTimeV1Summary(entries || []);
                setModuleContentState('timetracking', (entries || []).length > 0);
                if (typeof updateCaseTabCountBadges === 'function') updateCaseTabCountBadges();
            } catch (error) {
                console.error(error);
                const timeline = document.getElementById('timeTimelineColumns');
                const summary = document.getElementById('timeSummaryEntries');
                if (timeline) {
                    timeline.innerHTML = '<div class="text-danger text-center py-3">Kunne ikke hente tidsforbrug.</div>';
                }
                if (summary) {
                    summary.innerHTML = '<div class="text-danger small">Kunne ikke hente tids-sammendrag.</div>';
                }
                setModuleContentState('timetracking', true);
            }
        }

        async function startLiveTimerV1() {
            try {
                const res = await fetch('/api/v1/timetracking/time/start', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        sag_id: timeCaseId,
                        entry_type: document.getElementById('timeV1Type')?.value || 'manuel',
                        beskrivelse: document.getElementById('timeV1Description')?.value || null
                    })
                });
                if (!res.ok) throw new Error(await res.text());
                await loadTimeTrackingTab();
            } catch (error) {
                alert('Kunne ikke starte timer: ' + (error.message || 'ukendt fejl'));
            }
        }

        async function stopLiveTimerV1(extra = {}) {
            try {
                const res = await fetch('/api/v1/timetracking/time/stop', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(extra || {})
                });
                if (!res.ok) throw new Error(await res.text());
                await loadTimeTrackingTab();
            } catch (error) {
                alert('Kunne ikke stoppe timer: ' + (error.message || 'ukendt fejl'));
            }
        }

        function bindTimeV1Calculations() {
            const startIn = document.getElementById('timeV1Start');
            const endIn = document.getElementById('timeV1End');
            const minIn = document.getElementById('timeV1Minutes');
            
            if (!startIn || !endIn || !minIn) return;

            const parseTime = (val) => {
                if (!val) return null;
                const [h,m] = val.split(':').map(Number);
                return (h * 60) + m;
            };

            const toTimeStr = (totalMins) => {
                const h = Math.floor(totalMins / 60) % 24;
                const m = totalMins % 60;
                return `${h.toString().padStart(2,'0')}:${m.toString().padStart(2,'0')}`;
            };

            const recalculate = (trigger) => {
                const s = parseTime(startIn.value);
                const e = parseTime(endIn.value);
                const dur = parseInt(minIn.value);

                if (trigger === 'start' || trigger === 'end') {
                    if (s !== null && e !== null) {
                        let diff = e - s;
                        if (diff < 0) diff += 24*60;
                        minIn.value = diff;
                    } else if (s !== null && !isNaN(dur) && dur > 0 && !endIn.value) {
                        endIn.value = toTimeStr(s + dur);
                    } else if (e !== null && !isNaN(dur) && dur > 0 && !startIn.value) {
                        let base = e - dur;
                        while (base < 0) base += 24*60;
                        startIn.value = toTimeStr(base);
                    }
                } else if (trigger === 'min') {
                    if (s !== null && !isNaN(dur) && dur > 0) {
                        endIn.value = toTimeStr(s + dur);
                    } else if (e !== null && !isNaN(dur) && dur > 0 && !startIn.value) {
                        let base = e - dur;
                        while(base < 0) base+=24*60;
                        startIn.value = toTimeStr(base);
                    }
                }
            };

            startIn.addEventListener('change', () => recalculate('start'));
            endIn.addEventListener('change', () => recalculate('end'));
            minIn.addEventListener('input', () => recalculate('min'));
        }

        function getTimeV1EmployeeId() {
            const val = document.getElementById('timeV1EmployeeId')?.value;
            return val ? Number(val) : null;
        }

        async function createManualTimeV1(event) {
            event.preventDefault();
            const minutes = Number(document.getElementById('timeV1Minutes')?.value || 0);

            if (minutes <= 0) {
                alert('Indtast minutter over 0');
                return;
            }

            const dateVal = document.getElementById('timeV1Date')?.value || null;
            const tStart = document.getElementById('timeV1Start')?.value;
            const tEnd = document.getElementById('timeV1End')?.value;

            let startObj = null;
            let endObj = null;

            if (dateVal && tStart) {
                try {
                    const l = new Date(`${dateVal}T${tStart}:00`);
                    startObj = l.toISOString();
                } catch(e){}
            }

            if (dateVal && tEnd) {
                try {
                    const l = new Date(`${dateVal}T${tEnd}:00`);
                    if (startObj && new Date(startObj) > l) {
                        l.setDate(l.getDate() + 1);
                    }
                    endObj = l.toISOString();
                } catch(e){}
            }

            const payload = {
                sag_id: timeCaseId,
                medarbejder_id: getTimeV1EmployeeId(),
                faktisk_tid_min: minutes,
                worked_date: dateVal,
                entry_type: document.getElementById('timeV1Type')?.value || 'manuel',
                entry_status: document.getElementById('timeV1Status')?.value || 'afventer',
                beskrivelse: document.getElementById('timeV1Description')?.value || null,
                kilde: 'manuel',
                start_tid: startObj,
                slut_tid: endObj
            };

            try {
                const res = await fetch('/api/v1/timetracking/time/manual', {
                    method: 'POST',
                    credentials: 'include',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(payload)
                });
                if (!res.ok) {
                    let errMsg = res.statusText;
                    try { const j = await res.json(); errMsg = j.detail || JSON.stringify(j); } catch(e) {}
                    throw new Error(`${res.status}: ${errMsg}`);
                }

                const minutesInput = document.getElementById('timeV1Minutes');
                const descInput = document.getElementById('timeV1Description');
                const startIn = document.getElementById('timeV1Start');
                const endIn = document.getElementById('timeV1End');

                if (minutesInput) minutesInput.value = '';
                if (descInput) descInput.value = '';
                if (startIn) startIn.value = '';
                if (endIn) endIn.value = '';

                await loadTimeTrackingTab();
            } catch (error) {
                alert('Kunne ikke oprette tidsregistrering: ' + (error.message || 'ukendt fejl'));
            }
        }

        document.addEventListener('DOMContentLoaded', () => {
            bindTimeV1Calculations();
            const dateInput = document.getElementById('timeV1Date');
            if (dateInput && !dateInput.value) {
                dateInput.valueAsDate = new Date();
            }
        });
    </script>

    <script>
        let reminderUserId = null;
        const remindersCaseId = {{ case.id }};

        function getReminderUserId() {
            const token = localStorage.getItem('access_token') || sessionStorage.getItem('access_token');
            if (token) {
                try {
                    const payload = JSON.parse(atob(token.split('.')[1]));
                    return payload.sub || payload.user_id;
                } catch (e) {
                    console.warn('Could not decode token for reminder user_id');
                }
            }
            const metaTag = document.querySelector('meta[name="user-id"]');
            if (metaTag) return metaTag.getAttribute('content');
            return null;
        }

        async function ensureReminderUserId() {
            const localId = getReminderUserId();
            if (localId) return localId;

            try {
                const res = await fetch('/api/v1/auth/me', { credentials: 'include' });
                if (!res.ok) return null;
                const me = await res.json();
                return me?.id || me?.user_id || null;
            } catch (err) {
                return null;
            }
        }

        function formatReminderDate(value) {
            if (!value) return '-';
            const date = new Date(value);
            if (Number.isNaN(date.getTime())) return '-';
            return date.toLocaleString('da-DK', { hour12: false });
        }

        function updateReminderTriggerFields() {
            const triggerType = document.getElementById('rem_trigger_type')?.value;
            const timeWrap = document.getElementById('rem_trigger_time_wrap');
            const statusWrap = document.getElementById('rem_trigger_status_wrap');
            if (timeWrap && statusWrap) {
                if (triggerType === 'status_change') {
                    timeWrap.classList.add('d-none');
                    statusWrap.classList.remove('d-none');
                } else {
                    timeWrap.classList.remove('d-none');
                    statusWrap.classList.add('d-none');
                }
            }
        }

        function updateReminderRecurrenceFields() {
            const recurrenceType = document.getElementById('rem_recurrence_type')?.value;
            const dowWrap = document.getElementById('rem_recurrence_dow_wrap');
            const domWrap = document.getElementById('rem_recurrence_dom_wrap');
            if (!dowWrap || !domWrap) return;
            dowWrap.classList.toggle('d-none', recurrenceType !== 'weekly');
            domWrap.classList.toggle('d-none', recurrenceType !== 'monthly');
        }

        function openCreateReminderModal(defaultEventType) {
            reminderUserId = getReminderUserId();
            const warning = document.getElementById('rem_user_warning');
            if (warning) warning.classList.toggle('d-none', !!reminderUserId);

            const form = document.getElementById('createReminderForm');
            if (form) form.reset();
            document.getElementById('rem_notify_frontend').checked = true;
            document.getElementById('rem_priority').value = 'normal';
            document.getElementById('rem_event_type').value = defaultEventType || 'reminder';
            document.getElementById('rem_trigger_type').value = 'time_based';
            document.getElementById('rem_recurrence_type').value = 'once';
            updateReminderTriggerFields();
            updateReminderRecurrenceFields();
            new bootstrap.Modal(document.getElementById('createReminderModal')).show();
        }

        async function loadReminders() {
            const list = document.getElementById('remindersList');
            if (!list) return;
            reminderUserId = await ensureReminderUserId();

            if (!reminderUserId) {
                list.innerHTML = '<div class="p-4 text-center text-muted">Kunne ikke finde bruger-id.</div>';
                setModuleContentState('reminders', true);
                return;
            }

            list.innerHTML = '<div class="p-4 text-center text-muted"><span class="spinner-border spinner-border-sm"></span> Henter reminders...</div>';

            try {
                const res = await fetch(`/api/v1/sag/${remindersCaseId}/reminders?user_id=${reminderUserId}`);
                if (!res.ok) throw new Error('Kunne ikke hente reminders');
                const reminders = await res.json();
                renderReminders(reminders);
            } catch (e) {
                console.error(e);
                list.innerHTML = '<div class="p-4 text-center text-danger">Fejl ved hentning af reminders</div>';
                setModuleContentState('reminders', true);
            }
        }

        function renderReminders(reminders) {
            const list = document.getElementById('remindersList');
            if (!list) return;
            if (!reminders || reminders.length === 0) {
                list.innerHTML = '<div class="p-4 text-center text-muted">Ingen reminders endnu.</div>';
                setModuleContentState('reminders', false);
                return;
            }

            const triggerLabels = {
                time_based: 'Tidspunkt',
                status_change: 'Status ændring',
                deadline_approaching: 'Deadline'
            };

            const eventTypeLabels = {
                reminder: 'Reminder',
                meeting: 'Moede',
                technician_visit: 'Teknikerbesoeg',
                obs: 'OBS',
                deadline: 'Deadline'
            };

            const recurrenceLabels = {
                once: 'Én gang',
                daily: 'Dagligt',
                weekly: 'Ugentligt',
                monthly: 'Månedligt'
            };

            list.innerHTML = reminders.map(reminder => {
                const nextCheck = formatReminderDate(reminder.next_check_at);
                const createdAt = formatReminderDate(reminder.created_at);
                const isActive = reminder.is_active;
                const statusBadge = isActive
                    ? '<span class="badge bg-success">Aktiv</span>'
                    : '<span class="badge bg-secondary">Inaktiv</span>';

                return `
                    <div class="list-group-item">
                        <div class="d-flex justify-content-between align-items-start">
                            <div class="me-3">
                                <div class="fw-bold">${reminder.title}</div>
                                <div class="text-muted small">${reminder.message || '-'} </div>
                                <div class="small text-muted mt-1">
                                    Type: ${eventTypeLabels[reminder.event_type] || reminder.event_type || 'Reminder'} · Trigger: ${triggerLabels[reminder.trigger_type] || reminder.trigger_type} · Gentagelse: ${recurrenceLabels[reminder.recurrence_type] || reminder.recurrence_type}
                                </div>
                                <div class="small text-muted">Næste: ${nextCheck} · Oprettet: ${createdAt}</div>
                            </div>
                            <div class="d-flex flex-column align-items-end gap-2">
                                ${statusBadge}
                                <button class="btn btn-sm btn-outline-danger" onclick="deleteReminder(${reminder.id})">
                                    <i class="bi bi-trash"></i>
                                </button>
                            </div>
                        </div>
                    </div>
                `;
            }).join('');
            setModuleContentState('reminders', true);
        }

        async function saveReminder() {
            reminderUserId = await ensureReminderUserId();
            if (!reminderUserId) {
                alert('Mangler bruger-id. Log ind igen.');
                return;
            }

            const title = document.getElementById('rem_title').value.trim();
            const message = document.getElementById('rem_message').value.trim();
            const priority = document.getElementById('rem_priority').value;
            const eventType = document.getElementById('rem_event_type').value;
            const triggerType = document.getElementById('rem_trigger_type').value;
            const scheduledAtValue = document.getElementById('rem_scheduled_at').value;
            const targetStatus = document.getElementById('rem_target_status').value;
            const recurrenceType = document.getElementById('rem_recurrence_type').value;
            const recurrenceDow = document.getElementById('rem_recurrence_dow').value;
            const recurrenceDom = document.getElementById('rem_recurrence_dom').value;
            const notifyFrontend = document.getElementById('rem_notify_frontend').checked;
            const notifyEmail = document.getElementById('rem_notify_email').checked;
            const notifyMattermost = document.getElementById('rem_notify_mattermost').checked;
            const overridePrefs = document.getElementById('rem_override_prefs').checked;

            if (!title) {
                alert('Titel er påkrævet');
                return;
            }

            let triggerConfig = {};
            let scheduledAt = null;

            if (triggerType === 'status_change') {
                if (!targetStatus) {
                    alert('Vælg en status for statusændring');
                    return;
                }
                triggerConfig = { target_status: targetStatus };
            } else {
                if (!scheduledAtValue) {
                    alert('Vælg et tidspunkt');
                    return;
                }
                scheduledAt = new Date(scheduledAtValue).toISOString();
            }

            const payload = {
                title,
                message: message || null,
                priority,
                event_type: eventType,
                trigger_type: triggerType,
                trigger_config: triggerConfig,
                recipient_user_ids: [Number(reminderUserId)],
                recipient_emails: [],
                notify_mattermost: notifyMattermost,
                notify_email: notifyEmail,
                notify_frontend: notifyFrontend,
                override_user_preferences: overridePrefs,
                recurrence_type: recurrenceType,
                recurrence_day_of_week: recurrenceType === 'weekly' ? Number(recurrenceDow) : null,
                recurrence_day_of_month: recurrenceType === 'monthly' ? Number(recurrenceDom) : null,
                scheduled_at: scheduledAt
            };

            try {
                const res = await fetch(`/api/v1/sag/${remindersCaseId}/reminders?user_id=${reminderUserId}`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(payload)
                });
                if (!res.ok) {
                    const err = await res.json();
                    throw new Error(err.detail || 'Kunne ikke oprette reminder');
                }
                bootstrap.Modal.getInstance(document.getElementById('createReminderModal')).hide();
                await loadReminders();
                await loadCaseCalendar();
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        async function deleteReminder(reminderId) {
            if (!confirm('Vil du slette denne reminder?')) return;
            try {
                const res = await fetch(`/api/v1/sag/reminders/${reminderId}`, { method: 'DELETE' });
                if (!res.ok) throw new Error('Kunne ikke slette reminder');
                await loadReminders();
                await loadCaseCalendar();
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        function formatCalendarEvent(event) {
            const dateLabel = formatReminderDate(event.start);
            const typeLabelMap = {
                reminder: 'Reminder',
                meeting: 'Moede',
                technician_visit: 'Teknikerbesoeg',
                obs: 'OBS',
                deadline: 'Deadline',
                deferred: 'Deferred'
            };
            const typeLabel = typeLabelMap[event.event_kind] || event.event_kind || 'Reminder';
            return `
                <a href="${event.url}" class="list-group-item list-group-item-action">
                    <div class="d-flex justify-content-between">
                        <div>
                            <div class="fw-semibold">${event.title || 'Aftale'}</div>
                            <div class="text-muted small">${typeLabel} · ${dateLabel}</div>
                        </div>
                    </div>
                </a>
            `;
        }

        async function loadCaseCalendar() {
            const currentList = document.getElementById('caseCalendarCurrent');
            const childrenList = document.getElementById('caseCalendarChildren');
            if (!currentList || !childrenList) return;

            currentList.innerHTML = '<div class="text-muted small">Indlæser aftaler...</div>';
            childrenList.innerHTML = '<div class="text-muted small">Indlæser børnesager...</div>';

            try {
                const res = await fetch(`/api/v1/sag/${remindersCaseId}/calendar-events?include_children=true`);
                if (!res.ok) throw new Error('Kunne ikke hente kalenderaftaler');
                const data = await res.json();

                const currentEvents = data.current || [];
                const childGroups = data.children || [];
                const childCount = childGroups.reduce((sum, child) => sum + (child.events || []).length, 0);
                const hasAnyEvents = currentEvents.length > 0 || childCount > 0;

                if (!currentEvents.length) {
                    currentList.innerHTML = '<div class="text-muted small">Ingen aftaler for denne sag.</div>';
                } else {
                    currentList.innerHTML = currentEvents
                        .map(formatCalendarEvent)
                        .join('');
                }

                if (!childGroups.length) {
                    childrenList.innerHTML = '<div class="text-muted small">Ingen børnesager.</div>';
                } else {
                    childrenList.innerHTML = childGroups.map(child => {
                        const eventsHtml = (child.events || []).length
                            ? child.events.map(formatCalendarEvent).join('')
                            : '<div class="text-muted small">Ingen aftaler.</div>';
                        return `
                            <div class="mb-3">
                                <div class="fw-semibold mb-1">${child.case_title}</div>
                                <div class="list-group">
                                    ${eventsHtml}
                                </div>
                            </div>
                        `;
                    }).join('');
                }

                setModuleContentState('calendar', hasAnyEvents);
            } catch (e) {
                console.error(e);
                currentList.innerHTML = '<div class="text-danger small">Fejl ved hentning af aftaler.</div>';
                childrenList.innerHTML = '';
                setModuleContentState('calendar', true);
            }
        }

        document.addEventListener('DOMContentLoaded', function() {
            updateReminderTriggerFields();
            updateReminderRecurrenceFields();
            loadReminders();
            loadCaseCalendar();
        });
    </script>

    <!-- Modals for Solution (Inserted here) -->
    <div class="modal fade" id="createSolutionModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Opret Løsning</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="solutionForm">
                        <input type="hidden" id="sol_sag_id" value="{{ case.id }}">
                        <div class="mb-3">
                            <label class="form-label">Titel *</label>
                            <input type="text" class="form-control" id="sol_title" required>
                        </div>
                        <div class="row mb-3">
                            <div class="col-md-6">
                                <label class="form-label">Type</label>
                                <select class="form-select" id="sol_type">
                                    <option value="Support">Support</option>
                                    <option value="Drift">Drift</option>
                                    <option value="Konsulent">Konsulent</option>
                                    <option value="Infrastruktur">Infrastruktur</option>
                                </select>
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">Resultat</label>
                                <select class="form-select" id="sol_result">
                                    <option value="Løst">Løst</option>
                                    <option value="Delvist">Delvist</option>
                                    <option value="Workaround">Workaround</option>
                                    <option value="Ej løst">Ej løst</option>
                                </select>
                            </div>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Beskrivelse</label>
                            <textarea class="form-control" id="sol_desc" rows="5"></textarea>
                        </div>
                        <div class="border-top pt-3">
                            <div class="form-check mb-3">
                                <input class="form-check-input" type="checkbox" id="sol_add_time">
                                <label class="form-check-label" for="sol_add_time">
                                    Registrer tid med det samme
                                </label>
                            </div>
                            <div id="sol_time_fields" class="row g-3 d-none">
                                <div class="col-md-4">
                                    <label class="form-label">Dato</label>
                                    <input type="date" class="form-control" id="sol_time_date">
                                </div>
                                <div class="col-md-4">
                                    <label class="form-label">Tid brugt</label>
                                    <div class="input-group">
                                        <input type="number" class="form-control" id="sol_time_hours" min="0" placeholder="tt" step="1">
                                        <span class="input-group-text">:</span>
                                        <input type="number" class="form-control" id="sol_time_minutes" min="0" placeholder="mm" step="1">
                                    </div>
                                    <div class="form-text" id="sol_time_total">Total: 0.00 timer</div>
                                </div>
                                <div class="col-md-4">
                                    <label class="form-label">Beskrivelse</label>
                                    <input type="text" class="form-control" id="sol_time_desc" placeholder="F.eks. afsluttede løsning">
                                </div>
                                <div class="col-12">
                                    <div class="form-check">
                                        <input class="form-check-input" type="checkbox" id="sol_time_internal">
                                        <label class="form-check-label text-muted" for="sol_time_internal">
                                            Skjul for kunde (intern registrering)
                                        </label>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Luk</button>
                    <button type="button" class="btn btn-primary" onclick="saveSolution()">Gem Løsning</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Modal for Sale Item -->
    <div class="modal fade" id="saleItemModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="bi bi-basket3"></i> Varelinje</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="saleItemForm">
                        <input type="hidden" id="sale_item_id">
                        <div class="row g-3">
                            <div class="col-md-4">
                                <label class="form-label">Type *</label>
                                <select class="form-select" id="sale_type">
                                    <option value="sale">Salg</option>
                                    <option value="purchase">Køb</option>
                                </select>
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">Status *</label>
                                <select class="form-select" id="sale_status">
                                    <option value="draft">Kladde</option>
                                    <option value="confirmed">Bekræftet</option>
                                    <option value="cancelled">Annulleret</option>
                                </select>
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">Dato</label>
                                <input type="date" class="form-control" id="sale_date">
                            </div>
                            <div class="col-12">
                                <label class="form-label">Beskrivelse *</label>
                                <input type="text" class="form-control" id="sale_description" placeholder="F.eks. Switch, montage, kørsel">
                            </div>
                            <div class="col-md-3">
                                <label class="form-label">Antal</label>
                                <input type="number" class="form-control" id="sale_quantity" step="0.01" min="0">
                            </div>
                            <div class="col-md-3">
                                <label class="form-label">Enhed</label>
                                <input type="text" class="form-control" id="sale_unit" placeholder="stk, timer">
                            </div>
                            <div class="col-md-3">
                                <label class="form-label">Enhedspris</label>
                                <input type="number" class="form-control" id="sale_unit_price" step="0.01" min="0">
                            </div>
                            <div class="col-md-3">
                                <label class="form-label">Linjesum *</label>
                                <input type="number" class="form-control" id="sale_amount" step="0.01" min="0">
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">Valuta</label>
                                <input type="text" class="form-control" id="sale_currency" value="DKK">
                            </div>
                            <div class="col-md-8">
                                <label class="form-label">Reference</label>
                                <input type="text" class="form-control" id="sale_external_ref" placeholder="Valgfri reference">
                            </div>
                            <div class="col-12 d-none" id="sale_purchase_fields">
                                <div class="row g-3">
                                    <div class="col-md-4">
                                        <label class="form-label">Indkøbsformål</label>
                                        <select class="form-select" id="sale_purchase_purpose">
                                            <option value="">Vælg formål</option>
                                            <option value="salg">Salg</option>
                                            <option value="lager">Lager</option>
                                            <option value="asset">Asset</option>
                                            <option value="intern_brug">Intern brug</option>
                                            <option value="retur_reklamation">Retur/reklamation</option>
                                            <option value="projekt_omkostning">Projektomkostning</option>
                                        </select>
                                    </div>
                                    <div class="col-md-4">
                                        <label class="form-label">Leverandørfaktura ID</label>
                                        <input type="number" class="form-control" id="sale_supplier_invoice_id" min="1" step="1" placeholder="Fx 1254">
                                    </div>
                                    <div class="col-md-4">
                                        <label class="form-label">Fakturalinje ID</label>
                                        <input type="number" class="form-control" id="sale_supplier_invoice_line_id" min="1" step="1" placeholder="Fx 8921">
                                    </div>
                                </div>
                            </div>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Luk</button>
                    <button type="button" class="btn btn-primary" onclick="saveSaleItem()">Gem varelinje</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Modal for Internal Time -->
    <div class="modal fade" id="createTimeModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="bi bi-clock-history"></i> Registrer Tid</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="timeForm">
                        <input type="hidden" id="time_sag_id" value="{{ case.id }}">
                        <div class="row g-3">
                            <div class="col-12 col-md-6">
                                <label class="form-label">Dato *</label>
                                <input type="date" class="form-control" id="time_date" required>
                            </div>
                            <div class="col-12 col-md-6">
                                <label class="form-label">Tid brugt *</label>
                                <div class="input-group">
                                    <span class="input-group-text">Min.</span>
                                    <input type="number" class="form-control" id="time_total_minutes" min="1" placeholder="45" step="1" required>
                                </div>
                            </div>
                            <div class="col-6">
                                <label class="form-label">Starttid</label>
                                <input type="time" class="form-control" id="time_start_input">
                            </div>
                            <div class="col-6">
                                <label class="form-label">Sluttid</label>
                                <input type="time" class="form-control" id="time_end_input">
                            </div>

                            <div class="col-6">
                                <label class="form-label">Type</label>
                                <select class="form-select" id="time_work_type">
                                    <option value="support" selected>Support</option>
                                    <option value="troubleshooting">Fejlsøgning</option>
                                    <option value="development">Udvikling</option>
                                    <option value="on_site">Kørsel / On-site</option>
                                    <option value="meeting">Møde</option>
                                    <option value="other">Andet</option>
                                </select>
                            </div>
                            <div class="col-6">
                                <label class="form-label">Afregning</label>
                                <select class="form-select" id="time_billing_method">
                                    <option value="invoice" selected>Faktura</option>
                                    {% if prepaid_cards %}
                                    <optgroup label="Klippekort">
                                        {% for card in prepaid_cards %}
                                        <option value="card_{{ card.id }}">💳 Klippekort #{{ card.card_number or card.id }} ({{ '%.2f' % card.remaining_hours }}t tilbage{% if card.expires_at %} • Udløber {{ card.expires_at }}{% endif %})</option>
                                        {% endfor %}
                                    </optgroup>
                                    {% endif %}
                                    {% if fixed_price_agreements %}
                                    <optgroup label="Fastpris Aftaler">
                                        {% for agr in fixed_price_agreements %}
                                        <option value="fpa_{{ agr.id }}">📋 Fastpris #{{ agr.agreement_number }} ({{ '%.1f' % agr.remaining_hours_this_month }}t tilbage / {{ '%.0f' % agr.monthly_hours }}t/måned)</option>
                                        {% endfor %}
                                    </optgroup>
                                    {% endif %}
                                    <option value="internal">Internt / Ingen faktura</option>
                                    <option value="warranty">Garanti / Reklamation</option>
                                </select>
                            </div>
                            <div class="col-12">
                                <label class="form-label">Beskrivelse</label>
                                <textarea class="form-control" id="time_desc" rows="3" placeholder="Hvad er der brugt tid på?"></textarea>
                            </div>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Luk</button>
                    <button type="button" class="btn btn-primary" onclick="saveTime()">
                        <i class="bi bi-save"></i> Gem Tid
                    </button>
                </div>
            </div>
        </div>
    </div>

    <!-- Script for Solution/Time -->
    <script>
        function showCreateSolutionModal() {
            const addTimeCheckbox = document.getElementById('sol_add_time');
            const timeFields = document.getElementById('sol_time_fields');
            if (addTimeCheckbox && timeFields) {
                addTimeCheckbox.checked = false;
                timeFields.classList.add('d-none');
            }
            const timeDate = document.getElementById('sol_time_date');
            if (timeDate) timeDate.valueAsDate = new Date();
            const timeHours = document.getElementById('sol_time_hours');
            const timeMinutes = document.getElementById('sol_time_minutes');
            const timeTotal = document.getElementById('sol_time_total');
            if (timeHours) timeHours.value = '';
            if (timeMinutes) timeMinutes.value = '';
            if (timeTotal) timeTotal.textContent = 'Total: 0.00 timer';
            const timeDesc = document.getElementById('sol_time_desc');
            if (timeDesc) timeDesc.value = '';
            const timeInternal = document.getElementById('sol_time_internal');
            if (timeInternal) timeInternal.checked = false;
            new bootstrap.Modal(document.getElementById('createSolutionModal')).show();
        }

        function updateSolutionTimeTotal() {
            const h = parseInt(document.getElementById('sol_time_hours').value) || 0;
            const m = parseInt(document.getElementById('sol_time_minutes').value) || 0;
            const total = h + (m / 60);
            const output = document.getElementById('sol_time_total');
            if (output) output.textContent = `Total: ${total.toFixed(2)} timer`;
        }

        async function saveSolution() {
            const data = {
                sag_id: document.getElementById('sol_sag_id').value,
                title: document.getElementById('sol_title').value,
                solution_type: document.getElementById('sol_type').value,
                result: document.getElementById('sol_result').value,
                description: document.getElementById('sol_desc').value,
                created_by_user_id: 1 // TODO: Get from auth
            };
            const addTime = document.getElementById('sol_add_time')?.checked;
            const timeHours = parseInt(document.getElementById('sol_time_hours').value) || 0;
            const timeMinutes = parseInt(document.getElementById('sol_time_minutes').value) || 0;
            const timeTotal = timeHours + (timeMinutes / 60);
            
            try {
                const res = await fetch(`/api/v1/sag/${data.sag_id}/solution`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify(data)
                });
                if (res.ok) {
                    if (addTime && timeTotal > 0) {
                        const solution = await res.json();
                        const timePayload = {
                            sag_id: data.sag_id,
                            solution_id: solution.id,
                            description: document.getElementById('sol_time_desc').value || data.title,
                            original_hours: timeTotal,
                            worked_date: document.getElementById('sol_time_date').value || null,
                            is_internal: document.getElementById('sol_time_internal').checked,
                            work_type: 'support'
                        };
                        const timeRes = await fetch('/api/v1/timetracking/entries/internal', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify(timePayload)
                        });
                        if (!timeRes.ok) {
                            alert('Løsning oprettet, men tid kunne ikke registreres');
                        }
                    }
                    window.location.reload();
                } else {
                    alert('Fejl ved oprettelse af løsning');
                }
            } catch(e) { console.error(e); alert('Fejl'); }
        }

        function showAddTimeModal() {
             // Set date to today
             document.getElementById('time_date').valueAsDate = new Date();
             
             // Reset fields
             if(document.getElementById('time_total_minutes')) {
                 document.getElementById('time_total_minutes').value = '';
                 document.getElementById('time_start_input').value = '';
                 document.getElementById('time_end_input').value = '';
             }
             document.getElementById('time_desc').value = '';
             if(document.getElementById('time_internal')) document.getElementById('time_internal').checked = false;
             if(document.getElementById('time_billing_method')) document.getElementById('time_billing_method').value = 'invoice';
             if(document.getElementById('time_work_type')) document.getElementById('time_work_type').value = 'support';
             
             new bootstrap.Modal(document.getElementById('createTimeModal')).show();
        }
        
        // Auto-calculate total hours
        /* removed updateTimeTotal */
        
        // Add listeners safely
        document.addEventListener('DOMContentLoaded', () => {
            const hInput = document.getElementById('time_hours_input');
            const mInput = document.getElementById('time_minutes_input');
            
            const solAddTime = document.getElementById('sol_add_time');
            const solFields = document.getElementById('sol_time_fields');
            if (solAddTime && solFields) {
                solAddTime.addEventListener('change', () => {
                    solFields.classList.toggle('d-none', !solAddTime.checked);
                });
            }
            const solHours = document.getElementById('sol_time_hours');
            const solMinutes = document.getElementById('sol_time_minutes');
            if (solHours) solHours.addEventListener('input', updateSolutionTimeTotal);
            if (solMinutes) solMinutes.addEventListener('input', updateSolutionTimeTotal);
        });

                function bindTimeModalCalculations() {
            const startIn = document.getElementById('time_start_input');
            const endIn = document.getElementById('time_end_input');
            const minIn = document.getElementById('time_total_minutes');
            
            if (!startIn || !endIn || !minIn) return;

            const parseTime = (val) => {
                if (!val) return null;
                const [h,m] = val.split(':').map(Number);
                return (h * 60) + m;
            };

            const toTimeStr = (totalMins) => {
                const h = Math.floor(totalMins / 60) % 24;
                const m = totalMins % 60;
                return `${h.toString().padStart(2,'0')}:${m.toString().padStart(2,'0')}`;
            };

            const recalculate = (trigger) => {
                const s = parseTime(startIn.value);
                const e = parseTime(endIn.value);
                const dur = parseInt(minIn.value);

                if (trigger === 'start' || trigger === 'end') {
                    if (s !== null && e !== null) {
                        let diff = e - s;
                        if (diff < 0) diff += 24*60;
                        minIn.value = diff;
                    } else if (s !== null && !isNaN(dur) && dur > 0 && !endIn.value) {
                        endIn.value = toTimeStr(s + dur);
                    } else if (e !== null && !isNaN(dur) && dur > 0 && !startIn.value) {
                        let base = e - dur;
                        while (base < 0) base += 24*60;
                        startIn.value = toTimeStr(base);
                    }
                } else if (trigger === 'min') {
                    if (s !== null && !isNaN(dur) && dur > 0) {
                        endIn.value = toTimeStr(s + dur);
                    } else if (e !== null && !isNaN(dur) && dur > 0 && !startIn.value) {
                        let base = e - dur;
                        while(base < 0) base+=24*60;
                        startIn.value = toTimeStr(base);
                    }
                }
            };

            startIn.addEventListener('change', () => recalculate('start'));
            endIn.addEventListener('change', () => recalculate('end'));
            minIn.addEventListener('input', () => recalculate('min'));
        }

        document.addEventListener('DOMContentLoaded', bindTimeModalCalculations);

        async function saveTime() {
             const mInput = document.getElementById('time_total_minutes');
             const minVal = parseInt(mInput ? mInput.value : 0);
             if (!minVal || minVal <= 0) {
                 alert('Indtast en gyldig varighed (minutter).');
                 return;
             }
             const totalHours = minVal / 60;
             const dateVal = document.getElementById('time_date').value;
             // extract optional start/end limits
             const tStart = document.getElementById('time_start_input')?.value;
             const tEnd = document.getElementById('time_end_input')?.value;
            
             let startObj = null;
             let endObj = null;
             if (dateVal && tStart) {
                 try {
                     const l = new Date(`${dateVal}T${tStart}:00`);
                     startObj = l.toISOString();
                 } catch(e){}
             }
             if (dateVal && tEnd) {
                 try {
                     const l = new Date(`${dateVal}T${tEnd}:00`);
                     if (startObj && new Date(startObj) > l) {
                         l.setDate(l.getDate() + 1);
                     }
                     endObj = l.toISOString();
                 } catch(e){}
             }
             
             const sagId = document.getElementById('time_sag_id').value;
             const payload = {
                 sag_id: parseInt(sagId),
                 // Note: saveTime modal expects 'timer' as totalHours currently, let's keep compatibility:
                 timer: totalHours,
                 faktisk_tid_min: minVal,
                 worked_date: dateVal,
                 start_tid: startObj,
                 slut_tid: endObj,
                 description: document.getElementById('time_desc').value,
                 work_type: document.getElementById('time_work_type').value,
                 billing_method: document.getElementById('time_billing_method').value
             };
             
             try {
                 const res = await fetch('/api/v1/timetracking/time/manual', {
                     method: 'POST',
                     headers: {'Content-Type':'application/json'},
                     body: JSON.stringify(payload)
                 });
                 if(res.ok) {
                     window.location.reload();
                 } else {
                     alert("Fejl ved registrering af tid");
                 }
             } catch(err) {
                 console.error(err);
                 alert("Forbindelsesfejl");
             }
        }
    </script>

    <!-- Kontakt Info Modal -->
    <div class="modal fade" id="kontaktModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header" style="background: var(--accent); color: white;">
                    <h5 class="modal-title">
                        <i class="bi bi-person-circle me-2"></i>Kontakt Information
                    </h5>
                    <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    {% if hovedkontakt %}
                    <div class="mb-3">
                        <label class="small text-muted mb-1">Navn</label>
                        <div class="fw-bold">{{ hovedkontakt.first_name }} {{ hovedkontakt.last_name }}</div>
                    </div>
                    <div class="mb-3">
                        <label class="small text-muted mb-1">E-mail</label>
                        <div>
                            {% if hovedkontakt.email %}
                            <a href="mailto:{{ hovedkontakt.email }}" style="color: var(--accent);">
                                <i class="bi bi-envelope me-1"></i>{{ hovedkontakt.email }}
                            </a>
                            {% else %}
                            <span class="text-muted">Ingen email</span>
                            {% endif %}
                        </div>
                    </div>
                    <div class="mb-3">
                        <label class="small text-muted mb-1">Telefon</label>
                        <div>
                            {% if hovedkontakt.phone %}
                            <a href="tel:{{ hovedkontakt.phone }}" style="color: var(--accent);">
                                <i class="bi bi-telephone me-1"></i>{{ hovedkontakt.phone }}
                            </a>
                            {% else %}
                            <span class="text-muted">Ingen telefon</span>
                            {% endif %}
                        </div>
                    </div>
                    <div class="mb-3">
                        <label class="small text-muted mb-1">Mobil</label>
                        <div>
                            {% if hovedkontakt.mobile %}
                            <div class="d-flex align-items-center gap-2 flex-wrap">
                                <a href="tel:{{ hovedkontakt.mobile }}" style="color: var(--accent);">
                                    <i class="bi bi-phone me-1"></i>{{ hovedkontakt.mobile }}
                                </a>
                                <button type="button" class="btn btn-sm btn-outline-primary" onclick="openSmsPrompt({{ hovedkontakt.mobile|tojson }}, {{ (hovedkontakt.first_name ~ ' ' ~ hovedkontakt.last_name)|tojson }}, {{ hovedkontakt.id|default('null') }})">SMS</button>
                            </div>
                            {% else %}
                            <span class="text-muted">Ingen mobil</span>
                            {% endif %}
                        </div>
                    </div>
                    {% if hovedkontakt.title %}
                    <div class="mb-3">
                        <label class="small text-muted mb-1">Titel</label>
                        <div>{{ hovedkontakt.title }}</div>
                    </div>
                    {% endif %}
                    {% else %}
                    <p class="text-center text-muted mb-0">Ingen kontakt tilknyttet</p>
                    {% endif %}
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Luk</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Afdeling Modal -->
    <div class="modal fade" id="afdelingModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header" style="background: var(--accent); color: white;">
                    <h5 class="modal-title">
                        <i class="bi bi-building me-2"></i>Rediger Afdeling
                    </h5>
                    <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <label for="afdelingInput" class="form-label">Afdeling</label>
                    <input type="text" 
                           class="form-control" 
                           id="afdelingInput" 
                           value="{{ customer.department if customer and customer.department else '' }}"
                           placeholder="Indtast afdeling">
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuller</button>
                    <button type="button" class="btn btn-primary" style="background: var(--accent); border: none;" onclick="updateAfdeling()">
                        Gem
                    </button>
                </div>
            </div>
        </div>
    </div>

    <!-- Nextcloud Modals -->
    {% if nextcloud_instance %}
    <!-- Create User Modal -->
    <div class="modal fade" id="ncCreateUserModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Opret Nextcloud Bruger</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="ncCreateUserForm">
                        <div class="mb-3">
                            <label class="form-label">E-mail</label>
                            <input type="email" class="form-control" name="email" value="{{ hovedkontakt.email if hovedkontakt else '' }}" required>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Visningsnavn</label>
                            <input type="text" class="form-control" name="display_name" value="{{ hovedkontakt.first_name if hovedkontakt else '' }} {{ hovedkontakt.last_name if hovedkontakt else '' }}" required>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Bruger ID (UID)</label>
                            <input type="text" class="form-control" name="uid" value="{{ hovedkontakt.email if hovedkontakt else '' }}" required>
                            <div class="form-text">Bruges til login. Oftest email.</div>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Grupper</label>
                            <input type="text" class="form-control" name="groups" value="Kunder" placeholder="f.eks. Kunder, Ekstern">
                            <div class="form-text">Komma-separeret liste af grupper</div>
                        </div>
                        <div class="form-check">
                            <input class="form-check-input" type="checkbox" name="send_welcome" id="ncSendWelcome" checked>
                            <label class="form-check-label" for="ncSendWelcome">
                                Send velkomst-email med kode
                            </label>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuller</button>
                    <button type="button" class="btn btn-success" onclick="ncCreateUser()">Opret Bruger</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Disable User Modal -->
    <div class="modal fade" id="ncDisableUserModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title text-danger">Luk Nextcloud Bruger</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="ncDisableUserForm">
                        <div class="mb-3">
                            <label class="form-label">Bruger ID (UID)</label>
                            <input type="text" class="form-control" name="uid" value="{{ hovedkontakt.email if hovedkontakt else '' }}" required>
                        </div>
                        <div class="alert alert-warning small">
                            Brugeren vil ikke længere kunne logge ind, men data bevares.
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuller</button>
                    <button type="button" class="btn btn-danger" onclick="ncDisableUser()">Luk Bruger</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Reset Password Modal -->
    <div class="modal fade" id="ncResetPasswordModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Reset Kodeord</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="ncResetPasswordForm">
                        <div class="mb-3">
                            <label class="form-label">Bruger ID (UID)</label>
                            <input type="text" class="form-control" name="uid" value="{{ hovedkontakt.email if hovedkontakt else '' }}" required>
                        </div>
                        <div class="form-check">
                            <input class="form-check-input" type="checkbox" name="send_email" id="ncSendResetEmail" checked>
                            <label class="form-check-label" for="ncSendResetEmail">
                                Send ny kode på email
                            </label>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuller</button>
                    <button type="button" class="btn btn-warning" onclick="ncResetPassword()">Reset Kode</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Send Guide Modal -->
    <div class="modal fade" id="ncSendGuideModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Send Guide</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="ncSendGuideForm">
                        <div class="mb-3">
                            <label class="form-label">Bruger ID (UID)</label>
                            <input type="text" class="form-control" name="uid" value="{{ hovedkontakt.email if hovedkontakt else '' }}" required>
                        </div>
                        <p class="small text-muted">Sender en email med start-guide til Nextcloud til brugerens registrerede mail.</p>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuller</button>
                    <button type="button" class="btn btn-info text-white" onclick="ncSendGuide()">Send Guide</button>
                </div>
            </div>
        </div>
    </div>

    <script>
        {% endif %}
    </script>

    <div id="caseAddSideBackdrop" class="case-add-side-backdrop" onclick="closeCaseModuleAddPanel()"></div>
    <button type="button" id="caseAddSideReopen" class="case-add-side-reopen" onclick="openCaseModuleAddPanel()" title="Vis tilføj-panel igen">
        <i class="bi bi-layout-sidebar-inset"></i>Tilføj
    </button>
    <aside id="caseAddSidePanel" class="case-add-side-panel" aria-hidden="true">
        <div class="case-add-side-header">
            <h6 class="case-add-side-title"><i class="bi bi-plus-square"></i>Tilføj til modul</h6>
            <button type="button" class="btn btn-sm btn-outline-secondary" onclick="closeCaseModuleAddPanel()" title="Skjul panel">
                <i class="bi bi-chevron-left"></i>
            </button>
        </div>
        <div class="case-add-side-body">
            <div id="caseAddModuleList" class="case-add-module-list"></div>
            <div id="caseAddSideWorkspace" class="case-add-workspace">
                <div class="text-muted small">Vælg et aktivt modul for at tilføje data.</div>
            </div>
        </div>
    </aside>

    <!-- Generic Search Modal -->
    <div class="modal fade" id="entitySearchModal" tabindex="-1">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="entitySearchTitle">Søg</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <div class="input-group mb-3">
                        <span class="input-group-text"><i class="bi bi-search"></i></span>
                        <input type="text" class="form-control" id="entitySearchInput" placeholder="Søg (min. 2 tegn)..." autocomplete="off">
                    </div>
                    <div class="text-center d-none" id="entitySearchSpinner">
                        <div class="spinner-border text-primary" role="status"></div>
                    </div>
                    <div id="entitySearchResults" class="list-group list-group-flush" style="max-height: 300px; overflow-y: auto;">
                        <!-- Results go here -->
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Create Related Case Modal -->
    <div class="modal fade" id="createRelatedCaseModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Opret ny relateret sag</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="createRelatedForm">
                        <div class="mb-3">
                            <label class="form-label">Titel *</label>
                            <input type="text" class="form-control" id="newCaseTitle" required placeholder="F.eks. Opfølgning på...">
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Relationstype *</label>
                            <select class="form-select" id="newCaseRelationType" onchange="updateNewCaseRelationTypeHint()">
                                <option value="Relateret til">Relateret til (Ingen direkte afhængighed)</option>
                                <option value="Afledt af">Afledt af (Nuværende sag er afledt af den nye)</option>
                                <option value="Årsag til">Årsag til (Nuværende sag er årsag til den nye)</option>
                                <option value="Blokkerer">Blokkerer (Nuværende sag blokerer den nye)</option>
                            </select>
                        </div>
                        <div id="newCaseRelationTypeHint" class="alert alert-info small mb-3"></div>
                        <div class="alert alert-light border small">
                            <div class="fw-semibold mb-1">Sådan vælger du korrekt relation</div>
                            <div><strong>Relateret til</strong>: Samme emne/område, men ingen direkte afhængighed.</div>
                            <div><strong>Afledt af</strong>: Den nye sag opstår fordi den nuværende sag findes.</div>
                            <div><strong>Årsag til</strong>: Den nuværende sag opstår fordi den nye sag findes.</div>
                            <div><strong>Blokkerer</strong>: Løsning i én sag er nødvendig før den anden kan afsluttes.</div>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Beskrivelse</label>
                            <textarea class="form-control" id="newCaseDescription" rows="3"></textarea>
                        </div>
                        <div class="alert alert-info small mb-0">
                            <i class="bi bi-info-circle me-1"></i>
                            Sagen oprettes for kunden: <strong>{{ case.customer_name }}</strong>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuller</button>
                    <button type="button" class="btn btn-primary" onclick="createRelatedCase()">Opret & Link</button>
                </div>
            </div>
        </div>
    </div>

    <script>
        let currentSearchType = null;
        let searchDebounceIds = null;
        let caseAnyDeskConnectInFlight = false;
        const caseIds = {{ case.id }};
        const currentCaseTitle = {{ (case.titel or '') | tojson }};
        let caseAddPanelInitialized = false;
        let caseAddActiveAction = null;
        let caseAddOriginalShowRelModal = null;
        window.initialCaseTabCounts = Object.assign({}, window.initialCaseTabCounts || {}, {
            timetracking: {{ (time_entries or [])|length }}
        });
        const CASE_ADD_ACTIONS = [
            { action: 'time', label: 'Tidregistrering', icon: 'bi-clock', moduleKey: 'time', relFn: 'openRelTimeModal' },
            { action: 'note', label: 'Kommentar', icon: 'bi-chat-left-text', moduleKey: 'solution', relFn: 'openRelNoteModal' },
            { action: 'reminder', label: 'Pamindelse', icon: 'bi-bell', moduleKey: 'reminders', relFn: 'openRelReminderModal' },
            { action: 'pipeline', label: 'Salgspipeline', icon: 'bi-graph-up-arrow', moduleKey: 'pipeline', relFn: 'openRelPipelineModal' },
            { action: 'files', label: 'Filer', icon: 'bi-paperclip', moduleKey: 'files', relFn: 'openRelFilesModal' },
            { action: 'hardware', label: 'Hardware', icon: 'bi-cpu', moduleKey: 'hardware', relFn: 'openRelHardwareModal' },
            { action: 'todo', label: 'Opgave', icon: 'bi-check2-square', moduleKey: 'todo-steps', relFn: 'openRelTodoModal' },
            { action: 'solution', label: 'Losning', icon: 'bi-lightbulb', moduleKey: 'solution', relFn: 'openRelSolutionModal' },
            { action: 'sales', label: 'Varekob og salg', icon: 'bi-bag', moduleKey: 'sales', relFn: 'openRelSalesModal' },
            { action: 'subscription', label: 'Abonnement', icon: 'bi-arrow-repeat', moduleKey: 'subscription', relFn: 'openRelSubscriptionModal' },
            { action: 'email', label: 'Send email', icon: 'bi-envelope', moduleKey: 'emails', relFn: 'openRelEmailModal' }
        ];

        function normalizeAnyDeskIdClient(rawValue) {
            const raw = String(rawValue || '').trim();
            const digits = raw.replace(/\D/g, '');
            return digits || raw;
        }

        function onCaseAnyDeskIdInputChange() {
            const input = document.getElementById('caseAnydeskIdInput');
            const linkBtn = document.getElementById('caseAnydeskOpenLinkBtn');
            if (!input || !linkBtn) return;

            const id = normalizeAnyDeskIdClient(input.value);
            if (!id) {
                linkBtn.style.display = 'none';
                linkBtn.setAttribute('href', '#');
                return;
            }

            input.value = id;
            linkBtn.style.display = '';
            linkBtn.setAttribute('href', `anydesk:${id}`);
        }

        function setCaseAnyDeskInputFromSaved(anydeskId) {
            const input = document.getElementById('caseAnydeskIdInput');
            if (!input) return;
            input.value = normalizeAnyDeskIdClient(anydeskId);
            onCaseAnyDeskIdInputChange();
        }

        function renderCaseAnyDeskSavedIds(entries) {
            const container = document.getElementById('caseAnyDeskSavedIds');
            if (!container) return;

            if (!entries?.length) {
                container.innerHTML = '<span class="text-muted small">Ingen gemte AnyDesk IDs på sagen endnu.</span>';
                return;
            }

            container.innerHTML = entries.map((entry) => {
                const primary = entry?.is_primary ? ' border-primary text-primary' : '';
                const hardware = entry?.hardware_label ? ` <span class="text-muted">(${entry.hardware_label})</span>` : '';
                const badge = entry?.is_primary ? ' <span class="badge bg-primary-subtle text-primary-emphasis border border-primary-subtle">Primær</span>' : '';
                return `<button type="button" class="btn btn-sm btn-outline-secondary${primary}" onclick="setCaseAnyDeskInputFromSaved('${String(entry.anydesk_id || '').replace(/'/g, "\\'")}')">${entry.anydesk_id}${badge}${hardware}</button>`;
            }).join('');
        }

        function renderCaseAnyDeskHardwareOptions(caseHardware, customerHardware) {
            const select = document.getElementById('caseAnydeskHardwareSelect');
            if (!select) return;

            let html = '<option value="">Ingen hardware valgt</option>';

            if (Array.isArray(caseHardware) && caseHardware.length) {
                html += '<optgroup label="Hardware på sagen">';
                html += caseHardware.map((row) => `<option value="${row.id}">${row.label || ('Hardware #' + row.id)}</option>`).join('');
                html += '</optgroup>';
            }

            if (Array.isArray(customerHardware) && customerHardware.length) {
                html += '<optgroup label="Andet hardware hos kunden">';
                html += customerHardware.map((row) => `<option value="${row.id}">${row.label || ('Hardware #' + row.id)}</option>`).join('');
                html += '</optgroup>';
            }

            select.innerHTML = html;
        }

        async function loadCaseAnyDeskContext() {
            const [savedIdsRes, hardwareRes] = await Promise.all([
                fetch(`/api/v1/anydesk/cases/${caseIds}/ids`, { credentials: 'include' }),
                fetch(`/api/v1/anydesk/cases/${caseIds}/hardware-options`, { credentials: 'include' })
            ]);

            if (!savedIdsRes.ok) {
                throw new Error('Kunne ikke hente gemte AnyDesk IDs');
            }
            if (!hardwareRes.ok) {
                throw new Error('Kunne ikke hente hardwarevalg');
            }

            const savedIdsPayload = await savedIdsRes.json();
            const hardwarePayload = await hardwareRes.json();

            renderCaseAnyDeskSavedIds(savedIdsPayload?.ids || []);
            renderCaseAnyDeskHardwareOptions(hardwarePayload?.case_hardware || [], hardwarePayload?.customer_hardware || []);

            const primary = (savedIdsPayload?.ids || []).find((item) => item?.is_primary);
            if (primary?.anydesk_id) {
                setCaseAnyDeskInputFromSaved(primary.anydesk_id);
            }
        }

        async function openCaseAnyDeskModal() {
            if (caseAnyDeskConnectInFlight) {
                return;
            }

            const modalEl = document.getElementById('caseAnyDeskModal');
            if (!modalEl || typeof bootstrap === 'undefined' || !bootstrap.Modal) return;

            if (!caseAnyDeskModal || typeof caseAnyDeskModal.show !== 'function') {
                if (typeof bootstrap.Modal.getOrCreateInstance === 'function') {
                    caseAnyDeskModal = bootstrap.Modal.getOrCreateInstance(modalEl);
                } else {
                    caseAnyDeskModal = new bootstrap.Modal(modalEl);
                }
            }

            const noteInput = document.getElementById('caseAnydeskNoteInput');
            if (noteInput) noteInput.value = '';

            const saved = document.getElementById('caseAnyDeskSavedIds');
            if (saved) {
                saved.innerHTML = '<span class="text-muted small">Indlæser...</span>';
            }

            const hardwareSelect = document.getElementById('caseAnydeskHardwareSelect');
            if (hardwareSelect) {
                hardwareSelect.innerHTML = '<option value="">Indlæser hardware...</option>';
            }

            const input = document.getElementById('caseAnydeskIdInput');
            if (input && !input.value) {
                input.value = '';
            }
            onCaseAnyDeskIdInputChange();

            const connectBtn = document.getElementById('caseAnyDeskConnectBtn');
            if (connectBtn) {
                connectBtn.disabled = false;
                connectBtn.innerHTML = '<i class="bi bi-plug me-1"></i>Forbind og gem';
            }

            try {
                await loadCaseAnyDeskContext();
            } catch (error) {
                const message = error?.message || 'Kunne ikke hente AnyDesk data';
                if (saved) {
                    saved.innerHTML = `<span class="text-danger small">${message}</span>`;
                }
            }

            if (caseAnyDeskModal && typeof caseAnyDeskModal.show === 'function') {
                caseAnyDeskModal.show();
            }
        }

        async function registerCaseAnyDeskSession() {
            if (caseAnyDeskConnectInFlight) {
                return;
            }

            const anydeskId = normalizeAnyDeskIdClient(document.getElementById('caseAnydeskIdInput')?.value || '');
            const contactIdRaw = document.getElementById('caseAnydeskContactSelect')?.value || '';
            const hardwareIdRaw = document.getElementById('caseAnydeskHardwareSelect')?.value || '';
            const notes = (document.getElementById('caseAnydeskNoteInput')?.value || '').trim();

            if (!anydeskId) {
                alert('Udfyld AnyDesk ID');
                return;
            }

            const customerId = {{ customer.id if customer else 'null' }};
            if (!customerId) {
                alert('Sagen har ingen kunde - kan ikke starte AnyDesk session');
                return;
            }

            const createdByUserId = await ensureCaseCurrentUserId();

            const payload = {
                anydesk_id: anydeskId,
                contact_id: contactIdRaw ? Number(contactIdRaw) : null,
                hardware_asset_id: hardwareIdRaw ? Number(hardwareIdRaw) : null,
                note: notes,
                make_primary: true,
                created_by_user_id: createdByUserId || null
            };

            caseAnyDeskConnectInFlight = true;
            const connectBtn = document.getElementById('caseAnyDeskConnectBtn');
            const openBtn = document.getElementById('caseAnyDeskOpenBtn');
            if (connectBtn) {
                connectBtn.disabled = true;
                connectBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>Registrerer...';
            }
            if (openBtn) {
                openBtn.disabled = true;
            }

            try {
                const res = await fetch(`/api/v1/anydesk/cases/${caseIds}/connect`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    credentials: 'include',
                    body: JSON.stringify(payload)
                });

                if (!res.ok) {
                    const txt = await res.text();
                    throw new Error(txt || 'Kunne ikke starte AnyDesk quick connect');
                }

                const result = await res.json();
                if (caseAnyDeskModal && typeof caseAnyDeskModal.hide === 'function') {
                    caseAnyDeskModal.hide();
                }

                if (result?.deep_link) {
                    window.location.href = result.deep_link;
                }

                alert(`AnyDesk forbindelse startet (session: ${result?.session?.id || '-'})`);
                if (typeof loadComments === 'function') {
                    loadComments();
                }
            } catch (e) {
                alert('Fejl ved AnyDesk quick connect: ' + (e.message || 'Ukendt fejl'));
            } finally {
                caseAnyDeskConnectInFlight = false;
                if (connectBtn) {
                    connectBtn.disabled = false;
                    connectBtn.innerHTML = '<i class="bi bi-plug me-1"></i>Forbind og gem';
                }
                if (openBtn) {
                    openBtn.disabled = false;
                }
            }
        }

        // Ensure inline handlers and fallback listeners can always resolve AnyDesk actions.
        window.openCaseAnyDeskModal = openCaseAnyDeskModal;
        window.registerCaseAnyDeskSession = registerCaseAnyDeskSession;
        window.onCaseAnyDeskIdInputChange = onCaseAnyDeskIdInputChange;
        window.setCaseAnyDeskInputFromSaved = setCaseAnyDeskInputFromSaved;

        document.addEventListener('DOMContentLoaded', () => {
            const adjustCaseTopbarOffset = () => {
                const shell = document.querySelector('.case-detail-page-shell');
                const nav = document.querySelector('.navbar.fixed-top');
                if (!shell || !nav) return;

                const navHeight = Math.ceil(nav.getBoundingClientRect().height || 0);
                const bodyPaddingTop = parseFloat(getComputedStyle(document.body).paddingTop || '0') || 0;
                const needed = Math.max(0, navHeight - bodyPaddingTop + 8);
                shell.style.setProperty('--case-topbar-offset', `${needed}px`);
            };

            adjustCaseTopbarOffset();
            window.addEventListener('resize', adjustCaseTopbarOffset);

            const openBtn = document.getElementById('caseAnyDeskOpenBtn');
            if (openBtn) {
                openBtn.removeAttribute('onclick');
                openBtn.addEventListener('click', (event) => {
                    event.preventDefault();
                    event.stopPropagation();
                    openCaseAnyDeskModal();
                });
            }

            const connectBtn = document.getElementById('caseAnyDeskConnectBtn');
            if (connectBtn) {
                connectBtn.removeAttribute('onclick');
                connectBtn.addEventListener('click', (event) => {
                    event.preventDefault();
                    event.stopPropagation();
                    registerCaseAnyDeskSession();
                });
            }

            const anydeskInput = document.getElementById('caseAnydeskIdInput');
            if (anydeskInput) {
                anydeskInput.removeAttribute('oninput');
                anydeskInput.addEventListener('input', onCaseAnyDeskIdInputChange);
            }
        });

        async function openCaseModuleAddPanel() {
            if (typeof loadModulePrefs === 'function') {
                await loadModulePrefs();
            }

            const panel = document.getElementById('caseAddSidePanel');
            const backdrop = document.getElementById('caseAddSideBackdrop');
            if (!panel || !backdrop) return;

            backdrop.classList.add('open');
            panel.classList.add('open');
            panel.setAttribute('aria-hidden', 'false');

            if (!caseAddOriginalShowRelModal && typeof window._showRelModal === 'function') {
                caseAddOriginalShowRelModal = window._showRelModal;
            }
            if (typeof caseAddOriginalShowRelModal === 'function') {
                window._showRelModal = renderCaseAddWorkspaceModal;
            }

            // Remove legacy modal instance to avoid duplicate relQaModalEl IDs
            // when side-panel rendering is active.
            document.querySelectorAll('body > #relQaModalEl').forEach((el) => el.remove());

            renderCaseAddActionList(caseAddActiveAction);
            caseAddPanelInitialized = true;
        }

        function closeCaseModuleAddPanel() {
            const panel = document.getElementById('caseAddSidePanel');
            const backdrop = document.getElementById('caseAddSideBackdrop');
            if (!panel || !backdrop) return;

            panel.classList.remove('open');
            panel.setAttribute('aria-hidden', 'true');
            backdrop.classList.remove('open');

            if (typeof caseAddOriginalShowRelModal === 'function') {
                window._showRelModal = caseAddOriginalShowRelModal;
            }

            const workspace = document.getElementById('caseAddSideWorkspace');
            if (workspace) {
                workspace.innerHTML = '<div class="text-muted small">Vaelg en handling i venstre side.</div>';
            }
        }

        function renderCaseAddWorkspaceModal(title, bodyHtml, footerBtns) {
            const workspace = document.getElementById('caseAddSideWorkspace');
            if (!workspace) return;

            // Ensure only one relQaModalEl exists. Duplicate IDs can break button
            // handlers and value lookups across add forms.
            document.querySelectorAll('#relQaModalEl').forEach((el) => {
                if (!workspace.contains(el)) {
                    el.remove();
                }
            });

            workspace.innerHTML = `
                <div id="relQaModalEl" class="d-flex flex-column gap-2">
                    <div id="relQaModalTitle" class="section-title">${title}</div>
                    <div id="relQaModalBody">${bodyHtml}</div>
                    <div id="relQaModalFooter" class="d-flex justify-content-end gap-2 border-top pt-2">
                        <button class="btn btn-sm btn-outline-secondary" type="button" onclick="closeCaseModuleAddPanel()">Luk</button>
                        ${footerBtns || ''}
                    </div>
                </div>
            `;

            workspace.querySelectorAll('form').forEach((formEl) => {
                formEl.addEventListener('submit', (evt) => evt.preventDefault());
            });

            workspace.querySelectorAll('#relQaModalFooter button').forEach((btnEl) => {
                if (!btnEl.getAttribute('type')) {
                    btnEl.setAttribute('type', 'button');
                }
            });
        }

        function _isCaseAddModuleEnabled(actionConfig) {
            if (!actionConfig?.moduleKey) return true;
            if (actionConfig.moduleKey === 'time') return true;
            return modulePrefs[actionConfig.moduleKey] !== false;
        }

        function _renderCaseAddModuleToggle(actionConfig) {
            if (!actionConfig?.moduleKey) {
                return '<span class="d-inline-block" style="width:1rem; height:1rem;"></span>';
            }

            const isTimeModule = actionConfig.moduleKey === 'time';
            const isChecked = _isCaseAddModuleEnabled(actionConfig);
            return `<input type="checkbox" class="case-add-module-toggle" ${isChecked ? 'checked' : ''} ${isTimeModule ? 'disabled' : ''} onchange="toggleModulePref('${actionConfig.moduleKey}', this.checked)">`;
        }

        function renderCaseAddActionList(preferredAction = null) {
            const listEl = document.getElementById('caseAddModuleList');
            if (!listEl) return;

            const actions = CASE_ADD_ACTIONS;
            if (!actions.length) {
                listEl.innerHTML = '<div class="text-muted small">Ingen aktive moduler fundet.</div>';
                return;
            }

            listEl.innerHTML = actions.map((cfg) => `
                <div class="case-add-module-item">
                    <button type="button" class="case-add-module-btn" id="caseAddAction_${cfg.action}" onclick="openCaseAddAction('${cfg.action}')">
                        <i class="bi ${cfg.icon} me-1"></i>${cfg.label}
                    </button>
                    ${_renderCaseAddModuleToggle(cfg)}
                </div>
            `).join('');

            const fallbackAction = actions[0]?.action || null;
            const nextAction = actions.some((cfg) => cfg.action === preferredAction) ? preferredAction : fallbackAction;
            if (nextAction) {
                openCaseAddAction(nextAction);
            }
        }

        async function openCaseAddAction(actionName) {
            document.querySelectorAll('.case-add-module-btn').forEach((btn) => btn.classList.remove('active'));
            document.getElementById(`caseAddAction_${actionName}`)?.classList.add('active');
            caseAddActiveAction = actionName;

            const action = CASE_ADD_ACTIONS.find((cfg) => cfg.action === actionName);
            const workspace = document.getElementById('caseAddSideWorkspace');
            if (!action || !workspace) return;

            workspace.innerHTML = '<div class="text-muted small"><span class="spinner-border spinner-border-sm me-2"></span>Indlaeser formular...</div>';

            const relFn = window[action.relFn];
            if (typeof relFn !== 'function') {
                workspace.innerHTML = '<div class="text-danger small">Modulformular er ikke tilgaengelig endnu.</div>';
                return;
            }

            document.querySelectorAll('#relQaModalEl').forEach((existingRelQaEl) => {
                if (!workspace.contains(existingRelQaEl)) {
                    const existingModalInstance = window.bootstrap?.Modal?.getInstance(existingRelQaEl);
                    if (existingModalInstance) {
                        existingModalInstance.hide();
                    }
                    existingRelQaEl.remove();
                }
            });

            try {
                await Promise.resolve(relFn(caseIds, currentCaseTitle));
            } catch (error) {
                console.error('Could not load module add form', error);
                workspace.innerHTML = '<div class="text-danger small">Kunne ikke indlaese formularen.</div>';
            }
        }

        document.addEventListener('keydown', (event) => {
            if (event.key === 'Escape') {
                const panel = document.getElementById('caseAddSidePanel');
                if (panel && panel.classList.contains('open')) {
                    closeCaseModuleAddPanel();
                }
            }
        });

        function openSearchModal(type) {
            currentSearchType = type;
            const titles = {
                'hardware': 'Tilføj Hardware',
                'location': 'Tilføj Lokation',
                'contact': 'Tilføj Kontakt',
                'customer': 'Tilføj Kunde'
            };
            document.getElementById('entitySearchTitle').textContent = titles[type] || 'Søg';
            document.getElementById('entitySearchInput').value = '';
            document.getElementById('entitySearchResults').innerHTML = '';
            
            const modal = new bootstrap.Modal(document.getElementById('entitySearchModal'));
            modal.show();
            
            setTimeout(() => document.getElementById('entitySearchInput').focus(), 500);
        }

        document.getElementById('entitySearchInput').addEventListener('input', function(e) {
            clearTimeout(searchDebounceIds);
            const query = e.target.value.trim();
            if (query.length < 2) {
                document.getElementById('entitySearchResults').innerHTML = '';
                return;
            }
            
            searchDebounceIds = setTimeout(() => performSearch(query), 300);
        });

        async function performSearch(query) {
            document.getElementById('entitySearchSpinner').classList.remove('d-none');
            document.getElementById('entitySearchResults').classList.add('d-none');
            
            try {
                let url = '';
                if (currentSearchType === 'hardware') url = `/api/v1/search/hardware?q=${encodeURIComponent(query)}`;
                else if (currentSearchType === 'location') url = `/api/v1/search/locations?q=${encodeURIComponent(query)}`;
                else if (currentSearchType === 'contact') url = `/api/v1/search/contacts?q=${encodeURIComponent(query)}`;
                else if (currentSearchType === 'customer') url = `/api/v1/search/customers?q=${encodeURIComponent(query)}`;
                
                const res = await fetch(url);
                if (!res.ok) throw new Error('Search failed');
                const results = await res.json();
                renderResults(results);
            } catch (e) {
                console.error(e);
                document.getElementById('entitySearchResults').innerHTML = '<div class="text-danger text-center p-3">Fejl ved søgning</div>';
            } finally {
                document.getElementById('entitySearchSpinner').classList.add('d-none');
                document.getElementById('entitySearchResults').classList.remove('d-none');
            }
        }

        function renderResults(results) {
            const container = document.getElementById('entitySearchResults');
            if (results.length === 0) {
                container.innerHTML = '<div class="text-muted text-center p-3">Ingen resultater fundet</div>';
                return;
            }
            
            container.innerHTML = results.map(item => {
                let title = '', subtitle = '', icon = '', id = item.id;
                
                if (currentSearchType === 'hardware') {
                    title = `${item.brand} ${item.model}`;
                    subtitle = `SN: ${item.serial_number}`;
                    icon = 'bi-laptop';
                } else if (currentSearchType === 'location') {
                    title = item.name;
                    subtitle = `${item.address_street || ''} ${item.address_city || ''}`;
                    icon = 'bi-geo-alt';
                } else if (currentSearchType === 'contact') {
                    title = `${item.first_name} ${item.last_name}`;
                    subtitle = item.email;
                    icon = 'bi-person';
                } else if (currentSearchType === 'customer') {
                    title = item.name;
                    subtitle = `CVR: ${item.cvr_nummer || 'N/A'}`;
                    icon = 'bi-building';
                }
                
                return `
                    <button type="button" class="list-group-item list-group-item-action d-flex align-items-center" onclick="addEntity(${id})">
                        <div class="me-3 fs-4 text-muted"><i class="bi ${icon}"></i></div>
                        <div>
                            <div class="fw-bold">${title}</div>
                            <small class="text-muted">${subtitle}</small>
                        </div>
                    </button>
                `;
            }).join('');
        }

        async function addEntity(id) {
            let url = '', body = {};
            
            if (currentSearchType === 'hardware') {
                url = `/api/v1/sag/${caseIds}/hardware`;
                body = { hardware_id: id };
            } else if (currentSearchType === 'location') {
                url = `/api/v1/sag/${caseIds}/locations`;
                body = { location_id: id };
            } else if (currentSearchType === 'contact') {
                url = `/api/v1/sag/${caseIds}/contacts`;
                body = { contact_id: id };
            } else if (currentSearchType === 'customer') {
                url = `/api/v1/sag/${caseIds}/customers`;
                body = { customer_id: id };
            }
            
            try {
                const res = await fetch(url, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify(body)
                });
                
                if (!res.ok) {
                    const err = await res.json();
                    alert("Fejl: " + (err.detail || 'Kunne ikke tilføje'));
                    return;
                }
                
                bootstrap.Modal.getInstance(document.getElementById('entitySearchModal')).hide();
                window.location.reload();
            } catch (e) {
                alert("Fejl: " + e.message);
            }
        }

        async function removeContact(caseId, contactId) {
            if(!confirm("Fjern denne kontakt fra sagen?")) return;
            try {
                const res = await fetch(`/api/v1/sag/${caseId}/contacts/${contactId}`, { method: 'DELETE' });
                if (res.ok) window.location.reload();
                else alert("Fejl ved sletning");
            } catch(e) { alert("Fejl: " + e.message); }
        }

        function openContactRoleModal(contactId, contactName, role, isPrimary) {
            document.getElementById('contactRoleContactId').value = contactId;
            document.getElementById('contactRoleName').textContent = contactName || '-';
            document.getElementById('contactRoleInput').value = role || '';
            document.getElementById('contactRolePrimary').checked = !!isPrimary;

            const modal = new bootstrap.Modal(document.getElementById('contactRoleModal'));
            modal.show();
        }

        async function saveContactRole() {
            const contactId = document.getElementById('contactRoleContactId').value;
            const role = document.getElementById('contactRoleInput').value.trim();
            const isPrimary = document.getElementById('contactRolePrimary').checked;

            try {
                const res = await fetch(`/api/v1/sag/${caseIds}/contacts/${contactId}`, {
                    method: 'PATCH',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ role, is_primary: isPrimary })
                });

                if (!res.ok) {
                    const err = await res.json();
                    throw new Error(err.detail || 'Kunne ikke opdatere kontakt');
                }

                bootstrap.Modal.getInstance(document.getElementById('contactRoleModal')).hide();
                window.location.reload();
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        async function removeCustomer(caseId, customerId) {
            if(!confirm("Fjern denne kunde fra sagen?")) return;
            try {
                const res = await fetch(`/api/v1/sag/${caseId}/customers/${customerId}`, { method: 'DELETE' });
                if (res.ok) window.location.reload();
                else alert("Fejl ved sletning");
            } catch(e) { alert("Fejl: " + e.message); }
        }

        async function updateDeferredUntil(value) {
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ deferred_until: value || null })
                });
                if (!res.ok) {
                    const err = await res.json();
                    throw new Error(err.detail || 'Kunne ikke opdatere');
                }
                window.location.reload();
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        async function updateDeadline(value) {
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ deadline: value || null })
                });
                if (!res.ok) {
                    const err = await res.json();
                    throw new Error(err.detail || 'Kunne ikke opdatere deadline');
                }
                window.location.reload();
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        function shiftDeadlineDays(days) {
            const input = document.getElementById('deadlineInput');
            const base = input.value ? new Date(input.value) : new Date();
            base.setDate(base.getDate() + days);
            input.value = base.toISOString().slice(0, 10);
            updateDeadline(input.value);
        }

        function shiftDeadlineMonths(months) {
            const input = document.getElementById('deadlineInput');
            const base = input.value ? new Date(input.value) : new Date();
            base.setMonth(base.getMonth() + months);
            input.value = base.toISOString().slice(0, 10);
            updateDeadline(input.value);
        }

        function openDeadlineModal() {
            const modal = new bootstrap.Modal(document.getElementById('deadlineModal'));
            modal.show();
        }

        function saveDeadlineAll() {
            const input = document.getElementById('deadlineInput');
            updateDeadline(input.value || null);
        }

        function clearDeadlineAll() {
            const input = document.getElementById('deadlineInput');
            input.value = '';
            updateDeadline(null);
        }

        function setDeferredFromInput() {
            const input = document.getElementById('deferredUntilInput');
            updateDeferredUntil(input.value || null);
        }

        function shiftDeferredDays(days) {
            const input = document.getElementById('deferredUntilInput');
            const base = input.value ? new Date(input.value) : new Date();
            base.setDate(base.getDate() + days);
            input.value = base.toISOString().slice(0, 10);
            updateDeferredUntil(input.value);
        }

        function shiftDeferredMonths(months) {
            const input = document.getElementById('deferredUntilInput');
            const base = input.value ? new Date(input.value) : new Date();
            base.setMonth(base.getMonth() + months);
            input.value = base.toISOString().slice(0, 10);
            updateDeferredUntil(input.value);
        }

        function clearDeferredUntil() {
            const input = document.getElementById('deferredUntilInput');
            input.value = '';
            updateDeferredUntil(null);
        }

        function openDeferredModal() {
            const modal = new bootstrap.Modal(document.getElementById('deferredModal'));
            modal.show();
        }

        function findDeferredStatusOptionValue(primaryStatus, fallbackContains) {
            const statusSelect = document.getElementById('deferredStatusSelect');
            if (!statusSelect) return null;

            const targetPrimary = String(primaryStatus || '').trim().toLowerCase();
            const targetFallback = String(fallbackContains || '').trim().toLowerCase();
            const options = Array.from(statusSelect.options || []);

            const primary = options.find((opt) => String(opt.value || '').trim().toLowerCase() === targetPrimary);
            if (primary && primary.value) return primary.value;

            const fallback = options.find((opt) => String(opt.value || '').trim().toLowerCase().includes(targetFallback));
            if (fallback && fallback.value) return fallback.value;

            return null;
        }

        function getDeferredSelectedStatuses() {
            const statusSelect = document.getElementById('deferredStatusSelect');
            if (!statusSelect) return [];
            return Array.from(statusSelect.selectedOptions || [])
                .map((opt) => String(opt.value || '').trim())
                .filter((value) => value.length > 0);
        }

        function setDeferredSelectedStatuses(values) {
            const statusSelect = document.getElementById('deferredStatusSelect');
            if (!statusSelect) return;

            const normalized = new Set((Array.isArray(values) ? values : [])
                .map((value) => String(value || '').trim().toLowerCase())
                .filter((value) => value.length > 0));

            Array.from(statusSelect.options || []).forEach((opt) => {
                const key = String(opt.value || '').trim().toLowerCase();
                opt.selected = normalized.has(key);
            });
        }

        function openDeferredModalWithPresetStatus(statusKey) {
            const target = String(statusKey || '').trim().toLowerCase();
            const fallback = target === 'lukket' ? 'luk' : target;
            const value = findDeferredStatusOptionValue(target, fallback);

            openDeferredModal();

            if (!value) {
                showToast(`Status "${statusKey}" findes ikke i listen`, 'warning');
                return;
            }

            const statusSelect = document.getElementById('deferredStatusSelect');
            if (statusSelect) {
                setDeferredSelectedStatuses([value]);
            }
        }

        async function updateDeferredCaseAndStatus(caseId, statuses) {
            try {
                const normalizedStatuses = Array.isArray(statuses)
                    ? statuses
                        .map((status) => String(status || '').trim())
                        .filter((status) => status.length > 0)
                    : [];

                const res = await fetch(`/api/v1/sag/${caseIds}`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({
                        deferred_until_case_id: caseId ? parseInt(caseId, 10) : null,
                        deferred_until_status: normalizedStatuses.length ? normalizedStatuses.join(', ') : null
                    })
                });
                if (!res.ok) {
                    const err = await res.json();
                    throw new Error(err.detail || 'Kunne ikke opdatere');
                }
                window.location.reload();
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        function setDeferredCaseFromInputs() {
            const caseSelect = document.getElementById('deferredCaseSelect');
            updateDeferredCaseAndStatus(caseSelect.value || null, getDeferredSelectedStatuses());
        }

        function applyDeferredStatusTrigger(primaryStatus, fallbackContains, missingMessage) {
            const caseSelect = document.getElementById('deferredCaseSelect');
            const statusSelect = document.getElementById('deferredStatusSelect');
            if (!caseSelect || !statusSelect) return;

            if (!caseSelect.value) {
                showToast('Vælg først en relateret sag', 'warning');
                return;
            }

            const targetPrimary = String(primaryStatus || '').trim().toLowerCase();
            const targetFallback = String(fallbackContains || '').trim().toLowerCase();
            const matchValue = findDeferredStatusOptionValue(targetPrimary, targetFallback);

            if (!matchValue) {
                showToast(missingMessage || 'Status findes ikke i listen', 'warning');
                return;
            }

            setDeferredSelectedStatuses([matchValue]);
            saveDeferredAll();
        }

        function applyDeferredCloseTrigger() {
            applyDeferredStatusTrigger('lukket', 'luk', 'Status "Lukket" findes ikke i listen');
        }

        function applyDeferredResolvedTrigger() {
            applyDeferredStatusTrigger('løst', 'løs', 'Status "Løst" findes ikke i listen');
        }

        function applyDeferredAnyStatusChangeTrigger() {
            const caseSelect = document.getElementById('deferredCaseSelect');
            if (!caseSelect || !caseSelect.value) {
                showToast('Vælg først en relateret sag', 'warning');
                return;
            }
            setDeferredSelectedStatuses(['__any_change__']);
            saveDeferredAll();
        }

        function clearDeferredCase() {
            const caseSelect = document.getElementById('deferredCaseSelect');
            caseSelect.value = '';
            setDeferredSelectedStatuses([]);
            updateDeferredCaseAndStatus(null, null);
        }

        function saveDeferredAll() {
            const input = document.getElementById('deferredUntilInput');
            const caseSelect = document.getElementById('deferredCaseSelect');
            updateDeferredUntil(input.value || null);
            updateDeferredCaseAndStatus(caseSelect.value || null, getDeferredSelectedStatuses());
        }

        function clearDeferredAll() {
            const input = document.getElementById('deferredUntilInput');
            const caseSelect = document.getElementById('deferredCaseSelect');
            input.value = '';
            caseSelect.value = '';
            setDeferredSelectedStatuses([]);
            updateDeferredUntil(null);
            updateDeferredCaseAndStatus(null, null);
        }

        function togglePipelineEdit(forceEdit = null) {
            const moduleBody = document.getElementById('pipelineCardBody');
            const collapseIcon = document.getElementById('pipelineCollapseIcon');
            const view = document.getElementById('pipelineViewMode');
            const edit = document.getElementById('pipelineEditMode');
            const shouldEdit = forceEdit === null ? edit.classList.contains('d-none') : forceEdit;

            if (moduleBody && moduleBody.classList.contains('d-none')) {
                moduleBody.classList.remove('d-none');
            }
            if (collapseIcon) {
                collapseIcon.classList.remove('bi-chevron-down');
                collapseIcon.classList.add('bi-chevron-up');
            }

            if (shouldEdit) {
                view.classList.add('d-none');
                edit.classList.remove('d-none');
            } else {
                view.classList.remove('d-none');
                edit.classList.add('d-none');
            }

            if (shouldEdit) {
                ensurePipelineStagesLoaded();
            }
        }

        function togglePipelineModule(forceOpen = null) {
            const moduleBody = document.getElementById('pipelineCardBody');
            const collapseIcon = document.getElementById('pipelineCollapseIcon');
            if (!moduleBody) return;

            const shouldOpen = forceOpen === null ? moduleBody.classList.contains('d-none') : Boolean(forceOpen);
            if (shouldOpen) {
                moduleBody.classList.remove('d-none');
                if (collapseIcon) {
                    collapseIcon.classList.remove('bi-chevron-down');
                    collapseIcon.classList.add('bi-chevron-up');
                }
                return;
            }

            moduleBody.classList.add('d-none');
            if (collapseIcon) {
                collapseIcon.classList.remove('bi-chevron-up');
                collapseIcon.classList.add('bi-chevron-down');
            }
        }

        async function ensurePipelineStagesLoaded() {
            const select = document.getElementById('pipelineStageSelect');
            if (!select) return;

            if (select.options.length > 1) return;

            try {
                const response = await fetch('/api/v1/pipeline/stages', { credentials: 'include' });
                if (!response.ok) return;

                const stages = await response.json();
                if (!Array.isArray(stages) || stages.length === 0) return;

                const existingValue = select.value || '';
                select.innerHTML = '<option value="">Ikke sat</option>' +
                    stages.map((stage) => `<option value="${stage.id}">${stage.name}</option>`).join('');
                if (existingValue) {
                    select.value = existingValue;
                }
            } catch (error) {
                console.error('Could not load pipeline stages', error);
            }
        }

        async function saveCaseType(newType, newLabel, newIcon, newColor) {
            // Update UI immediately for snappy feel
            const btn = document.getElementById('caseTypeDropdownBtn');
            const lbl = document.getElementById('caseTypeLabel');
            const ico = document.getElementById('caseTypeIcon');
            if (btn) btn.style.setProperty('--tcolor', newColor);
            if (lbl) lbl.textContent = newLabel;
            if (ico) { ico.className = 'bi ' + newIcon; }
            window.caseTypeKey = String(newType || 'ticket').toLowerCase();

            try {
                const resp = await fetch(`/api/v1/sag/${caseId}`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ type: newType })
                });
                if (!resp.ok) throw new Error('HTTP ' + resp.status);
                // Reload to re-render template vars (color accent on ID chip etc.)
                location.reload();
            } catch (e) {
                console.error('saveCaseType error', e);
                showToast('Kunne ikke gemme sagstype', 'danger');
            }
        }

        async function saveCaseStatusFromTopbar() {
            const select = document.getElementById('topbarStatusSelect');
            if (!select) return;

            try {
                const response = await fetch(`/api/v1/sag/${caseId}`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ status: select.value || 'åben' })
                });

                if (!response.ok) throw new Error('HTTP ' + response.status);
                location.reload();
            } catch (e) {
                console.error('saveCaseStatusFromTopbar error', e);
                showToast('Kunne ikke gemme status', 'danger');
            }
        }

        async function hydrateTopbarStatusOptions() {
            const select = document.getElementById('topbarStatusSelect');
            if (!select) return;

            const initialValue = String(select.value || '').trim();
            const known = new Map();

            const addStatus = (raw) => {
                const value = String(raw || '').trim();
                if (!value) return;
                const key = value.toLowerCase();
                if (!known.has(key)) {
                    known.set(key, value);
                }
            };

            Array.from(select.options || []).forEach((opt) => addStatus(opt.value));

            try {
                const response = await fetch('/api/v1/sag?include_deferred=true', { credentials: 'include' });
                if (response.ok) {
                    const cases = await response.json();
                    (Array.isArray(cases) ? cases : []).forEach((c) => addStatus(c?.status));
                }
            } catch (error) {
                console.warn('Could not hydrate status options from cases API', error);
            }

            ['åben', 'under behandling', 'afventer', 'løst', 'lukket'].forEach(addStatus);
            addStatus(initialValue);

            const sortedValues = Array.from(known.values()).sort((a, b) =>
                a.localeCompare(b, 'da', { sensitivity: 'base' })
            );

            select.innerHTML = sortedValues.map((value) => {
                const selected = initialValue && value.toLowerCase() === initialValue.toLowerCase();
                return `<option value="${value}" ${selected ? 'selected' : ''}>${value.charAt(0).toUpperCase()}${value.slice(1)}</option>`;
            }).join('');

            if (initialValue) {
                select.value = Array.from(known.values()).find((v) => v.toLowerCase() === initialValue.toLowerCase()) || initialValue;
            }

            applyTopbarImportanceBubbles();
        }

        function saveCaseTypeFromTopbar() {
            const select = document.getElementById('topbarTypeSelect');
            if (!select) return;

            const typeMeta = {
                ticket: { label: 'Ticket', icon: 'bi-ticket-perforated', color: '#6366f1' },
                pipeline: { label: 'Pipeline', icon: 'bi-graph-up-arrow', color: '#0ea5e9' },
                opgave: { label: 'Opgave', icon: 'bi-puzzle', color: '#f59e0b' },
                ordre: { label: 'Ordre', icon: 'bi-receipt', color: '#10b981' },
                projekt: { label: 'Projekt', icon: 'bi-folder2-open', color: '#8b5cf6' },
                service: { label: 'Service', icon: 'bi-tools', color: '#ef4444' }
            };

            const nextType = (select.value || 'ticket').toLowerCase();
            const meta = typeMeta[nextType] || typeMeta.ticket;
            saveCaseType(nextType, meta.label, meta.icon, meta.color);
        }

        async function saveCasePriorityFromTopbar() {
            const select = document.getElementById('topbarPrioritySelect');
            if (!select) return;

            try {
                const resp = await fetch(`/api/v1/sag/${caseId}`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ priority: (select.value || 'normal').toLowerCase() })
                });

                if (!resp.ok) throw new Error('HTTP ' + resp.status);
                location.reload();
            } catch (e) {
                console.error('saveCasePriorityFromTopbar error', e);
                showToast('Kunne ikke gemme prioritet', 'danger');
            }
        }

        async function saveCaseStartDateFromTopbar() {
            const input = document.getElementById('topbarStartDateInput');
            if (!input) return;

            try {
                const resp = await fetch(`/api/v1/sag/${caseId}`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ start_date: input.value || null })
                });

                if (!resp.ok) throw new Error('HTTP ' + resp.status);
                location.reload();
            } catch (e) {
                console.error('saveCaseStartDateFromTopbar error', e);
                showToast('Kunne ikke gemme startdato', 'danger');
            }
        }

        function clearCaseStartDateFromTopbar() {
            const input = document.getElementById('topbarStartDateInput');
            if (!input) return;
            input.value = '';
            saveCaseStartDateFromTopbar();
        }

        function setStartDateAndSave(offsetDays = 0) {
            const input = document.getElementById('topbarStartDateInput');
            if (!input) return;
            const base = new Date();
            base.setDate(base.getDate() + Number(offsetDays || 0));
            input.value = base.toISOString().slice(0, 10);
            saveCaseStartDateFromTopbar();
        }

        function openStartDateModal() {
            const topbarInput = document.getElementById('topbarStartDateInput');
            const modalInput = document.getElementById('startDateModalInput');
            if (topbarInput && modalInput) {
                modalInput.value = topbarInput.value || '';
            }
            const modal = new bootstrap.Modal(document.getElementById('startDateModal'));
            modal.show();
        }

        function shiftStartDateDays(days) {
            const input = document.getElementById('startDateModalInput');
            if (!input) return;
            const base = input.value ? new Date(input.value) : new Date();
            base.setDate(base.getDate() + days);
            input.value = base.toISOString().slice(0, 10);
        }

        function shiftStartDateMonths(months) {
            const input = document.getElementById('startDateModalInput');
            if (!input) return;
            const base = input.value ? new Date(input.value) : new Date();
            base.setMonth(base.getMonth() + months);
            input.value = base.toISOString().slice(0, 10);
        }

        function setStartDateModalToday() {
            const input = document.getElementById('startDateModalInput');
            if (!input) return;
            input.value = new Date().toISOString().slice(0, 10);
        }

        function clearStartDateFromModal() {
            const topbarInput = document.getElementById('topbarStartDateInput');
            const modalInput = document.getElementById('startDateModalInput');
            if (topbarInput) topbarInput.value = '';
            if (modalInput) modalInput.value = '';
            saveCaseStartDateFromTopbar();
        }

        function saveStartDateFromModal() {
            const topbarInput = document.getElementById('topbarStartDateInput');
            const modalInput = document.getElementById('startDateModalInput');
            if (!topbarInput || !modalInput) return;
            topbarInput.value = modalInput.value || '';
            saveCaseStartDateFromTopbar();
        }

        async function saveAssignmentFromTabsBar() {
            const topUser = document.getElementById('tabsAssignmentUserSelect');
            const topGroup = document.getElementById('tabsAssignmentGroupSelect');
            const legacyUser = document.getElementById('assignmentUserSelect');
            const legacyGroup = document.getElementById('assignmentGroupSelect');

            if (legacyUser && topUser) {
                legacyUser.value = topUser.value;
            }
            if (legacyGroup && topGroup) {
                legacyGroup.value = topGroup.value;
            }

            await saveAssignment();
        }

        async function saveAssignment() {
            const statusEl = document.getElementById('assignmentStatus');
            const userValue = document.getElementById('assignmentUserSelect')?.value || '';
            const groupValue = document.getElementById('assignmentGroupSelect')?.value || '';

            const payload = {
                ansvarlig_bruger_id: userValue ? parseInt(userValue, 10) : null,
                assigned_group_id: groupValue ? parseInt(groupValue, 10) : null
            };

            if (statusEl) {
                statusEl.textContent = 'Gemmer...';
            }

            try {
                const response = await fetch(`/api/v1/sag/${caseId}`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(payload)
                });

                if (!response.ok) {
                    let message = 'Kunne ikke gemme tildeling';
                    try {
                        const data = await response.json();
                        message = data.detail || message;
                    } catch (err) {
                        // Keep default message
                    }
                    if (statusEl) {
                        statusEl.textContent = `❌ ${message}`;
                    }
                    return;
                }

                if (statusEl) {
                    statusEl.textContent = '✅ Tildeling gemt';
                }

                const topUser = document.getElementById('tabsAssignmentUserSelect');
                const topGroup = document.getElementById('tabsAssignmentGroupSelect');
                if (topUser) {
                    topUser.value = userValue;
                }
                if (topGroup) {
                    topGroup.value = groupValue;
                }
            } catch (err) {
                if (statusEl) {
                    statusEl.textContent = `❌ ${err.message}`;
                }
            }
        }

        function openAssignmentQuick() {
            const preferred = document.getElementById('tabsAssignmentUserSelect')
                || document.getElementById('assignmentUserSelect');
            const fallback = document.getElementById('tabsAssignmentGroupSelect')
                || document.getElementById('assignmentGroupSelect');
            const target = preferred || fallback;

            if (!target) {
                alert('Kunne ikke finde tildelingsfelter på siden.');
                return;
            }

            target.scrollIntoView({ behavior: 'smooth', block: 'center' });
            setTimeout(() => target.focus(), 200);

            if (typeof showToast === 'function') {
                showToast('Vælg ansvarlig bruger/gruppe i feltet, så gemmes det med det samme.', 'info');
            }
        }

        async function savePipeline() {
            const stageValue = document.getElementById('pipelineStageSelect').value;
            const probabilityValue = document.getElementById('pipelineProbabilityInput').value;
            const amountValue = document.getElementById('pipelineAmountInput').value;
            const descriptionValue = document.getElementById('pipelineDescriptionInput').value;

            const payload = {
                stage_id: stageValue ? parseInt(stageValue, 10) : null,
                probability: probabilityValue === '' ? null : parseInt(probabilityValue, 10),
                amount: amountValue === '' ? null : parseFloat(amountValue),
                description: descriptionValue === '' ? null : descriptionValue
            };

            try {
                const response = await fetch(`/api/v1/sag/${caseId}/pipeline`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(payload)
                });

                if (!response.ok) {
                    let message = 'Kunne ikke opdatere pipeline';
                    try {
                        const err = await response.json();
                        message = err.detail || err.message || message;
                    } catch (_e) {
                        const text = await response.text();
                        if (text) message = text;
                    }
                    throw new Error(`${message} (HTTP ${response.status})`);
                }

                window.location.reload();
            } catch (error) {
                alert(`Fejl: ${error.message}`);
            }
        }

        // ==========================================
        // VIEW CONTROL (Tag-based)
        // ==========================================

        let modulePrefs = {};
        let currentCaseView = 'Sag-detalje';

        function moduleHasContent(el) {
            const attr = el.getAttribute('data-has-content');
            if (attr === 'true') return true;
            if (attr === 'false') return false;
            if (attr === 'unknown') return false;

            if (el.querySelector('.person-card')) return true;
            if (el.querySelector('.list-group-item')) return true;
            return true;
        }

        function setModuleContentState(moduleKey, hasContent) {
            const el = document.querySelector(`[data-module="${moduleKey}"]`);
            if (!el) return;
            el.setAttribute('data-has-content', hasContent ? 'true' : 'false');
            applyViewLayout(currentCaseView);
            updateCaseTabCountBadges();
        }

        function applyViewLayout(viewName) {
            if (!viewName) return;
            currentCaseView = viewName;
            document.body.setAttribute('data-case-view', viewName);

            const viewDefaults = {
                'Pipeline': ['pipeline', 'relations', 'sales', 'time', 'buzzwords'],
                'Kundevisning': ['customers', 'contacts', 'locations', 'wiki', 'tags', 'buzzwords'],
                'Sag-detalje': ['pipeline', 'hardware', 'locations', 'contacts', 'customers', 'wiki', 'tags', 'buzzwords', 'todo-steps', 'relations', 'call-history', 'files', 'emails', 'solution', 'time', 'sales', 'subscription', 'reminders', 'calendar']
            };

            const currentCaseTypeKey = (typeof caseTypeKey !== 'undefined' && caseTypeKey)
                ? caseTypeKey
                : (window.caseTypeKey || 'ticket');
            const defaultsByCaseType = caseTypeModuleDefaults[currentCaseTypeKey];
            const standardModules = Array.isArray(defaultsByCaseType) && defaultsByCaseType.length > 0
                ? defaultsByCaseType
                : (viewDefaults[viewName] || []);
            const standardModuleSet = new Set(standardModules);
            standardModuleSet.add('tags');
            standardModuleSet.add('time');
            standardModuleSet.add('buzzwords');

            document.querySelectorAll('[data-module]').forEach((el) => {
                const moduleName = el.getAttribute('data-module');
                const hasContent = moduleHasContent(el);
                const isTimeModule = moduleName === 'time';
                const isBuzzwordsModule = moduleName === 'buzzwords';
                const shouldCompactWhenEmpty = moduleName !== 'wiki' && moduleName !== 'pipeline' && moduleName !== 'buzzwords' && !isTimeModule;
                const pref = modulePrefs[moduleName];
                const tabButton = document.querySelector(`[data-module-tab="${moduleName}"]`);

                // Helper til at skjule eller vise modulet og dets mb-3 indpakning 
                const setVisibility = (visible) => {
                    let wrapper = null;
                    if (el.parentElement) {
                        const isMB3 = el.parentElement.classList.contains('mb-3');
                        const isRowCol12 = el.parentElement.classList.contains('col-12') && el.parentElement.parentElement && el.parentElement.parentElement.classList.contains('row');
                        if (isMB3) wrapper = el.parentElement;
                        else if (isRowCol12) wrapper = el.parentElement.parentElement;
                    }

                    if (visible) {
                        el.classList.remove('d-none');
                        if (wrapper && wrapper.classList.contains('d-none')) {
                            wrapper.classList.remove('d-none');
                        }
                        if (tabButton && tabButton.classList.contains('d-none')) {
                            tabButton.classList.remove('d-none');
                        }
                    } else {
                        el.classList.add('d-none');
                        if (wrapper && !wrapper.classList.contains('d-none')) wrapper.classList.add('d-none');
                        if (tabButton && !tabButton.classList.contains('d-none')) tabButton.classList.add('d-none');
                    }
                };

                // Altid vis time (tid)
                if (isTimeModule) {
                    setVisibility(true);
                    el.classList.remove('module-empty-compact');
                    return;
                }

                if (isBuzzwordsModule) {
                    setVisibility(true);
                    el.classList.remove('module-empty-compact');
                    return;
                }

                // HVIS specifik præference deaktiverer den - Skjul den! Uanset content.
                if (pref === false) {
                    setVisibility(false);
                    el.classList.remove('module-empty-compact');
                    return;
                }

                // HVIS specifik præference aktiverer den (brugervalg)
                if (pref === true) {
                    setVisibility(true);
                    el.classList.toggle('module-empty-compact', shouldCompactWhenEmpty && !hasContent);
                    return;
                }

                // Moduler med indhold vises automatisk, når der ikke er et eksplicit brugervalg.
                if (hasContent) {
                    setVisibility(true);
                    el.classList.remove('module-empty-compact');
                    return;
                }

                // Default logic - ingen content: se på layout defaults
                if (standardModuleSet.has(moduleName)) {
                    setVisibility(true);
                    el.classList.toggle('module-empty-compact', shouldCompactWhenEmpty);
                } else {
                    setVisibility(false);
                    el.classList.remove('module-empty-compact');
                }
            });

            updateRightColumnVisibility();
            updateInnerColumnVisibility();
        }

        function updateRightColumnVisibility() {
            const detailsPane = document.getElementById('details');
            const rightColumn = document.getElementById('case-right-column');
            const leftColumn = document.getElementById('case-left-column');
            if (!rightColumn || !leftColumn) return;

            if (detailsPane) {
                let detailsRow = null;
                try {
                    detailsRow = detailsPane.querySelector(':scope > .row.g-4');
                } catch (e) {
                    detailsRow = detailsPane.querySelector('.row.g-4');
                }
                if (detailsRow && rightColumn.parentElement !== detailsRow) {
                    detailsRow.appendChild(rightColumn);
                }
            }

            const visibleRightModules = rightColumn.querySelectorAll('.right-module-card:not(.d-none)');
            if (visibleRightModules.length === 0) {
                rightColumn.classList.add('d-none');
                rightColumn.classList.remove('col-xl-4');
                rightColumn.classList.remove('col-lg-4');
                leftColumn.classList.remove('col-xl-8');
                leftColumn.classList.remove('col-lg-8');
                leftColumn.classList.add('col-12');
            } else {
                rightColumn.classList.remove('d-none');
                rightColumn.classList.add('col-xl-4');
                rightColumn.classList.add('col-lg-4');
                leftColumn.classList.add('col-xl-8');
                leftColumn.classList.add('col-lg-8');
                leftColumn.classList.remove('col-12');
            }
        }

        function updateInnerColumnVisibility() {
            const leftCol = document.getElementById('inner-left-col');
            const centerCol = document.getElementById('inner-center-col');
            if (!leftCol || !centerCol) return;

            // Tæl synlige moduler i venstre kolonnen (mb-3 wrappers der ikke er skjulte)
            const visibleLeftModules = leftCol.querySelectorAll('.mb-3:not(.d-none) [data-module]');
            const hasVisibleLeft = visibleLeftModules.length > 0;

            if (!hasVisibleLeft) {
                // Ingen synlige moduler i venstre - center forbliver fuld bredde
                leftCol.classList.add('d-none');
                centerCol.classList.add('col-12');
            } else {
                // Begge interne sektioner vises stadig i én kolonne hver
                leftCol.classList.remove('d-none');
                centerCol.classList.add('col-12');
            }
        }

        function _setCaseTabCountBadge(badgeId, count) {
            const badge = document.getElementById(badgeId);
            if (!badge) return;
            const safeCount = Number(count || 0);
            if (safeCount <= 0) {
                badge.style.display = 'none';
                badge.textContent = '';
                return;
            }
            badge.style.display = 'inline-block';
            badge.textContent = safeCount > 99 ? '99+' : String(safeCount);
        }

        function _countRows(selector) {
            const container = document.querySelector(selector);
            if (!container) return 0;
            const rows = Array.from(container.querySelectorAll('tr'));
            return rows.filter((row) => {
                const cells = row.querySelectorAll('td');
                if (cells.length === 0) return false;
                const colspanCell = row.querySelector('td[colspan]');
                if (colspanCell && cells.length === 1) return false;
                return true;
            }).length;
        }

        function updateCaseTabCountBadges() {
            const detailCount = document.querySelectorAll('#details .right-module-card[data-has-content="true"]').length;
            _setCaseTabCountBadge('detailsTabCountBadge', detailCount);

            const solutionHasContent = String(document.getElementById('solution')?.getAttribute('data-has-content') || '').toLowerCase() === 'true';
            _setCaseTabCountBadge('solutionTabCountBadge', solutionHasContent ? 1 : 0);

            const emailThreads = Number(document.getElementById('linkedEmailThreadsCount')?.textContent || 0);
            _setCaseTabCountBadge('emailsTabCountBadge', emailThreads);

            const salesCount = _countRows('#saleItemsSalesBody') + _countRows('#saleItemsPurchaseBody');
            _setCaseTabCountBadge('salesTabCountBadge', salesCount);

            const supplierCount = _countRows('#supplierPurchaseLinesBody');
            _setCaseTabCountBadge('supplierTabCountBadge', supplierCount);

            const timeEntriesStore = (typeof timeV1EntriesById !== 'undefined' && timeV1EntriesById && typeof timeV1EntriesById === 'object')
                ? timeV1EntriesById
                : null;
            const initialTimeCount = Number(window.initialCaseTabCounts?.timetracking || 0);
            const loadedTimeCount = timeEntriesStore ? Object.keys(timeEntriesStore).length : 0;
            const timeDomCount = document.querySelectorAll('#timetracking tbody tr').length;
            const timeCount = Math.max(initialTimeCount, loadedTimeCount, timeDomCount);
            _setCaseTabCountBadge('timetrackingTabCountBadge', timeCount);

            const subscriptionCount = _countRows('#subscriptionItemsBody');
            _setCaseTabCountBadge('subscriptionTabCountBadge', subscriptionCount);

            const reminderCount = document.querySelectorAll('#remindersList .list-group-item').length;
            _setCaseTabCountBadge('remindersTabCountBadge', reminderCount);
        }

        async function applyViewFromTags() {
            try {
                const res = await fetch(`/api/v1/tags/entity/case/${caseIds}`);
                if (!res.ok) return;
                const tags = await res.json();
                const viewTag = tags.find(t => ['Pipeline', 'Kundevisning', 'Sag-detalje'].includes(t.name));
                applyViewLayout(viewTag ? viewTag.name : 'Sag-detalje');
                updateCaseTabCountBadges();
            } catch (e) {
                console.error('View tag lookup failed', e);
            }
        }

        async function loadModulePrefs() {
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}/modules`);
                if (!res.ok) return;
                const prefs = await res.json();
                modulePrefs = (prefs || []).reduce((acc, p) => {
                    acc[p.module_key] = p.is_enabled;
                    return acc;
                }, {});
                modulePrefs.time = true;
                updateCaseTabCountBadges();
            } catch (e) {
                console.error('Module prefs load failed', e);
            }
        }

        async function loadCaseTypeModuleDefaultsSetting() {
            try {
                const res = await fetch('/api/v1/settings/case_type_module_defaults');
                if (!res.ok) return;
                const setting = await res.json();
                const parsed = JSON.parse(setting.value || '{}');
                if (parsed && typeof parsed === 'object') {
                    caseTypeModuleDefaults = Object.entries(parsed).reduce((acc, [key, value]) => {
                        acc[String(key || '').toLowerCase()] = Array.isArray(value) ? value : [];
                        return acc;
                    }, {});
                } else {
                    caseTypeModuleDefaults = {};
                }
            } catch (e) {
                console.error('Case type module defaults load failed', e);
                caseTypeModuleDefaults = {};
            }
        }

        async function openModuleControlModal() {
            const list = document.getElementById('moduleControlList');
            list.innerHTML = '<div class="text-muted small">Indlæser...</div>';

            const modules = Array.from(document.querySelectorAll('[data-module]')).map(el => {
                const key = el.getAttribute('data-module');
                return { key, label: window.moduleDisplayNames[key] || key };
            });

            list.innerHTML = modules.map(m => {
                const isTimeModule = m.key === 'time';
                const checked = isTimeModule ? true : modulePrefs[m.key] !== false;
                return `
                    <div class="form-check mb-2">
                        <input class="form-check-input" type="checkbox" id="module_${m.key}" ${checked ? 'checked' : ''}
                            ${isTimeModule ? 'disabled' : ''}
                            onchange="toggleModulePref('${m.key}', this.checked)">
                        <label class="form-check-label" for="module_${m.key}">${m.label}${isTimeModule ? ' (altid synlig)' : ''}</label>
                    </div>
                `;
            }).join('');

            const modal = new bootstrap.Modal(document.getElementById('moduleControlModal'));
            modal.show();
        }

        async function toggleModulePref(moduleKey, isEnabled) {
            if (moduleKey === 'time') {
                modulePrefs.time = true;
                applyViewFromTags();
                return;
            }
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}/modules`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ module_key: moduleKey, is_enabled: isEnabled })
                });
                if (!res.ok) {
                    const err = await res.json();
                    throw new Error(err.detail || 'Kunne ikke opdatere modul');
                }
                modulePrefs[moduleKey] = isEnabled;
                applyViewFromTags();
            } catch (e) {
                alert('Fejl: ' + e.message);
            }
        }

        // ==========================================
        // FILES & EMAILS LOGIC
        // ==========================================

        let sagFilesCache = [];
        
        // ---------------- FILES ----------------

        function updateCaseEmailAttachmentOptions(files) {
            const select = document.getElementById('caseEmailAttachmentIds');
            if (!select) return;

            const safeFiles = Array.isArray(files) ? files : [];
            if (!safeFiles.length) {
                select.innerHTML = '<option disabled>Ingen sagsfiler tilgængelige</option>';
                return;
            }

            select.innerHTML = safeFiles.map((file) => {
                const fileId = Number(file.id);
                const filename = escapeHtml(file.filename || `Fil ${fileId}`);
                const date = file.created_at ? new Date(file.created_at).toLocaleDateString('da-DK') : '-';
                return `<option value="${fileId}">${filename} (${date})</option>`;
            }).join('');
        }
        
        async function loadSagFiles() {
            const container = document.getElementById('files-list');
            if (container) {
                container.innerHTML = '<div class="p-3 text-center text-muted"><span class="spinner-border spinner-border-sm"></span> Henter filer...</div>';
            }
            
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}/files`);
                if(res.ok) {
                    const files = await res.json();
                    sagFilesCache = Array.isArray(files) ? files : [];
                    updateCaseEmailAttachmentOptions(sagFilesCache);
                    renderFiles(files);
                } else {
                    sagFilesCache = [];
                    updateCaseEmailAttachmentOptions(sagFilesCache);
                    if (container) {
                        container.innerHTML = '<div class="p-3 text-center text-danger">Fejl ved hentning af filer</div>';
                    }
                    setModuleContentState('files', true);
                }
            } catch(e) {
                console.error(e);
                sagFilesCache = [];
                updateCaseEmailAttachmentOptions(sagFilesCache);
                if (container) {
                    container.innerHTML = '<div class="p-3 text-center text-danger">Fejl ved hentning af filer</div>';
                }
                setModuleContentState('files', true);
            }
        }

        function renderFiles(files) {
            const container = document.getElementById('files-list');
            sagFilesCache = Array.isArray(files) ? files : [];
            updateCaseEmailAttachmentOptions(sagFilesCache);

            if (!container) {
                return;
            }

            if(!files || files.length === 0) {
                container.innerHTML = '<div class="p-3 text-center text-muted">Ingen filer fundet...</div>';
                setModuleContentState('files', false);
                return;
            }
            setModuleContentState('files', true);
            container.innerHTML = files.map(f => {
                const size = (f.size_bytes / 1024 / 1024).toFixed(2) + ' MB';
                const sourceType = String(f.source_type || '').toLowerCase();
                const sourceToken = String(f.source_token || '').toUpperCase();
                const isWorkOrder = sourceType === 'scanner_email' && sourceToken.includes('BMCSCAN-WO-');
                const isScannerFile = sourceType === 'scanner_email';
                const displayName = isWorkOrder ? `Arbejdsseddel: ${f.filename}` : f.filename;
                const badgeHtml = isWorkOrder
                    ? '<span class="badge rounded-pill text-bg-warning ms-2"><i class="bi bi-clipboard-check me-1"></i>Arbejdsseddel</span>'
                    : (isScannerFile
                        ? '<span class="badge rounded-pill text-bg-info ms-2"><i class="bi bi-upc-scan me-1"></i>Scanner</span>'
                        : '');
                return `
                    <div class="list-group-item d-flex justify-content-between align-items-center">
                        <div class="ms-2 me-auto">
                            <div class="fw-bold text-truncate d-flex align-items-center" style="max-width: 380px;">
                                <a href="javascript:void(0);" onclick="previewFile(${f.id}, '${f.filename.replace(/'/g, "\\'")}', '${f.content_type || ''}')" class="text-decoration-none text-dark">
                                    <i class="bi ${isWorkOrder ? 'bi-clipboard-check' : 'bi-file-earmark'} me-1"></i> ${displayName}
                                </a>
                                ${badgeHtml}
                            </div>
                            <small class="text-muted">${size} • ${new Date(f.created_at).toLocaleDateString()}</small>
                        </div>
                        <div class="d-flex gap-1">
                            <a href="${f.download_url}?download=true" class="btn btn-sm btn-outline-primary border-0" title="Download">
                                <i class="bi bi-download"></i>
                            </a>
                            <button class="btn btn-sm btn-outline-danger border-0" onclick="deleteFile(${f.id})" title="Slet">
                                <i class="bi bi-x-lg"></i>
                            </button>
                        </div>
                    </div>
                `;
            }).join('');
        }

        async function handleFileUpload(fileList) {
            if(!fileList || fileList.length === 0) return;
            const formData = new FormData();
            for (let i = 0; i < fileList.length; i++) {
                formData.append("files", fileList[i]);
            }
            
            // Show loading
            document.getElementById('files-list').innerHTML += '<div class="p-2 text-center text-muted fst-italic">Uploader...</div>';
            
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}/files`, {
                    method: 'POST',
                    body: formData
                });
                if(res.ok) {
                    loadSagFiles();
                } else {
                    alert('Upload fejlede');
                    loadSagFiles(); // Reload to clear loading state
                }
            } catch(e) {
                alert('Upload fejl: ' + e);
                loadSagFiles();
            }
        }

        async function deleteFile(fileId) {
            if(!confirm("Slet denne fil?")) return;
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}/files/${fileId}`, { method: 'DELETE' });
                if(res.ok) loadSagFiles();
                else alert("Kunne ikke slette fil");
            } catch(e) { alert("Fejl: " + e); }
        }

        async function renderPdfPreview(fileUrl, fileId, filename, previewContent) {
            const imageUrl = `/api/v1/sag/${caseIds}/files/${fileId}/preview-image?page=1&scale=3.4`;

            previewContent.innerHTML = `
                <div class="d-flex flex-column align-items-center justify-content-center w-100" style="min-height: 70vh;">
                    <div class="spinner-border text-primary" role="status"></div>
                    <div class="small text-muted mt-2">Indlæser PDF...</div>
                </div>
            `;

            const img = new Image();
            img.alt = filename;
            img.className = 'img-fluid';
            img.style.maxHeight = '86vh';
            img.style.width = 'auto';
            img.style.display = 'block';
            img.style.margin = '0 auto';
            img.style.boxShadow = '0 8px 24px rgba(0,0,0,0.2)';
            img.style.background = '#fff';

            img.onload = () => {
                previewContent.innerHTML = '';

                const frame = document.createElement('div');
                frame.style.background = '#eef2f7';
                frame.style.padding = '6px';
                frame.style.borderRadius = '12px';
                frame.style.minHeight = '82vh';
                frame.appendChild(img);
                previewContent.appendChild(frame);
            };

            img.onerror = () => {
                // Fallback to native viewer in full-window tab if image rendering fails.
                window.open(fileUrl, '_blank', 'noopener');
                previewContent.innerHTML = `
                    <div class="p-4 text-center text-muted">
                        Kunne ikke vise PDF i modal. Åbnede i nyt vindue.
                    </div>
                `;
            };

            img.src = imageUrl;
        }

        // File Preview
        function previewFile(fileId, filename, contentType) {
            const modal = new bootstrap.Modal(document.getElementById('filePreviewModal'));
            const previewContent = document.getElementById('previewContent');
            const fileNameEl = document.getElementById('previewFileName');
            
            // Set filename
            fileNameEl.textContent = filename;
            const fileUrl = `/api/v1/sag/${caseIds}/files/${fileId}`;
            
            // Show loading spinner
            previewContent.innerHTML = `
                <div class="spinner-border text-primary" role="status">
                    <span class="visually-hidden">Indlæser...</span>
                </div>
            `;
            
            modal.show();
            
            // Determine file type and render preview
            const ext = filename.split('.').pop().toLowerCase();
            
            if (['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'bmp'].includes(ext)) {
                // Image preview
                previewContent.innerHTML = `<img src="${fileUrl}" class="img-fluid" style="max-height: 80vh;" alt="${filename}">`;
            } else if (ext === 'pdf') {
                // PDF preview with forced readable scale
                renderPdfPreview(fileUrl, fileId, filename, previewContent);
            } else if (['txt', 'log', 'md', 'json', 'xml', 'csv', 'html', 'css', 'js', 'py', 'sql'].includes(ext)) {
                // Text file preview
                fetch(fileUrl)
                    .then(res => res.text())
                    .then(text => {
                        previewContent.innerHTML = `<pre class="p-3 m-0 overflow-auto h-100" style="max-height: 80vh;"><code>${escapeHtml(text)}</code></pre>`;
                    })
                    .catch(err => {
                        previewContent.innerHTML = `<div class="alert alert-danger m-4">Kunne ikke indlæse fil: ${err}</div>`;
                    });
            } else if (['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'].includes(ext)) {
                // Office documents - use Google Docs Viewer
                const encodedUrl = encodeURIComponent(window.location.origin + fileUrl);
                previewContent.innerHTML = `<iframe src="https://docs.google.com/viewer?url=${encodedUrl}&embedded=true" class="w-100 h-100 border-0" style="min-height: 60vh;"></iframe>`;
            } else if (['mp4', 'webm', 'ogg'].includes(ext)) {
                // Video preview
                previewContent.innerHTML = `
                    <video controls class="w-100" style="max-height: 80vh;">
                        <source src="${fileUrl}" type="video/${ext}">
                        Din browser understøtter ikke video afspilning.
                    </video>
                `;
            } else if (['mp3', 'wav', 'ogg', 'm4a'].includes(ext)) {
                // Audio preview
                previewContent.innerHTML = `
                    <div class="p-5 text-center">
                        <i class="bi bi-music-note-beamed display-1 text-muted mb-4"></i>
                        <h5>${filename}</h5>
                        <audio controls class="w-100 mt-3">
                            <source src="${fileUrl}" type="audio/${ext}">
                            Din browser understøtter ikke audio afspilning.
                        </audio>
                    </div>
                `;
            } else {
                // Unsupported file type
                previewContent.innerHTML = `
                    <div class="p-5 text-center">
                        <i class="bi bi-file-earmark-x display-1 text-muted mb-4"></i>
                        <h5>Kan ikke vise forhåndsvisning for denne filtype</h5>
                        <p class="text-muted">${filename}</p>
                        <a href="${fileUrl}?download=true" class="btn btn-primary mt-3" download="${filename}">
                            <i class="bi bi-download me-2"></i> Download fil
                        </a>
                    </div>
                `;
            }
        }

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

        // File Drag & Drop
        const fileDropZone = document.getElementById('fileDropZone');
        if(fileDropZone) {
            fileDropZone.addEventListener('dragover', e => { e.preventDefault(); fileDropZone.classList.add('bg-light-subtle'); });
            fileDropZone.addEventListener('dragleave', e => { e.preventDefault(); fileDropZone.classList.remove('bg-light-subtle'); });
            fileDropZone.addEventListener('drop', e => {
                e.preventDefault();
                fileDropZone.classList.remove('bg-light-subtle');
                if(e.dataTransfer.files.length) handleFileUpload(e.dataTransfer.files);
            });
        }
        
        // ---------------- EMAILS ----------------

        let linkedEmailsCache = [];
        let filteredLinkedEmailsCache = [];
        let selectedLinkedEmailId = null;
        let isNewThread = false;  // true when composing a brand-new thread (not a reply)
        let selectedLinkedEmailDetail = null;
        let selectedEmailThreadKey = null;

        function parseEmailField(value) {
            return String(value || '')
                .split(/[\n,;]+/)
                .map((email) => email.trim())
                .filter(Boolean);
        }

        function escapeHtmlForInput(value) {
            return String(value || '')
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#39;');
        }

        let rewriteReviewState = null;

        function extractRewriteBody(rawText, context) {
            const text = String(rawText || '').trim();
            if (!text) return '';

            if (context === 'email') {
                const bodyMatch = text.match(/(?:^|\n)Besked:\s*\n([\s\S]*)$/i);
                if (bodyMatch?.[1]) return bodyMatch[1].trim();
                return text;
            }

            if (context === 'case') {
                const descMatch = text.match(/(?:^|\n)Beskrivelse:\s*\n([\s\S]*)$/i);
                if (descMatch?.[1]) return descMatch[1].trim();
                return text;
            }

            return text;
        }

        function buildLineDiff(originalText, rewrittenText) {
            const originalLines = String(originalText || '').split('\n');
            const rewrittenLines = String(rewrittenText || '').split('\n');
            const maxLen = Math.max(originalLines.length, rewrittenLines.length);
            const changes = [];

            for (let idx = 0; idx < maxLen; idx += 1) {
                const before = originalLines[idx] ?? '';
                const after = rewrittenLines[idx] ?? '';
                if (before !== after) {
                    changes.push({ index: idx, before, after });
                }
            }

            return { changes, originalLines, rewrittenLines };
        }

        function updateRewriteSelectionInfo() {
            const infoEl = document.getElementById('rewritePreviewSelectionInfo');
            const selectedCount = document.querySelectorAll('.rewrite-change-check:checked').length;
            const totalCount = rewriteReviewState?.changes?.length || 0;
            if (!infoEl) return;
            infoEl.textContent = `${selectedCount} af ${totalCount} ændringer valgt`;
        }

        function renderRewritePreview(changes) {
            const listEl = document.getElementById('rewritePreviewList');
            const noChangesEl = document.getElementById('rewritePreviewNoChanges');
            if (!listEl || !noChangesEl) return;

            if (!changes.length) {
                listEl.innerHTML = '';
                noChangesEl.classList.remove('d-none');
                return;
            }

            noChangesEl.classList.add('d-none');
            listEl.innerHTML = changes.map((change, i) => `
                <div class="card border-0 shadow-sm">
                    <div class="card-body py-2 px-3">
                        <div class="d-flex justify-content-between align-items-center mb-2">
                            <div class="form-check">
                                <input class="form-check-input rewrite-change-check" type="checkbox" value="${change.index}" id="rewriteChange_${change.index}" checked>
                                <label class="form-check-label small fw-semibold" for="rewriteChange_${change.index}">
                                    Ændring ${i + 1} (linje ${change.index + 1})
                                </label>
                            </div>
                        </div>
                        <div class="row g-2">
                            <div class="col-md-6">
                                <div class="small text-muted mb-1">Før</div>
                                <div class="border rounded p-2 bg-light" style="white-space: pre-wrap; min-height: 44px;">${escapeHtml(change.before) || '<span class="text-muted fst-italic">(tom)</span>'}</div>
                            </div>
                            <div class="col-md-6">
                                <div class="small text-muted mb-1">Efter</div>
                                <div class="border rounded p-2" style="white-space: pre-wrap; min-height: 44px; background: rgba(15,76,117,0.08);">${escapeHtml(change.after) || '<span class="text-muted fst-italic">(tom)</span>'}</div>
                            </div>
                        </div>
                    </div>
                </div>
            `).join('');

            listEl.querySelectorAll('.rewrite-change-check').forEach((input) => {
                input.addEventListener('change', updateRewriteSelectionInfo);
            });
            updateRewriteSelectionInfo();
        }

        function applyRewriteChanges(mode) {
            if (!rewriteReviewState) return;

            const { originalLines, rewrittenLines, applyToTarget } = rewriteReviewState;
            if (mode === 'all') {
                applyToTarget(rewrittenLines.join('\n'));
                return;
            }

            const selectedIndexes = new Set(
                Array.from(document.querySelectorAll('.rewrite-change-check:checked'))
                    .map((el) => Number(el.value))
                    .filter((val) => Number.isInteger(val) && val >= 0)
            );

            const merged = [...originalLines];
            for (let idx = 0; idx < rewrittenLines.length; idx += 1) {
                if (selectedIndexes.has(idx)) {
                    merged[idx] = rewrittenLines[idx] ?? '';
                }
            }
            applyToTarget(merged.join('\n'));
        }

        function openRewriteReviewModal({ title, originalText, rewrittenText, applyToTarget }) {
            const summaryEl = document.getElementById('rewritePreviewSummary');
            const applyAllBtn = document.getElementById('rewriteApplyAllBtn');
            const applySelectedBtn = document.getElementById('rewriteApplySelectedBtn');
            const modalEl = document.getElementById('rewritePreviewModal');
            if (!summaryEl || !applyAllBtn || !applySelectedBtn || !modalEl) return;

            const diff = buildLineDiff(originalText, rewrittenText);
            rewriteReviewState = {
                ...diff,
                applyToTarget,
            };

            summaryEl.textContent = `${title}: ${diff.changes.length} foreslaaede ændringer.`;
            renderRewritePreview(diff.changes);

            applyAllBtn.disabled = !diff.changes.length;
            applySelectedBtn.disabled = !diff.changes.length;

            const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
            modal.show();
        }

        async function requestRewriteSuggestion(endpoint, text, context) {
            const response = await fetch(endpoint, {
                method: 'POST',
                credentials: 'include',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ text, context })
            });
            if (!response.ok) {
                let detail = `HTTP ${response.status}`;
                try {
                    const err = await response.json();
                    if (err?.detail) detail = err.detail;
                } catch (_) {}
                throw new Error(detail);
            }
            return response.json();
        }

        window.rewriteCaseEmailWithApproval = async function () {
            const bodyInput = document.getElementById('caseEmailBody');
            const btn = document.getElementById('caseEmailRewriteBtn');
            if (!bodyInput) return;

            const source = (bodyInput.value || '').trim();
            if (!source) {
                alert('Skriv en besked først.');
                return;
            }

            const originalHtml = btn?.innerHTML || '';
            if (btn) {
                btn.disabled = true;
                btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Renskriver...';
            }

            try {
                const payload = await requestRewriteSuggestion('/api/v1/emails/rewrite-text', source, 'email');
                const rewritten = extractRewriteBody(payload?.rewritten_text || '', 'email');
                openRewriteReviewModal({
                    title: 'Email-tekst',
                    originalText: source,
                    rewrittenText: rewritten,
                    applyToTarget: (nextText) => {
                        bodyInput.value = nextText;
                        bootstrap.Modal.getOrCreateInstance(document.getElementById('rewritePreviewModal')).hide();
                    }
                });
            } catch (error) {
                console.error(error);
                alert(`Kunne ikke renskrive email: ${error.message || 'Ukendt fejl'}`);
            } finally {
                if (btn) {
                    btn.disabled = false;
                    btn.innerHTML = originalHtml;
                }
            }
        };

        function getDefaultCaseRecipient() {
            const primaryContact = document.querySelector('.contact-row[data-is-primary="true"][data-email]');
            if (primaryContact?.dataset?.email) {
                return primaryContact.dataset.email.trim();
            }

            const anyContact = document.querySelector('.contact-row[data-email]');
            if (anyContact?.dataset?.email) {
                return anyContact.dataset.email.trim();
            }

            const customerSmall = document.querySelector('.customer-row small');
            if (customerSmall) {
                const text = customerSmall.textContent || '';
                const match = text.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i);
                if (match) {
                    return match[0].trim();
                }
            }

            return '';
        }

        function prefillCaseEmailCompose() {
            const toInput = document.getElementById('caseEmailTo');
            const subjectInput = document.getElementById('caseEmailSubject');
            const modalLabel = document.getElementById('caseEmailComposeModalLabel');

            // Update modal title based on context
            if (modalLabel) {
                modalLabel.innerHTML = isNewThread
                    ? '<i class="bi bi-envelope-plus me-2"></i>Ny email (ny tråd)'
                    : '<i class="bi bi-envelope me-2"></i>Ny email';
            }

            if (toInput && !toInput.value.trim()) {
                const recipient = getDefaultCaseRecipient();
                if (recipient) {
                    toInput.value = recipient;
                }
            }

            if (subjectInput && !subjectInput.value.trim()) {
                const title = (currentCaseTitle || '').trim() || 'EMNE PÅ SAGEN';
                subjectInput.value = escapeHtmlForInput(`(Sag:${caseIds}) - "${title}"`);
            }
        }

        function startNewEmailThread() {
            // Clear all compose fields and thread references
            selectedLinkedEmailId = null;
            isNewThread = true;
            const toInput = document.getElementById('caseEmailTo');
            const ccInput = document.getElementById('caseEmailCc');
            const bccInput = document.getElementById('caseEmailBcc');
            const subjectInput = document.getElementById('caseEmailSubject');
            const bodyInput = document.getElementById('caseEmailBody');
            if (toInput) toInput.value = '';
            if (ccInput) ccInput.value = '';
            if (bccInput) bccInput.value = '';
            if (subjectInput) subjectInput.value = '';
            if (bodyInput) bodyInput.value = '';
            const composeModalEl = document.getElementById('caseEmailComposeModal');
            if (composeModalEl) {
                bootstrap.Modal.getOrCreateInstance(composeModalEl).show();
            }
        }

        function openReplyToLinkedEmail() {
            const composeModalEl = document.getElementById('caseEmailComposeModal');
            if (!composeModalEl || !selectedLinkedEmailId || !selectedLinkedEmailDetail) {
                return;
            }
            isNewThread = false;  // This is a reply, not a new thread

            const toInput = document.getElementById('caseEmailTo');
            const subjectInput = document.getElementById('caseEmailSubject');
            const bodyInput = document.getElementById('caseEmailBody');

            const senderEmail = (selectedLinkedEmailDetail.sender_email || '').trim();
            const originalSubject = (selectedLinkedEmailDetail.subject || '').trim();

            if (toInput && !toInput.value.trim() && senderEmail) {
                toInput.value = senderEmail;
            }

            if (subjectInput && !subjectInput.value.trim()) {
                const replySubject = /^re:\s*/i.test(originalSubject)
                    ? originalSubject
                    : `Re: ${originalSubject || `Sag #${caseIds}`}`;
                subjectInput.value = escapeHtmlForInput(replySubject);
            }

            if (bodyInput && !bodyInput.value.trim()) {
                const received = selectedLinkedEmailDetail.received_date
                    ? new Date(selectedLinkedEmailDetail.received_date).toLocaleString('da-DK')
                    : '-';
                const senderName = selectedLinkedEmailDetail.sender_name || senderEmail || 'Ukendt';
                bodyInput.value = `\n\n---\nFra: ${senderName}\nDato: ${received}\nEmne: ${originalSubject || '(Ingen emne)'}\n`;
            }

            bootstrap.Modal.getOrCreateInstance(composeModalEl).show();
        }

        async function sendCaseEmail() {
            const toInput = document.getElementById('caseEmailTo');
            const ccInput = document.getElementById('caseEmailCc');
            const bccInput = document.getElementById('caseEmailBcc');
            const subjectInput = document.getElementById('caseEmailSubject');
            const bodyInput = document.getElementById('caseEmailBody');
            const attachmentSelect = document.getElementById('caseEmailAttachmentIds');
            const sendBtn = document.getElementById('caseEmailSendBtn');
            const statusEl = document.getElementById('caseEmailSendStatus');

            if (!toInput || !subjectInput || !bodyInput || !sendBtn || !statusEl) {
                return;
            }

            const to = parseEmailField(toInput.value);
            const cc = parseEmailField(ccInput?.value || '');
            const bcc = parseEmailField(bccInput?.value || '');
            const subject = (subjectInput.value || '').trim();
            const bodyText = (bodyInput.value || '').trim();
            const attachmentFileIds = Array.from(attachmentSelect?.selectedOptions || [])
                .map((opt) => Number(opt.value))
                .filter((id) => Number.isInteger(id) && id > 0);

            if (!to.length) {
                alert('Udfyld mindst én modtager i Til-feltet.');
                return;
            }

            if (!subject) {
                alert('Udfyld emne før afsendelse.');
                return;
            }

            if (!bodyText) {
                alert('Udfyld besked før afsendelse.');
                return;
            }

            sendBtn.disabled = true;
            statusEl.className = 'text-muted';
            statusEl.textContent = 'Sender e-mail...';

            try {
                const res = await fetch(`/api/v1/sag/${caseIds}/emails/send`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({
                        to,
                        cc,
                        bcc,
                        subject,
                        body_text: bodyText,
                        attachment_file_ids: attachmentFileIds,
                        thread_email_id: isNewThread ? null : (selectedLinkedEmailId || null),
                        thread_key: isNewThread ? null : (
                            linkedEmailsCache.find((entry) => Number(entry.id) === Number(selectedLinkedEmailId))?.resolved_thread_key
                            || linkedEmailsCache.find((entry) => Number(entry.id) === Number(selectedLinkedEmailId))?.thread_key
                            || null
                        )
                    })
                });

                if (!res.ok) {
                    let message = `HTTP ${res.status} ${res.statusText || 'Send failed'}`;
                    try {
                        const responseText = await res.text();
                        if (responseText) {
                            try {
                                const err = JSON.parse(responseText);
                                if (err?.detail) {
                                    message = err.detail;
                                } else if (err?.message) {
                                    message = err.message;
                                }
                            } catch (_) {
                                message = responseText.slice(0, 500);
                            }
                        }
                    } catch (_) {
                    }
                    throw new Error(message);
                }

                if (subjectInput) subjectInput.value = '';
                if (bodyInput) bodyInput.value = '';
                if (ccInput) ccInput.value = '';
                if (bccInput) bccInput.value = '';
                if (attachmentSelect) {
                    Array.from(attachmentSelect.options).forEach((option) => {
                        option.selected = false;
                    });
                }

                statusEl.className = 'text-success';
                statusEl.textContent = 'E-mail sendt.';
                isNewThread = false;  // Reset after send
                loadLinkedEmails();

                const composeModalEl = document.getElementById('caseEmailComposeModal');
                const composeModal = composeModalEl ? bootstrap.Modal.getInstance(composeModalEl) : null;
                if (composeModal) {
                    composeModal.hide();
                }
            } catch (error) {
                statusEl.className = 'text-danger';
                statusEl.textContent = error?.message || 'Email send failed (ukendt fejl)';
            } finally {
                sendBtn.disabled = false;
            }
        }

        function openCaseEmailTab() {
            const trigger = document.getElementById('emails-tab');
            if (!trigger) return;
            forceCaseTabActivation('emails');
        }

        window.quickReplyToEmailFromComment = async function(emailId) {
            const parsedId = Number(emailId);
            if (!Number.isFinite(parsedId)) return;

            openCaseEmailTab();

            try {
                await loadLinkedEmails();
                await loadLinkedEmailDetail(parsedId);
                openReplyToLinkedEmail();
            } catch (error) {
                console.error('Kunne ikke starte quick svar fra kommentar:', error);
            }
        }

        async function loadLinkedEmails() {
            const container = document.getElementById('linked-emails-list');
            const threadContainer = document.getElementById('email-threads-list');
            if (!container || !threadContainer) return;
            
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}/email-links`);
                if(res.ok) {
                    linkedEmailsCache = await res.json();
                    updateEmailTabUnreadBadge();
                    await applyLinkedEmailFilters(true);
                } else {
                    container.innerHTML = '<div class="p-3 text-center text-danger">Fejl ved hentning af emails</div>';
                    threadContainer.innerHTML = '<div class="p-3 text-center text-danger">Fejl ved hentning af tråde</div>';
                    updateEmailTabUnreadBadge();
                    setModuleContentState('emails', true);
                }
            } catch(e) {
                console.error(e);
                container.innerHTML = '<div class="p-3 text-center text-danger">Fejl ved hentning af emails</div>';
                threadContainer.innerHTML = '<div class="p-3 text-center text-danger">Fejl ved hentning af tråde</div>';
                updateEmailTabUnreadBadge();
                setModuleContentState('emails', true);
            }
        }

        function updateEmailTabUnreadBadge() {
            const badge = document.getElementById('emailTabUnreadBadge');
            if (!badge) return;

            const unreadItems = (linkedEmailsCache || []).filter((mail) => !Boolean(mail?.is_read));
            if (!unreadItems.length) {
                badge.style.display = 'none';
                badge.textContent = '';
                badge.classList.remove('is-warm', 'is-hot');
                return;
            }

            const now = Date.now();
            const oldestUnreadMs = unreadItems.reduce((oldest, item) => {
                const ts = item?.received_date ? new Date(item.received_date).getTime() : now;
                return Math.min(oldest, Number.isFinite(ts) ? ts : now);
            }, now);

            const ageHours = Math.max(0, (now - oldestUnreadMs) / (1000 * 60 * 60));
            badge.classList.remove('is-warm', 'is-hot');
            if (ageHours >= 72) {
                badge.classList.add('is-hot');
            } else if (ageHours >= 24) {
                badge.classList.add('is-warm');
            }

            badge.style.display = 'inline-block';
            badge.textContent = unreadItems.length > 99 ? '99+' : String(unreadItems.length);
            badge.title = ageHours >= 72
                ? 'Ulæste mails (ældre end 72 timer)'
                : (ageHours >= 24 ? 'Ulæste mails (ældre end 24 timer)' : 'Ulæste mails');
        }

        function getFilteredLinkedEmails() {
            const textFilter = (document.getElementById('emailFilterInput')?.value || '').trim().toLowerCase();
            const attachmentFilter = document.getElementById('emailAttachmentFilter')?.value || 'all';
            const readFilter = document.getElementById('emailReadFilter')?.value || 'all';

            return linkedEmailsCache.filter((email) => {
                if (textFilter) {
                    const haystack = [
                        email.subject,
                        email.sender_email,
                        email.sender_name,
                        email.body_text,
                        email.body_html
                    ].join(' ').toLowerCase();
                    if (!haystack.includes(textFilter)) return false;
                }

                const hasAttachments = Boolean(email.has_attachments) || Number(email.attachment_count || 0) > 0;
                if (attachmentFilter === 'with' && !hasAttachments) return false;
                if (attachmentFilter === 'without' && hasAttachments) return false;

                const isRead = Boolean(email.is_read);
                if (readFilter === 'read' && !isRead) return false;
                if (readFilter === 'unread' && isRead) return false;

                return true;
            });
        }

        function _normalizeThreadToken(value) {
            if (!value) return '';
            return String(value)
                .trim()
                .replace(/[<>]/g, '')
                .replace(/\s+/g, '')
                .toLowerCase();
        }

        function _extractFirstThreadToken(value) {
            if (!value) return '';
            const first = String(value).trim().split(/[\s,]+/)[0] || '';
            return _normalizeThreadToken(first);
        }

        function _normalizeThreadSubject(value) {
            if (!value) return '';
            return String(value)
                .toLowerCase()
                .replace(/^(?:(?:re|fw|fwd|sv|aw)\s*:\s*)+/i, '')
                .replace(/\s+/g, ' ')
                .trim();
        }

        function getThreadKey(email) {
            const resolved = _normalizeThreadToken(email?.resolved_thread_key);
            if (resolved && !resolved.startsWith('email-')) return resolved;

            const direct = _normalizeThreadToken(email?.thread_key);
            if (direct && !direct.startsWith('email-')) return direct;

            const replyTo = _extractFirstThreadToken(email?.in_reply_to);
            if (replyTo) return replyTo;

            const refs = _extractFirstThreadToken(email?.email_references);
            if (refs) return refs;

            const normalizedSubject = _normalizeThreadSubject(email?.subject);
            if (normalizedSubject) return `subject:${normalizedSubject}`;

            const messageId = _normalizeThreadToken(email?.message_id);
            if (messageId) return messageId;

            return `email-${email?.id || 'unknown'}`;
        }

        function isOutgoingEmail(email) {
            if (typeof email?.is_outgoing === 'boolean') {
                return email.is_outgoing;
            }
            const folder = (email?.folder || '').toString().toLowerCase();
            const status = (email?.status || '').toString().toLowerCase();
            return folder.startsWith('sent') || status === 'sent';
        }

        function buildThreadGroups(emails) {
            const map = new Map();

            emails.forEach((email) => {
                const threadKey = getThreadKey(email);
                const existing = map.get(threadKey);
                const receivedDateMs = email.received_date ? new Date(email.received_date).getTime() : 0;

                if (!existing) {
                    map.set(threadKey, {
                        threadKey,
                        lastDateMs: receivedDateMs,
                        latestEmail: email,
                        emails: [email]
                    });
                    return;
                }

                existing.emails.push(email);
                if (receivedDateMs > existing.lastDateMs) {
                    existing.lastDateMs = receivedDateMs;
                    existing.latestEmail = email;
                }
            });

            return Array.from(map.values())
                .map((group) => {
                    group.emails.sort((a, b) => {
                        const aDate = a.received_date ? new Date(a.received_date).getTime() : 0;
                        const bDate = b.received_date ? new Date(b.received_date).getTime() : 0;
                        return bDate - aDate;
                    });
                    return group;
                })
                .sort((a, b) => b.lastDateMs - a.lastDateMs);
        }

        function getCurrentThreadEmails() {
            if (!selectedEmailThreadKey) return [];
            return filteredLinkedEmailsCache
                .filter((email) => getThreadKey(email) === selectedEmailThreadKey)
                .sort((a, b) => {
                    const aDate = a.received_date ? new Date(a.received_date).getTime() : 0;
                    const bDate = b.received_date ? new Date(b.received_date).getTime() : 0;
                    return bDate - aDate;
                });
        }

        function renderEmailThreads(threadGroups) {
            const container = document.getElementById('email-threads-list');
            if (!container) return;

            if (!threadGroups.length) {
                container.innerHTML = '<div class="p-3 text-center text-muted">Ingen tråde fundet...</div>';
                const counter = document.getElementById('linkedEmailThreadsCount');
                if (counter) counter.textContent = '0';
                return;
            }

            const counter = document.getElementById('linkedEmailThreadsCount');
            if (counter) counter.textContent = String(threadGroups.length);

            const getThreadParticipants = (group) => {
                const participants = [];
                const seen = new Set();

                (group.emails || []).forEach((mail) => {
                    const sender = (mail.sender_name || mail.sender_email || '').trim();
                    if (sender && !seen.has(sender.toLowerCase())) {
                        participants.push(sender);
                        seen.add(sender.toLowerCase());
                    }

                    if (isOutgoingEmail(mail)) {
                        const recipients = String(mail.recipient_email || '')
                            .split(',')
                            .map((item) => item.trim())
                            .filter(Boolean);
                        recipients.forEach((recipient) => {
                            const key = recipient.toLowerCase();
                            if (!seen.has(key)) {
                                participants.push(recipient);
                                seen.add(key);
                            }
                        });
                    }
                });

                if (!participants.length) return 'Deltagere: -';
                const visible = participants.slice(0, 3);
                const extra = participants.length - visible.length;
                return `Deltagere: ${visible.join(', ')}${extra > 0 ? ` +${extra}` : ''}`;
            };

            container.innerHTML = threadGroups.map((group) => {
                const latest = group.latestEmail || {};
                const isSelected = selectedEmailThreadKey === group.threadKey;
                const receivedDate = latest.received_date ? new Date(latest.received_date).toLocaleString('da-DK') : '-';
                const sender = latest.sender_name || latest.sender_email || '-';
                const subject = latest.subject || '(Ingen emne)';
                const unreadCount = group.emails.filter((item) => !item.is_read).length;
                const participantsLabel = getThreadParticipants(group);

                return `
                <button type="button" class="email-thread-item list-group-item list-group-item-action border-0 border-bottom text-start ${isSelected ? 'active' : ''}" onclick='selectEmailThread(${JSON.stringify(group.threadKey)})'>
                    <div class="d-flex justify-content-between align-items-start gap-2">
                        <div class="flex-grow-1 overflow-hidden">
                            <div class="fw-semibold text-truncate">${escapeHtml(subject)}</div>
                            <div class="small ${isSelected ? 'text-white-50' : 'text-muted'} text-truncate">${escapeHtml(sender)}</div>
                            <div class="participants-line text-truncate">${escapeHtml(participantsLabel)}</div>
                            <div class="small ${isSelected ? 'text-white-50' : 'text-muted'} text-truncate">${escapeHtml(receivedDate)}</div>
                        </div>
                        <div class="d-flex flex-column align-items-end gap-1">
                            <span class="badge ${isSelected ? 'bg-light text-dark' : 'bg-secondary'}">${group.emails.length}</span>
                            ${unreadCount > 0 ? `<span class="badge bg-warning text-dark">${unreadCount} ulæst</span>` : ''}
                        </div>
                    </div>
                </button>
                `;
            }).join('');
        }

        function selectEmailThread(threadKey) {
            selectedEmailThreadKey = String(threadKey || '');

            const threadGroups = buildThreadGroups(filteredLinkedEmailsCache);
            renderEmailThreads(threadGroups);

            const threadEmails = getCurrentThreadEmails();
            renderLinkedEmails(threadEmails);

            if (!threadEmails.length) {
                selectedLinkedEmailId = null;
                renderEmailPreviewEmpty();
                return;
            }

            const hasCurrentSelected = threadEmails.some((item) => Number(item.id) === Number(selectedLinkedEmailId));
            if (!hasCurrentSelected) {
                selectedLinkedEmailId = Number(threadEmails[0].id);
            }

            loadLinkedEmailDetail(selectedLinkedEmailId, true);
        }

        async function applyLinkedEmailFilters(loadDetail = false) {
            filteredLinkedEmailsCache = getFilteredLinkedEmails();
            updateEmailTabUnreadBadge();
            const threadGroups = buildThreadGroups(filteredLinkedEmailsCache);

            renderEmailThreads(threadGroups);

            if (!threadGroups.length) {
                selectedEmailThreadKey = null;
                selectedLinkedEmailId = null;
                renderLinkedEmails([]);
                const threadCounter = document.getElementById('threadEmailsCount');
                if (threadCounter) threadCounter.textContent = '0';
                renderEmailPreviewEmpty();
                setModuleContentState('emails', false);
                return;
            }

            const selectedThreadExists = threadGroups.some((group) => group.threadKey === selectedEmailThreadKey);
            if (!selectedThreadExists) {
                selectedEmailThreadKey = threadGroups[0].threadKey;
            }

            const threadEmails = getCurrentThreadEmails();
            renderLinkedEmails(threadEmails);

            const threadCounter = document.getElementById('threadEmailsCount');
            if (threadCounter) threadCounter.textContent = String(threadEmails.length);

            if (!threadEmails.length) {
                selectedLinkedEmailId = null;
                renderEmailPreviewEmpty();
                return;
            }

            const selectedEmailExists = threadEmails.some((item) => Number(item.id) === Number(selectedLinkedEmailId));
            if (!selectedEmailExists) {
                selectedLinkedEmailId = Number(threadEmails[0].id);
            }

            if (loadDetail && selectedLinkedEmailId) {
                await loadLinkedEmailDetail(selectedLinkedEmailId, true);
            }

            setModuleContentState('emails', true);
        }

        function renderLinkedEmails(emails) {
            const container = document.getElementById('linked-emails-list');
            if (!container) return;
            if(!emails || emails.length === 0) {
                container.innerHTML = '<div class="p-3 text-center text-muted">Ingen linkede e-mails...</div>';
                return;
            }

            container.innerHTML = emails.map(e => {
                const isSelected = Number(selectedLinkedEmailId) === Number(e.id);
                const receivedDate = e.received_date ? new Date(e.received_date).toLocaleString('da-DK') : '-';
                const sender = e.sender_name || e.sender_email || '-';
                const subject = e.subject || '(Ingen emne)';
                const isOutgoing = isOutgoingEmail(e);
                const snippetSource = e.body_text || e.body_html || '';
                const snippet = snippetSource.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 130);
                const hasAttachments = Boolean(e.has_attachments) || Number(e.attachment_count || 0) > 0;

                return `
                <button type="button" class="list-group-item list-group-item-action border-0 border-bottom text-start ${isSelected ? 'active' : ''}" onclick="loadLinkedEmailDetail(${e.id})">
                    <div class="d-flex justify-content-between align-items-start gap-2">
                        <div class="flex-grow-1 overflow-hidden">
                            <div class="fw-semibold text-truncate">${escapeHtml(subject)}</div>
                            <div class="small ${isSelected ? 'text-white-50' : 'text-muted'} text-truncate">${escapeHtml(sender)}</div>
                            <div class="small mt-1">${isOutgoing
                                ? '<span class="badge bg-primary-subtle text-primary-emphasis">Udgående</span>'
                                : '<span class="badge bg-success-subtle text-success-emphasis">Indgående</span>'
                            }</div>
                            <div class="small ${isSelected ? 'text-white-50' : 'text-muted'} text-truncate">${escapeHtml(snippet || 'Ingen preview')}</div>
                        </div>
                        <div class="d-flex flex-column align-items-end gap-1">
                            <div class="small ${isSelected ? 'text-white-50' : 'text-muted'}">${escapeHtml(receivedDate)}</div>
                            ${hasAttachments ? '<span class="badge bg-info-subtle text-info-emphasis">📎</span>' : ''}
                            ${!e.is_read ? '<span class="badge bg-warning text-dark">Ulæst</span>' : ''}
                            <span class="btn btn-sm btn-link p-0 ${isSelected ? 'text-white' : 'text-danger'}" onclick="event.stopPropagation(); unlinkEmail(${e.id});" title="Fjern link">
                                <i class="bi bi-link-45deg" style="text-decoration: line-through;"></i>
                            </span>
                        </div>
                    </div>
                </button>
                `;
            }).join('');
        }

        function renderEmailPreviewEmpty() {
            const panel = document.getElementById('email-preview-panel');
            if (!panel) return;
            selectedLinkedEmailDetail = null;
            panel.innerHTML = `
                <div class="p-3 text-center text-muted d-flex align-items-center justify-content-center flex-grow-1">
                    Vælg en e-mail i listen for at se indhold og vedhæftninger
                </div>
            `;
        }

        async function loadLinkedEmailDetail(emailId, skipRefresh = false) {
            selectedLinkedEmailId = Number(emailId);
            const panel = document.getElementById('email-preview-panel');
            if (!panel) return;

            panel.innerHTML = `
                <div class="p-4 text-center text-muted">
                    <div class="spinner-border spinner-border-sm me-2" role="status"></div>
                    Henter e-mail...
                </div>
            `;

            if (!skipRefresh) {
                const threadEmails = getCurrentThreadEmails();
                renderLinkedEmails(threadEmails);
            }

            try {
                const res = await fetch(`/api/v1/emails/${emailId}`);
                if (!res.ok) {
                    panel.innerHTML = '<div class="p-3 text-danger">Kunne ikke hente e-mail detaljer.</div>';
                    return;
                }

                const email = await res.json();
                const subject = email.subject || '(Ingen emne)';
                const sender = email.sender_name || email.sender_email || '-';
                const received = email.received_date ? new Date(email.received_date).toLocaleString('da-DK') : '-';
                const attachments = Array.isArray(email.attachments) ? email.attachments : [];
                const bodyText = email.body_text || '';
                const bodyHtml = email.body_html || '';
                selectedLinkedEmailDetail = email;

                panel.innerHTML = `
                    <div class="border-bottom p-3">
                        <div class="fw-bold mb-1">${escapeHtml(subject)}</div>
                        <div class="small text-muted">Fra: ${escapeHtml(sender)}</div>
                        <div class="small text-muted">Dato: ${escapeHtml(received)}</div>
                        <div class="mt-2 d-flex gap-2">
                            <button type="button" class="btn btn-sm btn-primary" onclick="openReplyToLinkedEmail()">
                                <i class="bi bi-reply me-1"></i>Svar i tråd
                            </button>
                            <button type="button" class="btn btn-sm ${email.is_read ? 'btn-outline-secondary' : 'btn-warning'}" id="emailReadToggleBtn" onclick="toggleLinkedEmailReadState()">
                                <i class="bi ${email.is_read ? 'bi-envelope-open' : 'bi-envelope'} me-1"></i>
                                ${email.is_read ? 'Marker som ulæst' : 'Marker som læst'}
                            </button>
                            <span class="badge ${email.is_read ? 'bg-success-subtle text-success-emphasis' : 'bg-warning text-dark'} mail-read-chip align-self-center" id="emailReadStateBadge">
                                ${email.is_read ? 'Læst' : 'Ulæst'}
                            </span>
                        </div>
                    </div>
                    <div class="p-3 border-bottom">
                        <div class="small fw-semibold mb-2">Vedhæftninger (${attachments.length})</div>
                        <div id="email-attachments-list" class="d-flex flex-wrap gap-2"></div>
                    </div>
                    <div class="p-3 overflow-auto" style="max-height: 45vh; white-space: normal;">
                        ${bodyText ? `<pre class="mb-0" style="white-space: pre-wrap; font-family: inherit;">${escapeHtml(bodyText)}</pre>` : (bodyHtml ? bodyHtml : '<div class="text-muted">Ingen indhold</div>')}
                    </div>
                `;

                const attachmentContainer = document.getElementById('email-attachments-list');
                if (attachmentContainer) {
                    if (!attachments.length) {
                        attachmentContainer.innerHTML = '<span class="text-muted small">Ingen vedhæftninger</span>';
                    } else {
                        attachmentContainer.innerHTML = attachments.map(att => {
                            const attachmentName = att.filename || `Vedhæftning ${att.id}`;
                            const url = `/api/v1/emails/${email.id}/attachments/${att.id}`;
                            return `<a class="btn btn-sm btn-outline-secondary" href="${url}"><i class="bi bi-download me-1"></i>${escapeHtml(attachmentName)}</a>`;
                        }).join('');
                    }
                }

                const cacheIdx = linkedEmailsCache.findIndex((item) => Number(item.id) === Number(email.id));
                if (cacheIdx >= 0) {
                    linkedEmailsCache[cacheIdx].is_read = Boolean(email.is_read);
                }

                const filteredIdx = filteredLinkedEmailsCache.findIndex((item) => Number(item.id) === Number(email.id));
                if (filteredIdx >= 0) {
                    filteredLinkedEmailsCache[filteredIdx].is_read = Boolean(email.is_read);
                }

                updateEmailTabUnreadBadge();

                if (!skipRefresh) {
                    const threadEmails = getCurrentThreadEmails();
                    renderLinkedEmails(threadEmails);
                    renderEmailThreads(buildThreadGroups(filteredLinkedEmailsCache));
                }
            } catch (e) {
                console.error(e);
                selectedLinkedEmailDetail = null;
                panel.innerHTML = '<div class="p-3 text-danger">Fejl ved hentning af e-mail detaljer.</div>';
            }
        }

        async function toggleLinkedEmailReadState() {
            if (!selectedLinkedEmailDetail || !selectedLinkedEmailId) return;
            const targetState = !Boolean(selectedLinkedEmailDetail.is_read);

            try {
                const res = await fetch(`/api/v1/emails/${selectedLinkedEmailId}/read-state`, {
                    method: 'PATCH',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ is_read: targetState })
                });

                if (!res.ok) {
                    let detail = `Kunne ikke opdatere læsestatus (${res.status})`;
                    try {
                        const payload = await res.json();
                        if (payload?.detail) detail = payload.detail;
                    } catch (_) {
                    }
                    alert(detail);
                    return;
                }

                selectedLinkedEmailDetail.is_read = targetState;

                const updateCollection = (items) => {
                    const idx = items.findIndex((entry) => Number(entry.id) === Number(selectedLinkedEmailId));
                    if (idx >= 0) {
                        items[idx].is_read = targetState;
                    }
                };

                updateCollection(linkedEmailsCache);
                updateCollection(filteredLinkedEmailsCache);
                updateEmailTabUnreadBadge();

                const threadEmails = getCurrentThreadEmails();
                renderLinkedEmails(threadEmails);
                renderEmailThreads(buildThreadGroups(filteredLinkedEmailsCache));

                const toggleBtn = document.getElementById('emailReadToggleBtn');
                if (toggleBtn) {
                    toggleBtn.className = `btn btn-sm ${targetState ? 'btn-outline-secondary' : 'btn-warning'}`;
                    toggleBtn.innerHTML = `<i class="bi ${targetState ? 'bi-envelope-open' : 'bi-envelope'} me-1"></i>${targetState ? 'Marker som ulæst' : 'Marker som læst'}`;
                }

                const badge = document.getElementById('emailReadStateBadge');
                if (badge) {
                    badge.className = `badge ${targetState ? 'bg-success-subtle text-success-emphasis' : 'bg-warning text-dark'} mail-read-chip align-self-center`;
                    badge.textContent = targetState ? 'Læst' : 'Ulæst';
                }
            } catch (error) {
                console.error(error);
                alert('Fejl ved opdatering af læsestatus.');
            }
        }
        
        async function unlinkEmail(emailId) {
            if(!confirm("Fjern link til denne email?")) return;
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}/email-links/${emailId}`, { method: 'DELETE' });
                if(res.ok) {
                    if (Number(selectedLinkedEmailId) === Number(emailId)) {
                        selectedLinkedEmailId = null;
                        renderEmailPreviewEmpty();
                    }
                    loadLinkedEmails();
                }
            } catch(e) { alert(e); }
        }

        // Email Search
        const emailSearchInput = document.getElementById('emailSearchInput');
        const emailSearchResults = document.getElementById('emailSearchResults');
        let emailDebounce = null;

        if(emailSearchInput) {
            emailSearchInput.addEventListener('input', e => {
                clearTimeout(emailDebounce);
                const q = e.target.value.trim();
                if(q.length < 2) {
                    emailSearchResults.style.display = 'none'; 
                    return; 
                }
                emailDebounce = setTimeout(() => searchEmails(q), 300);
            });
            
            // Hide on outside click
            document.addEventListener('click', e => {
                if(!emailSearchInput.contains(e.target) && !emailSearchResults.contains(e.target)) {
                    emailSearchResults.style.display = 'none';
                }
            });
        }

        ['emailFilterInput', 'emailAttachmentFilter', 'emailReadFilter'].forEach((id) => {
            const el = document.getElementById(id);
            if (!el) return;
            const eventName = id === 'emailFilterInput' ? 'input' : 'change';
            el.addEventListener(eventName, () => {
                applyLinkedEmailFilters(true);
            });
        });

        async function searchEmails(query) {
            try {
                const res = await fetch(`/api/v1/emails?q=${encodeURIComponent(query)}&limit=5`);
                if(res.ok) {
                    const emails = await res.json();
                    renderEmailSuggestions(emails);
                    emailSearchResults.style.display = 'block';
                }
            } catch(e) { console.error(e); }
        }

        function renderEmailSuggestions(emails) {
             if(!emails.length) {
                 emailSearchResults.innerHTML = '<div class="list-group-item text-muted">Ingen fundet</div>';
                 return;
             }
             emailSearchResults.innerHTML = emails.map(e => `
                 <button class="list-group-item list-group-item-action" onclick="linkEmail(${e.id})">
                     <div class="fw-bold text-truncate">${e.subject}</div>
                     <div class="small text-muted">${e.sender_email}</div>
                 </button>
             `).join('');
        }

        async function linkEmail(emailId) {
             emailSearchInput.value = '';
             emailSearchResults.style.display = 'none';
             try {
                 const res = await fetch(`/api/v1/sag/${caseIds}/email-links`, {
                     method: 'POST',
                     headers: {'Content-Type': 'application/json'},
                     body: JSON.stringify({email_id: emailId})
                 });
                 if(res.ok) loadLinkedEmails();
                 else alert("Kunne ikke linke email");
             } catch(e) { alert(e); }
        }

        // Email Import Drag & Drop (.msg / .eml)
        const emailDropZone = document.getElementById('emailDropZone');
        if(emailDropZone) {
            emailDropZone.addEventListener('dragover', e => { e.preventDefault(); emailDropZone.classList.add('bg-warning-subtle'); });
            emailDropZone.addEventListener('dragleave', e => { e.preventDefault(); emailDropZone.classList.remove('bg-warning-subtle'); });
            emailDropZone.addEventListener('drop', e => {
                e.preventDefault();
                emailDropZone.classList.remove('bg-warning-subtle');
                const files = e.dataTransfer.files;
                if(files.length) uploadEmailFile(files[0]);
            });
        }
        
        async function uploadEmailFile(file) {
            if (!file) return;
            const lowerName = String(file.name || '').toLowerCase();
            if (!(lowerName.endsWith('.eml') || lowerName.endsWith('.msg'))) {
                alert('Kun .eml og .msg filer understøttes');
                return;
            }

            const formData = new FormData();
            formData.append('file', file);
            
            // Show busy indicator
            emailDropZone.style.opacity = '0.5';
            
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}/upload-email`, {
                    method: 'POST',
                    body: formData
                });
                if(res.ok) {
                    loadLinkedEmails();
                } else {
                    alert('Import fejlede');
                }
            } catch(e) { alert(e); }
            finally {
                emailDropZone.style.opacity = '1';
            }
        }

        // Load content on start
        document.addEventListener('DOMContentLoaded', () => {
            const caseEmailSendBtn = document.getElementById('caseEmailSendBtn');
            if (caseEmailSendBtn) {
                caseEmailSendBtn.addEventListener('click', sendCaseEmail);
            }

            const caseEmailRewriteBtn = document.getElementById('caseEmailRewriteBtn');
            if (caseEmailRewriteBtn) {
                caseEmailRewriteBtn.addEventListener('click', rewriteCaseEmailWithApproval);
            }

            const rewriteApplyAllBtn = document.getElementById('rewriteApplyAllBtn');
            if (rewriteApplyAllBtn) {
                rewriteApplyAllBtn.addEventListener('click', () => applyRewriteChanges('all'));
            }

            const rewriteApplySelectedBtn = document.getElementById('rewriteApplySelectedBtn');
            if (rewriteApplySelectedBtn) {
                rewriteApplySelectedBtn.addEventListener('click', () => applyRewriteChanges('selected'));
            }

            const caseEmailComposeModal = document.getElementById('caseEmailComposeModal');
            if (caseEmailComposeModal) {
                caseEmailComposeModal.addEventListener('show.bs.modal', () => {
                    const statusEl = document.getElementById('caseEmailSendStatus');
                    if (statusEl) {
                        statusEl.className = 'text-muted';
                        statusEl.textContent = '';
                    }
                    prefillCaseEmailCompose();
                    updateCaseEmailAttachmentOptions(sagFilesCache);
                });
            }

            prefillCaseEmailCompose();
            updateCaseEmailAttachmentOptions(sagFilesCache);
            loadSagFiles();
            loadLinkedEmails();
        });

    </script>

    <script>
        const subscriptionCaseId = {{ case.id }};
        let currentSubscription = null;
        let subscriptionProducts = [];
        let lastCreatedSubscriptionProductId = null;

        function formatSubscriptionInterval(interval) {
            const map = {
                'daily': 'Daglig',
                'biweekly': '14-dage',
                'monthly': 'Maaned',
                'quarterly': 'Kvartal',
                'yearly': 'Aar'
            };
            return map[interval] || interval || '-';
        }

        function formatSubscriptionCurrency(amount) {
            return new Intl.NumberFormat('da-DK', {
                style: 'currency',
                currency: 'DKK',
                minimumFractionDigits: 0,
                maximumFractionDigits: 0
            }).format(amount || 0);
        }

        function formatSubscriptionDate(dateStr) {
            if (!dateStr) return '-';
            const date = new Date(dateStr);
            return date.toLocaleDateString('da-DK');
        }

        function setSubscriptionBadge(status) {
            const badge = document.getElementById('subscriptionStatusBadge');
            if (!badge) return;
            const classes = {
                'draft': 'bg-light text-dark',
                'active': 'bg-success',
                'paused': 'bg-warning',
                'cancelled': 'bg-secondary'
            };
            const label = {
                'draft': 'Kladde',
                'active': 'Aktiv',
                'paused': 'Pauset',
                'cancelled': 'Opsagt'
            };
            badge.className = `badge ${classes[status] || 'bg-light text-dark'}`;
            badge.textContent = label[status] || status || 'Ingen';
        }

        function showSubscriptionCreateForm() {
            const empty = document.getElementById('subscriptionEmpty');
            const form = document.getElementById('subscriptionCreateForm');
            const details = document.getElementById('subscriptionDetails');
            if (empty) empty.classList.remove('d-none');
            if (form) form.classList.remove('d-none');
            if (details) details.classList.add('d-none');
            setSubscriptionBadge(null);

            const startDateInput = document.getElementById('subscriptionStartDateInput');
            if (startDateInput && !startDateInput.value) {
                startDateInput.value = new Date().toISOString().split('T')[0];
            }

            const body = document.getElementById('subscriptionLineItemsBody');
            if (body) {
                body.innerHTML = `
                    <tr>
                        <td>
                            <select class="form-select form-select-sm subscriptionProductSelect" onchange="applySubscriptionProduct(this)">
                                <option value="">Vælg produkt</option>
                            </select>
                        </td>
                        <td><input type="text" class="form-control form-control-sm" placeholder="Managed Backup"></td>
                        <td><input type="number" class="form-control form-control-sm" min="0.01" step="0.01" value="1" oninput="updateSubscriptionLineTotals()"></td>
                        <td><input type="number" class="form-control form-control-sm" min="0" step="0.01" value="0" oninput="updateSubscriptionLineTotals()"></td>
                        <td class="text-end"><span class="subscriptionLineTotal">0,00 kr</span></td>
                        <td class="text-end">
                            <button type="button" class="btn btn-sm btn-outline-danger" onclick="removeSubscriptionLine(this)"><i class="bi bi-x"></i></button>
                        </td>
                    </tr>
                `;
            }
            populateSubscriptionProductSelects();
            updateSubscriptionLineTotals();
        }

        function populateSubscriptionProductSelects() {
            const selects = document.querySelectorAll('.subscriptionProductSelect');
            selects.forEach(select => {
                const currentValue = select.value;
                select.innerHTML = '<option value="">Vælg produkt</option>';
                subscriptionProducts.forEach(product => {
                    const option = document.createElement('option');
                    option.value = product.id;
                    option.textContent = product.name;
                    option.dataset.salesPrice = product.sales_price ?? '';
                    option.dataset.description = product.short_description ?? '';
                    select.appendChild(option);
                });
                if (currentValue) {
                    select.value = currentValue;
                } else if (lastCreatedSubscriptionProductId) {
                    select.value = String(lastCreatedSubscriptionProductId);
                }
            });
            lastCreatedSubscriptionProductId = null;
        }

        function applySubscriptionProduct(select) {
            const row = select.closest('tr');
            if (!row) return;
            const descriptionInput = row.querySelector('input[type="text"]');
            const unitPriceInput = row.querySelectorAll('input[type="number"]')[1];
            const selected = select.options[select.selectedIndex];
            if (!selected) return;

            const description = selected.dataset.description || selected.textContent || '';
            const salesPrice = selected.dataset.salesPrice;

            if (descriptionInput && !descriptionInput.value.trim()) {
                descriptionInput.value = description;
            }
            if (unitPriceInput && salesPrice !== '') {
                unitPriceInput.value = salesPrice;
            }
            updateSubscriptionLineTotals();
        }

        function addSubscriptionLine() {
            const body = document.getElementById('subscriptionLineItemsBody');
            if (!body) return;
            const row = document.createElement('tr');
            row.innerHTML = `
                <td>
                    <select class="form-select form-select-sm subscriptionProductSelect" onchange="applySubscriptionProduct(this)">
                        <option value="">Vælg produkt</option>
                    </select>
                </td>
                <td><input type="text" class="form-control form-control-sm" placeholder="Beskrivelse"></td>
                <td><input type="number" class="form-control form-control-sm" min="0.01" step="0.01" value="1" oninput="updateSubscriptionLineTotals()"></td>
                <td><input type="number" class="form-control form-control-sm" min="0" step="0.01" value="0" oninput="updateSubscriptionLineTotals()"></td>
                <td class="text-end"><span class="subscriptionLineTotal">0,00 kr</span></td>
                <td class="text-end">
                    <button type="button" class="btn btn-sm btn-outline-danger" onclick="removeSubscriptionLine(this)"><i class="bi bi-x"></i></button>
                </td>
            `;
            body.appendChild(row);
            populateSubscriptionProductSelects();
            updateSubscriptionLineTotals();
        }

        function removeSubscriptionLine(button) {
            const row = button.closest('tr');
            const body = document.getElementById('subscriptionLineItemsBody');
            if (!row || !body) return;
            if (body.children.length <= 1) {
                row.querySelectorAll('input').forEach(input => {
                    input.value = input.type === 'number' ? 0 : '';
                });
            } else {
                row.remove();
            }
            updateSubscriptionLineTotals();
        }

        function updateSubscriptionLineTotals() {
            const body = document.getElementById('subscriptionLineItemsBody');
            const totalEl = document.getElementById('subscriptionLinesTotal');
            if (!body || !totalEl) return;

            let total = 0;
            Array.from(body.querySelectorAll('tr')).forEach(row => {
                const inputs = row.querySelectorAll('input');
                const description = inputs[0]?.value || '';
                const qty = parseFloat(inputs[1]?.value || 0);
                const unit = parseFloat(inputs[2]?.value || 0);
                const lineTotal = (qty > 0 ? qty : 0) * (unit > 0 ? unit : 0);
                total += lineTotal;
                const lineTotalEl = row.querySelector('.subscriptionLineTotal');
                if (lineTotalEl) {
                    lineTotalEl.textContent = formatSubscriptionCurrency(lineTotal);
                }
                if (!description && qty === 0 && unit === 0) {
                    if (lineTotalEl) {
                        lineTotalEl.textContent = formatSubscriptionCurrency(0);
                    }
                }
            });

            totalEl.textContent = formatSubscriptionCurrency(total);
        }

        function collectSubscriptionLineItems() {
            const body = document.getElementById('subscriptionLineItemsBody');
            if (!body) return [];
            const items = [];
            Array.from(body.querySelectorAll('tr')).forEach(row => {
                const productSelect = row.querySelector('.subscriptionProductSelect');
                const inputs = row.querySelectorAll('input');
                const description = (inputs[0]?.value || '').trim();
                const quantity = parseFloat(inputs[1]?.value || 0);
                const unitPrice = parseFloat(inputs[2]?.value || 0);
                if (!description && quantity === 0 && unitPrice === 0) {
                    return;
                }
                items.push({
                    product_id: productSelect && productSelect.value ? parseInt(productSelect.value, 10) : null,
                    description,
                    quantity,
                    unit_price: unitPrice
                });
            });
            return items;
        }

        async function loadSubscriptionProducts() {
            try {
                const res = await fetch('/api/v1/products');
                if (!res.ok) {
                    throw new Error('Kunne ikke hente produkter');
                }
                subscriptionProducts = await res.json();
            } catch (e) {
                console.error('Error loading products:', e);
                subscriptionProducts = [];
            }
            populateSubscriptionProductSelects();
        }

        function openSubscriptionProductModal() {
            const form = document.getElementById('subscriptionProductForm');
            if (form) form.reset();
            new bootstrap.Modal(document.getElementById('subscriptionProductModal')).show();
        }

        async function createSubscriptionProduct() {
            const payload = {
                name: document.getElementById('subscriptionProductName').value.trim(),
                type: document.getElementById('subscriptionProductType').value.trim() || null,
                status: document.getElementById('subscriptionProductStatus').value,
                sales_price: document.getElementById('subscriptionProductSalesPrice').value || null,
                billing_period: document.getElementById('subscriptionProductBillingPeriod').value || null,
                short_description: document.getElementById('subscriptionProductDescription').value.trim() || null
            };

            if (!payload.name) {
                alert('Navn er paakraevet');
                return;
            }

            const res = await fetch('/api/v1/products', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload)
            });

            if (!res.ok) {
                const error = await res.json();
                alert(error.detail || 'Kunne ikke oprette produkt');
                return;
            }

            const product = await res.json();
            lastCreatedSubscriptionProductId = product.id;
            bootstrap.Modal.getInstance(document.getElementById('subscriptionProductModal')).hide();
            await loadSubscriptionProducts();
            updateSubscriptionLineTotals();
        }

        function renderSubscription(subscription) {
            currentSubscription = subscription;
            const empty = document.getElementById('subscriptionEmpty');
            const form = document.getElementById('subscriptionCreateForm');
            const details = document.getElementById('subscriptionDetails');
            if (empty) empty.classList.add('d-none');
            if (form) form.classList.add('d-none');
            if (details) details.classList.remove('d-none');

            document.getElementById('subscriptionNumber').textContent = subscription.subscription_number || `#${subscription.id}`;
            document.getElementById('subscriptionProduct').textContent = subscription.product_name || '-';
            document.getElementById('subscriptionInterval').textContent = formatSubscriptionInterval(subscription.billing_interval);
            document.getElementById('subscriptionPrice').textContent = formatSubscriptionCurrency(subscription.price);
            document.getElementById('subscriptionStartDate').textContent = formatSubscriptionDate(subscription.start_date);
            document.getElementById('subscriptionStatusText').textContent = subscription.status || '-';
            
            // New fields
            const periodStartEl = document.getElementById('subscriptionPeriodStart');
            const nextInvoiceEl = document.getElementById('subscriptionNextInvoice');
            if (periodStartEl) {
                periodStartEl.textContent = subscription.period_start ? formatSubscriptionDate(subscription.period_start) : '-';
            }
            if (nextInvoiceEl) {
                const nextDate = subscription.next_invoice_date ? formatSubscriptionDate(subscription.next_invoice_date) : '-';
                nextInvoiceEl.textContent = nextDate;
                // Highlight if invoice is due soon
                if (subscription.next_invoice_date) {
                    const daysUntil = Math.ceil((new Date(subscription.next_invoice_date) - new Date()) / (1000 * 60 * 60 * 24));
                    if (daysUntil <= 7 && daysUntil >= 0) {
                        nextInvoiceEl.innerHTML = `${nextDate} <span class="badge bg-warning text-dark">Om ${daysUntil} dage</span>`;
                    }
                }
            }

            setSubscriptionBadge(subscription.status);

            const itemsBody = document.getElementById('subscriptionItemsBody');
            const itemsTotal = document.getElementById('subscriptionItemsTotal');
            if (itemsBody) {
                const items = subscription.line_items || [];
                if (!items.length) {
                    itemsBody.innerHTML = '<tr><td colspan="5" class="text-center text-muted">Ingen linjer</td></tr>';
                } else {
                    itemsBody.innerHTML = items.map(item => `
                        <tr>
                            <td>${item.product_name || '-'}</td>
                            <td>${item.description}</td>
                            <td class="text-end">${parseFloat(item.quantity).toFixed(2)}</td>
                            <td class="text-end">${formatSubscriptionCurrency(item.unit_price)}</td>
                            <td class="text-end">${formatSubscriptionCurrency(item.line_total)}</td>
                        </tr>
                    `).join('');
                }
            }
            if (itemsTotal) {
                itemsTotal.textContent = formatSubscriptionCurrency(subscription.price || 0);
            }

            const actions = document.getElementById('subscriptionActions');
            if (!actions) return;

            const buttons = [];
            if (subscription.status === 'draft' || subscription.status === 'paused') {
                buttons.push(`<button class="btn btn-sm btn-success" onclick="updateSubscriptionStatus('active')"><i class="bi bi-play-circle me-1"></i>Aktiver</button>`);
            }
            if (subscription.status === 'active') {
                buttons.push(`<button class="btn btn-sm btn-warning" onclick="updateSubscriptionStatus('paused')"><i class="bi bi-pause-circle me-1"></i>Pause</button>`);
            }
            if (subscription.status !== 'cancelled') {
                buttons.push(`<button class="btn btn-sm btn-outline-danger" onclick="updateSubscriptionStatus('cancelled')"><i class="bi bi-x-circle me-1"></i>Opsig</button>`);
            }
            actions.innerHTML = buttons.join(' ');
        }

        async function loadSubscriptionForCase() {
            try {
                const res = await fetch(`/api/v1/sag-subscriptions/by-sag/${subscriptionCaseId}?allow_missing=true`);
                if (res.status === 404) {
                    showSubscriptionCreateForm();
                    setModuleContentState('subscription', false);
                    return;
                }
                if (!res.ok) {
                    throw new Error('Kunne ikke hente abonnement');
                }
                const payload = await res.json();
                const subscription = payload && Object.prototype.hasOwnProperty.call(payload, 'subscription')
                    ? payload.subscription
                    : payload;
                if (!subscription || !subscription.id) {
                    showSubscriptionCreateForm();
                    setModuleContentState('subscription', false);
                    return;
                }
                renderSubscription(subscription);
                setModuleContentState('subscription', true);
            } catch (e) {
                console.error('Error loading subscription:', e);
                showSubscriptionCreateForm();
                setModuleContentState('subscription', true);
            }
        }

        async function createSubscription() {
            const billingInterval = document.getElementById('subscriptionIntervalInput').value;
            const billingDay = parseInt(document.getElementById('subscriptionBillingDayInput').value, 10);
            const startDate = document.getElementById('subscriptionStartDateInput').value;
            const notes = document.getElementById('subscriptionNotesInput').value.trim();

            const lineItems = collectSubscriptionLineItems();

            if (!billingInterval || !billingDay || !startDate) {
                alert('Udfyld venligst alle paakraevet felter');
                return;
            }
            if (!lineItems.length) {
                alert('Du skal angive mindst en varelinje');
                return;
            }

            try {
                const res = await fetch('/api/v1/sag-subscriptions', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        sag_id: subscriptionCaseId,
                        billing_interval: billingInterval,
                        billing_day: billingDay,
                        start_date: startDate,
                        notes: notes || null,
                        line_items: lineItems
                    })
                });

                if (!res.ok) {
                    const error = await res.json();
                    throw new Error(error.detail || 'Fejl ved oprettelse');
                }

                const subscription = await res.json();
                renderSubscription(subscription);
            } catch (e) {
                alert(e.message || e);
            }
        }

        async function updateSubscriptionStatus(status) {
            if (!currentSubscription) return;
            if (status === 'cancelled' && !confirm('Er du sikker paa, at abonnementet skal opsiges?')) {
                return;
            }

            try {
                const res = await fetch(`/api/v1/sag-subscriptions/${currentSubscription.id}/status`, {
                    method: 'PATCH',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ status })
                });

                if (!res.ok) {
                    const error = await res.json();
                    throw new Error(error.detail || 'Kunne ikke opdatere status');
                }

                const updated = await res.json();
                renderSubscription(updated);
            } catch (e) {
                alert(e.message || e);
            }
        }

        document.addEventListener('DOMContentLoaded', () => {
            loadSubscriptionProducts();
            loadSubscriptionForCase();
        });

        // === Quick Time Entry Functions (for inline time tracking) ===
        function toggleQuickTimeForm() {
            const container = document.getElementById('quickTimeFormContainer');
            if (container) {
                container.classList.remove('d-none');
            }
        }
        
        // Make function globally available for onclick handler
        window.toggleQuickTimeForm = toggleQuickTimeForm;

        async function quickAddTime(event) {
            event.preventDefault();
            
            const form = document.getElementById('quickAddTimeForm');
            const formData = new FormData(form);
            
            // Parse hours and minutes
            const hours = parseInt(formData.get('hours')) || 0;
            const minutes = parseInt(formData.get('minutes')) || 0;
            const totalHours = hours + (minutes / 60);
            
            if (totalHours === 0) {
                alert('Angiv venligst timer eller minutter');
                return;
            }

            const billingSelect = document.getElementById('quickTimeBillingMethod');
            let billingMethod = billingSelect ? billingSelect.value : 'invoice';
            let prepaidCardId = null;
            let fixedPriceAgreementId = null;

            if (billingMethod.startsWith('card_')) {
                prepaidCardId = parseInt(billingMethod.split('_')[1]);
                billingMethod = 'prepaid';
            }

            if (billingMethod.startsWith('fpa_')) {
                fixedPriceAgreementId = parseInt(billingMethod.split('_')[1]);
                billingMethod = 'fixed_price';
            }

            const isInternal = billingMethod === 'internal';
            
            // Build payload
            const payload = {
                sag_id: {{ case.id }},
                worked_date: formData.get('date'),
                original_hours: totalHours,
                description: formData.get('description'),
                billing_method: billingMethod,
                is_internal: isInternal
            };

            if (prepaidCardId) {
                payload.prepaid_card_id = prepaidCardId;
            }

            if (fixedPriceAgreementId) {
                payload.fixed_price_agreement_id = fixedPriceAgreementId;
            }
            
            try {
                const response = await fetch('/api/v1/timetracking/entries/internal', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(payload)
                });
                
                if (!response.ok) {
                    const error = await response.json();
                    throw new Error(error.detail || 'Kunne ikke gemme tidsregistrering');
                }
                
                // Success - reload page to show new entry
                window.location.reload();
            } catch (error) {
                alert('Fejl: ' + error.message);
                console.error('Quick add time error:', error);
            }
        }
        
        // Set today's date as default for quick time form
        document.addEventListener('DOMContentLoaded', function() {
            const dateInput = document.getElementById('quickTimeDate');
            if (dateInput && !dateInput.value) {
                const today = new Date().toISOString().split('T')[0];
                dateInput.value = today;
            }
            // Activate tab from ?tab= URL parameter (used when navigating from relation tree QA menu)
            const tabParam = new URLSearchParams(window.location.search).get('tab');
            if (tabParam) {
                const tabBtn = document.getElementById(tabParam + '-tab')
                    || document.querySelector(`[data-module-tab="${tabParam}"]`);
                if (tabBtn) {
                    setTimeout(() => {
                        const targetSelector = tabBtn.getAttribute('data-bs-target') || '';
                        const targetTabId = targetSelector.startsWith('#') ? targetSelector.slice(1) : tabParam;
                        forceCaseTabActivation(targetTabId);
                    }, 300);
                }
            }
        });
    </script>

    <script>
    // Fallback bindings: keep relation modal buttons working even if an earlier script fails.
    (function () {
        function ensureAndShowModal(modalId) {
            const modalEl = document.getElementById(modalId);
            if (!modalEl || !window.bootstrap || !window.bootstrap.Modal) return false;
            const instance = window.bootstrap.Modal.getOrCreateInstance(modalEl);
            instance.show();
            return true;
        }

        window.showRelationModal = function () {
            const opened = ensureAndShowModal('relationModal');
            if (opened) {
                setTimeout(() => {
                    const input = document.getElementById('relationCaseSearch');
                    if (input) input.focus();
                }, 250);
            }
        };

        window.showCreateRelatedModal = function () {
            const opened = ensureAndShowModal('createRelatedCaseModal');
            if (opened && typeof window.updateNewCaseRelationTypeHint === 'function') {
                window.updateNewCaseRelationTypeHint();
            }
        };

        if (typeof window.createRelatedCase !== 'function') {
            window.createRelatedCase = async function () {
                const titleEl = document.getElementById('newCaseTitle');
                const relationTypeEl = document.getElementById('newCaseRelationType');
                const descriptionEl = document.getElementById('newCaseDescription');

                const title = (titleEl?.value || '').trim();
                const relationType = (relationTypeEl?.value || '').trim();
                const description = (descriptionEl?.value || '').trim();

                if (!title) {
                    alert('Titel er påkrævet');
                    return;
                }

                if (!relationType) {
                    alert('Vælg relationstype');
                    return;
                }

                const pathMatch = String(window.location.pathname || '').match(/\/sag\/(\d+)/);
                const rootCaseId = pathMatch ? parseInt(pathMatch[1], 10) : null;
                if (!rootCaseId) {
                    alert('Kunne ikke finde sags-id i URL');
                    return;
                }

                let customerId = {{ case.customer_id if case.customer_id else 'null' }};
                if (!customerId) {
                    try {
                        const rootCaseResponse = await fetch(`/api/v1/sag/${rootCaseId}`, { credentials: 'include' });
                        if (rootCaseResponse.ok) {
                            const rootCase = await rootCaseResponse.json();
                            customerId = rootCase?.customer_id || null;
                        }
                    } catch (_) {
                        // handled by validation below
                    }
                }

                if (!customerId) {
                    alert('Sagen mangler kunde. Tilknyt kunde først, før du opretter relateret sag.');
                    return;
                }

                try {
                    const caseResponse = await fetch('/api/v1/sag', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        credentials: 'include',
                        body: JSON.stringify({
                            titel: title,
                            beskrivelse: description,
                            status: 'åben',
                            customer_id: customerId
                        })
                    });

                    if (!caseResponse.ok) {
                        const payload = await caseResponse.json().catch(() => ({}));
                        throw new Error(payload.detail || 'Kunne ikke oprette sag');
                    }

                    const newCase = await caseResponse.json();
                    const newCaseId = Number(newCase?.id || 0);
                    if (!newCaseId) {
                        throw new Error('Kunne ikke læse nyt sags-id');
                    }

                    const relationResponse = await fetch(`/api/v1/sag/${rootCaseId}/relationer`, {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        credentials: 'include',
                        body: JSON.stringify({
                            målsag_id: newCaseId,
                            relationstype: relationType
                        })
                    });

                    if (!relationResponse.ok) {
                        const payload = await relationResponse.json().catch(() => ({}));
                        throw new Error(payload.detail || 'Kunne ikke oprette relation');
                    }

                    window.location.reload();
                } catch (error) {
                    alert('Der opstod en fejl: ' + (error?.message || error));
                }
            };
        }
    })();
    </script>

    <!-- ── Relation row: quick-actions + inline tags ──────────────────────── -->
    <script>
    (function () {
        'use strict';

        let _openPopover = null;

        // ── helpers ───────────────────────────────────────────────────────
        function closeAllPopovers() {
            document.querySelectorAll('.rel-qa-menu').forEach(el => el.remove());
            _openPopover = null;
        }
        document.addEventListener('click', function(e) {
            if (!e.target.closest('.rel-qa-menu') && !e.target.closest('.btn-rel-action')) closeAllPopovers();
        });
        document.addEventListener('keydown', function(e) {
            if (e.key === 'Escape') closeAllPopovers();
        });

        function popoverPos(btn) {
            const r = btn.getBoundingClientRect();
            return { top: r.bottom + window.scrollY + 4, left: r.left + window.scrollX };
        }

        function esc(s) { return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }

        // ── load global entity tags into rel-tag-row divs (using global tag system) ──
        async function loadAllRelationTags() {
            const rows = Array.from(document.querySelectorAll('.rel-tag-row'));
            if (!rows.length) return;
            // Wait briefly for tag-picker.js to initialize
            const renderFn = () => window.renderEntityTags;
            await new Promise(res => { const t = setInterval(() => { if (renderFn()) { clearInterval(t); res(); } }, 50); setTimeout(() => { clearInterval(t); res(); }, 2000); });
            await Promise.all(rows.map(async el => {
                const caseId = parseInt(el.id.replace('rel-tags-', ''));
                if (isNaN(caseId) || !window.renderEntityTags) return;
                await window.renderEntityTags('case', caseId, el.id);
            }));
        }

        // ── tag button → opens global tag picker ──────────────────────────
        window.openRelTagPopover = function(caseId) {
            if (!window.showTagPicker) return;
            window.showTagPicker('case', caseId, () => {
                if (window.renderEntityTags) window.renderEntityTags('case', caseId, 'rel-tags-' + caseId);
            });
        };

        // ── quick action menu ─────────────────────────────────────────────
        const QA_ITEMS = [
            { icon: 'bi-clock',           label: 'Tidregistrering',  action: 'time'         },
            { icon: 'bi-chat-left-text',  label: 'Kommentar',        action: 'note'         },
            { icon: 'bi-bell',            label: 'Påmindelse',       action: 'reminder'     },
            { icon: 'bi-graph-up-arrow',  label: 'Salgspipeline',    action: 'pipeline'     },
            { icon: 'bi-paperclip',       label: 'Filer',            action: 'files'        },
            { icon: 'bi-cpu',             label: 'Hardware',         action: 'hardware'     },
            { icon: 'bi-check2-square',   label: 'Opgave',           action: 'todo'         },
            { icon: 'bi-lightbulb',       label: 'Løsning',          action: 'solution'     },
            { icon: 'bi-bag',             label: 'Varekøb & salg',   action: 'sales'        },
            { icon: 'bi-arrow-repeat',    label: 'Abonnement',       action: 'subscription' },
            { icon: 'bi-envelope',        label: 'Send email',       action: 'email'        },
        ];

        // cache pipeline presence per caseId so we only fetch once per page load
        const _pipelineCache = {};

        window.openRelQaMenu = async function(caseId, caseTitle, btn) {
            closeAllPopovers();
            btn.classList.add('active');
            const pos = popoverPos(btn);
            const menu = document.createElement('div');
            menu.className = 'rel-qa-menu';
            menu.style.cssText = `position:absolute;top:${pos.top}px;left:${Math.max(0, pos.left - 120)}px;`;
            menu.innerHTML = `<div style="font-size:.72rem;font-weight:700;color:var(--accent);padding:4px 12px 4px;">SAG-${caseId}</div>`
                + `<div style="font-size:.72rem;color:var(--text-secondary,#aaa);padding:2px 12px 4px;"><span class="spinner-border spinner-border-sm" style="width:.6rem;height:.6rem;border-width:.1em;"></span></div>`;
            document.body.appendChild(menu);
            _openPopover = menu;

            // Fetch case data to check pipeline presence (cached)
            if (!(_pipelineCache[caseId] !== undefined)) {
                try {
                    const r = await fetch(`/api/v1/sag/${caseId}`, { credentials: 'include' });
                    if (r.ok) {
                        const d = await r.json();
                        _pipelineCache[caseId] = !!(d.pipeline_stage_id || d.pipeline_amount || d.pipeline_description);
                    } else {
                        _pipelineCache[caseId] = false;
                    }
                } catch { _pipelineCache[caseId] = false; }
            }

            const hasPipeline = _pipelineCache[caseId];

            // Filter: hide pipeline item if case already has one; show "Se pipeline" link instead
            const items = QA_ITEMS.filter(i => i.action !== 'pipeline' || !hasPipeline);
            const extra = hasPipeline
                ? `<div class="qa-item" style="opacity:.55;font-style:italic;" onclick="window.open('/sag/${caseId}/v3','_blank')"><i class="bi bi-graph-up-arrow"></i>Pipeline (se sagen)</div>`
                : '';

            if (!_openPopover || _openPopover !== menu) return; // closed before fetch returned
            menu.innerHTML = `<div style="font-size:.72rem;font-weight:700;color:var(--accent);padding:4px 12px 4px;">SAG-${caseId}</div>`
                + items.map(item =>
                    `<div class="qa-item" onclick="relQaAction('${item.action}',${caseId},'${caseTitle.replace(/'/g,"\\'")}')"><i class="bi ${item.icon}"></i>${esc(item.label)}</div>`
                ).join('')
                + extra;
        };

        function getRelQaPrimaryButton() {
            const sidePanel = document.getElementById('caseAddSidePanel');
            if (sidePanel && sidePanel.classList.contains('open')) {
                return document.querySelector('#caseAddSideWorkspace #relQaModalFooter .btn-primary');
            }
            return document.querySelector('body > #relQaModalEl .btn-primary');
        }

        function closeRelQaSurfaceAfterSave() {
            const sidePanel = document.getElementById('caseAddSidePanel');
            const panelOpen = !!(sidePanel && sidePanel.classList.contains('open'));

            const relModalEl = document.getElementById('relQaModalEl');
            const relModalInstance = relModalEl ? bootstrap.Modal.getInstance(relModalEl) : null;
            if (relModalInstance) {
                relModalInstance.hide();
            }

            // In sidepanel mode, refresh to reflect new persisted data across modules.
            if (panelOpen) {
                setTimeout(() => window.location.reload(), 120);
            }
        }

        window.relQaAction = function(action, caseId, caseTitle) {
            closeAllPopovers();
            if      (action === 'time')         openRelTimeModal(caseId, caseTitle);
            else if (action === 'email')        openRelEmailModal(caseId, caseTitle);
            else if (action === 'note')         openRelNoteModal(caseId, caseTitle);
            else if (action === 'reminder')     openRelReminderModal(caseId, caseTitle);
            else if (action === 'todo')         openRelTodoModal(caseId, caseTitle);
            else if (action === 'assign')       openRelAssignModal(caseId, caseTitle);
            else if (action === 'pipeline')     openRelPipelineModal(caseId, caseTitle);
            else if (action === 'files')        openRelFilesModal(caseId, caseTitle);
            else if (action === 'hardware')     openRelHardwareModal(caseId, caseTitle);
            else if (action === 'solution')     openRelSolutionModal(caseId, caseTitle);
            else if (action === 'sales')        openRelSalesModal(caseId, caseTitle);
            else if (action === 'subscription') openRelSubscriptionModal(caseId, caseTitle);
            else                                window.open(`/sag/${caseId}/v3`, '_blank');
        };

        // ── Quick Pipeline modal ──────────────────────────────────────────
        window.openRelPipelineModal = function(caseId, caseTitle) {
            _showRelModal(
                `<i class="bi bi-graph-up-arrow me-2"></i>Salgspipeline`,
                `<div class="mb-2"><label class="form-label small fw-semibold">SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Stage</label>
                   <select id="rqp_stage" class="form-select form-select-sm">
                     <option value="">-- Vælg stage --</option>
                     <option value="1">Ny</option>
                     <option value="2">Afklaring</option>
                     <option value="3">Tilbud</option>
                     <option value="4">Commit</option>
                     <option value="5">Vundet</option>
                     <option value="6">Tabt</option>
                     <option value="7">Opsalg</option>
                     <option value="8">Lead</option>
                     <option value="9">Kontakt</option>
                     <option value="10">Forhandling</option>
                   </select>
                 </div>
                 <div class="row g-2 mb-2">
                   <div class="col-7">
                     <label class="form-label small fw-semibold">Beløb (DKK)</label>
                     <input type="number" id="rqp_amount" class="form-control form-control-sm" min="0" step="0.01" placeholder="0">
                   </div>
                   <div class="col-5">
                     <label class="form-label small fw-semibold">Sandsynlighed %</label>
                     <input type="number" id="rqp_prob" class="form-control form-control-sm" min="0" max="100" placeholder="0">
                   </div>
                 </div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Note</label>
                   <textarea id="rqp_desc" class="form-control form-control-sm" rows="2" placeholder="Pipeline-note…"></textarea>
                 </div>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelPipeline(${caseId})"><i class="bi bi-check2 me-1"></i>Gem</button>`
            );
        };

        window._submitRelPipeline = async function(caseId) {
            const stage = document.getElementById('rqp_stage').value;
            const amount = document.getElementById('rqp_amount').value;
            const prob = document.getElementById('rqp_prob').value;
            const desc = document.getElementById('rqp_desc').value;
            const payload = {};
            if (stage)  payload.stage_id     = parseInt(stage);
            if (amount) payload.amount        = parseFloat(amount);
            if (prob)   payload.probability   = parseInt(prob);
            if (desc)   payload.description   = desc;
            if (!Object.keys(payload).length) { if (typeof showNotification === 'function') showNotification('Udfyld mindst ét felt', 'warning'); return; }
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) { saveBtn.disabled = true; }
            try {
                const r = await fetch(`/api/v1/sag/${caseId}/pipeline`, { method: 'PATCH', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) });
                if (r.ok) {
                    closeRelQaSurfaceAfterSave();
                    if (typeof showNotification === 'function') showNotification('Pipeline opdateret ✓', 'success');
                } else {
                    const d = await r.json().catch(()=>({}));
                    if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl', 'error');
                    if (saveBtn) saveBtn.disabled = false;
                }
            } catch { if (saveBtn) saveBtn.disabled = false; }
        };

        // ── Quick Files modal ─────────────────────────────────────────────
        window.openRelFilesModal = function(caseId, caseTitle) {
            _showRelModal(
                `<i class="bi bi-paperclip me-2"></i>Upload fil`,
                `<div class="mb-2"><label class="form-label small fw-semibold">SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Vælg fil</label>
                   <input type="file" id="rqf_file" class="form-control form-control-sm" multiple>
                 </div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Beskrivelse (valgfri)</label>
                   <input type="text" id="rqf_desc" class="form-control form-control-sm" placeholder="Fil-note…">
                 </div>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelFiles(${caseId})"><i class="bi bi-upload me-1"></i>Upload</button>`
            );
        };

        window._submitRelFiles = async function(caseId) {
            const fileInput = document.getElementById('rqf_file');
            if (!fileInput.files.length) { if (typeof showNotification === 'function') showNotification('Vælg mindst én fil', 'warning'); return; }
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) { saveBtn.disabled = true; saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Uploader…'; }
            try {
                const fd = new FormData();
                for (const file of fileInput.files) {
                    fd.append('files', file);
                }

                const r = await fetch(`/api/v1/sag/${caseId}/files`, { method: 'POST', credentials: 'include', body: fd });
                if (!r.ok) {
                    const d = await r.json().catch(() => ({}));
                    if (typeof showNotification === 'function') showNotification(d.detail || 'Upload fejlede', 'error');
                    if (saveBtn) {
                        saveBtn.disabled = false;
                        saveBtn.innerHTML = '<i class="bi bi-upload me-1"></i>Upload';
                    }
                    return;
                }

                const saved = await r.json().catch(() => []);
                const uploadedCount = Array.isArray(saved) ? saved.length : 0;
                if (uploadedCount === 0) {
                    if (typeof showNotification === 'function') showNotification('Filer blev ikke gemt. Prøv igen.', 'warning');
                    if (saveBtn) {
                        saveBtn.disabled = false;
                        saveBtn.innerHTML = '<i class="bi bi-upload me-1"></i>Upload';
                    }
                    return;
                }

                if (typeof loadSagFiles === 'function') {
                    await loadSagFiles();
                }
                closeRelQaSurfaceAfterSave();
                if (typeof showNotification === 'function') {
                    showNotification(`${uploadedCount} fil(er) uploadet ✓`, 'success');
                }
            } catch {
                if (typeof showNotification === 'function') showNotification('Upload fejlede', 'error');
                if (saveBtn) {
                    saveBtn.disabled = false;
                    saveBtn.innerHTML = '<i class="bi bi-upload me-1"></i>Upload';
                }
            }
        };

        // ── Quick Hardware modal ──────────────────────────────────────────
        window.openRelHardwareModal = async function(caseId, caseTitle) {
            _showRelModal(
                `<i class="bi bi-cpu me-2"></i>Hardware`,
                `<div class="mb-2"><label class="form-label small fw-semibold">SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Søg hardware</label>
                   <input type="text" id="rqhw_search" class="form-control form-control-sm" placeholder="Serienummer, navn…" autocomplete="off">
                   <div id="rqhw_results" class="mt-1" style="max-height:180px;overflow-y:auto;border:1px solid var(--border,#dee2e6);border-radius:6px;display:none;"></div>
                 </div>
                 <div id="rqhw_selected" class="text-muted small"></div>
                 <div class="mb-2 mt-2">
                   <label class="form-label small fw-semibold">Note (valgfri)</label>
                   <input type="text" id="rqhw_note" class="form-control form-control-sm" placeholder="Note om hardware…">
                 </div>
                 <input type="hidden" id="rqhw_id" value="">`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelHardware(${caseId})"><i class="bi bi-check2 me-1"></i>Tilknyt</button>`
            );
            // Wire up search
            const inp = document.getElementById('rqhw_search');
            const res = document.getElementById('rqhw_results');
            let _hwTimer;
            inp.addEventListener('input', () => {
                clearTimeout(_hwTimer);
                _hwTimer = setTimeout(async () => {
                    const q = inp.value.trim();
                    if (q.length < 2) { res.style.display='none'; return; }
                    try {
                        const r = await fetch(`/api/v1/search/hardware?q=${encodeURIComponent(q)}`, { credentials: 'include' });
                        if (!r.ok) return;
                        const items = await r.json();
                        if (!items.length) { res.innerHTML = '<div class="p-2 text-muted small">Ingen resultater</div>'; res.style.display='block'; return; }
                        res.innerHTML = items.slice(0,10).map(h =>
                            `<div class="p-2 border-bottom hw-opt" style="cursor:pointer;font-size:.82rem;" data-id="${h.id}" data-label="${esc(h.name||h.serial_number||h.id)}">${esc(h.name||'')} <span class="text-muted">${esc(h.serial_number||'')}</span></div>`
                        ).join('');
                        res.style.display = 'block';
                        res.querySelectorAll('.hw-opt').forEach(el => el.addEventListener('click', () => {
                            document.getElementById('rqhw_id').value = el.dataset.id;
                            document.getElementById('rqhw_selected').textContent = '✓ Valgt: ' + el.dataset.label;
                            inp.value = el.dataset.label;
                            res.style.display = 'none';
                        }));
                    } catch {}
                }, 300);
            });
        };

        window._submitRelHardware = async function(caseId) {
            const hwId = document.getElementById('rqhw_id').value;
            if (!hwId) { if (typeof showNotification === 'function') showNotification('Vælg hardware fra listen', 'warning'); return; }
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) saveBtn.disabled = true;
            try {
                const r = await fetch(`/api/v1/sag/${caseId}/hardware`, {
                    method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'},
                    body: JSON.stringify({ hardware_id: parseInt(hwId), note: document.getElementById('rqhw_note').value })
                });
                if (r.ok) {
                    closeRelQaSurfaceAfterSave();
                    if (typeof showNotification === 'function') showNotification('Hardware tilknyttet ✓', 'success');
                } else {
                    const d = await r.json().catch(()=>({}));
                    if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl', 'error');
                    if (saveBtn) saveBtn.disabled = false;
                }
            } catch { if (saveBtn) saveBtn.disabled = false; }
        };

        // ── Quick Løsning modal ───────────────────────────────────────────
        window.openRelSolutionModal = function(caseId, caseTitle) {
            const today = new Date().toISOString().split('T')[0];
            _showRelModal(
                `<i class="bi bi-lightbulb me-2"></i>Løsning`,
                `<div class="mb-2"><label class="form-label small fw-semibold">SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Titel</label>
                   <input type="text" id="rqs_title" class="form-control form-control-sm" placeholder="Løsningstitel…">
                 </div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Type</label>
                   <select id="rqs_type" class="form-select form-select-sm">
                     <option value="standard">Standard</option>
                     <option value="workaround">Workaround</option>
                     <option value="permanent">Permanent</option>
                     <option value="external">Ekstern</option>
                   </select>
                 </div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Resultat</label>
                   <select id="rqs_result" class="form-select form-select-sm">
                     <option value="resolved">Løst</option>
                     <option value="partial">Delvist løst</option>
                     <option value="unresolved">Uløst</option>
                   </select>
                 </div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Beskrivelse</label>
                   <textarea id="rqs_desc" class="form-control form-control-sm" rows="3" placeholder="Beskriv løsningen…"></textarea>
                 </div>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelSolution(${caseId})"><i class="bi bi-check2 me-1"></i>Gem</button>`
            );
        };

        window._submitRelSolution = async function(caseId) {
            const title = document.getElementById('rqs_title').value.trim();
            if (!title) { if (typeof showNotification === 'function') showNotification('Angiv en titel', 'warning'); return; }
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) saveBtn.disabled = true;
            try {
                const r = await fetch(`/api/v1/sag/${caseId}/solution`, {
                    method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'},
                    body: JSON.stringify({
                        sag_id: caseId,
                        title,
                        solution_type:  document.getElementById('rqs_type').value,
                        result:         document.getElementById('rqs_result').value,
                        description:    document.getElementById('rqs_desc').value,
                    })
                });
                if (r.ok) {
                    closeRelQaSurfaceAfterSave();
                    if (typeof showNotification === 'function') showNotification('Løsning gemt ✓', 'success');
                } else {
                    const d = await r.json().catch(()=>({}));
                    if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl', 'error');
                    if (saveBtn) saveBtn.disabled = false;
                }
            } catch { if (saveBtn) saveBtn.disabled = false; }
        };

        // ── Quick Varekøb & Salg modal ────────────────────────────────────
        window.openRelSalesModal = function(caseId, caseTitle) {
            const today = new Date().toISOString().split('T')[0];
            _showRelModal(
                `<i class="bi bi-bag me-2"></i>Varekøb &amp; salg`,
                `<div class="mb-2"><label class="form-label small fw-semibold">SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Type</label>
                   <select id="rqsl_type" class="form-select form-select-sm">
                     <option value="sale">Salg</option>
                     <option value="purchase">Indkøb</option>
                   </select>
                 </div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Beskrivelse</label>
                   <input type="text" id="rqsl_desc" class="form-control form-control-sm" placeholder="Varebeskrivelse…">
                 </div>
                 <div class="row g-2 mb-2">
                   <div class="col-4">
                     <label class="form-label small fw-semibold">Antal</label>
                     <input type="number" id="rqsl_qty" class="form-control form-control-sm" min="1" value="1" step="1">
                   </div>
                   <div class="col-4">
                     <label class="form-label small fw-semibold">Stykpris</label>
                     <input type="number" id="rqsl_uprice" class="form-control form-control-sm" min="0" step="0.01" placeholder="0.00">
                   </div>
                   <div class="col-4">
                     <label class="form-label small fw-semibold">Total (DKK)</label>
                     <input type="number" id="rqsl_total" class="form-control form-control-sm" min="0" step="0.01" placeholder="0.00">
                   </div>
                 </div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Dato</label>
                   <input type="date" id="rqsl_date" class="form-control form-control-sm" value="${today}">
                 </div>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelSales(${caseId})"><i class="bi bi-check2 me-1"></i>Gem</button>`
            );
            // Auto-calculate total when qty/uprice changes
            setTimeout(() => {
                const qtyEl   = document.getElementById('rqsl_qty');
                const uprEl   = document.getElementById('rqsl_uprice');
                const totEl   = document.getElementById('rqsl_total');
                function calcTotal() {
                    const q = parseFloat(qtyEl.value) || 0;
                    const u = parseFloat(uprEl.value) || 0;
                    if (q && u) totEl.value = (q * u).toFixed(2);
                }
                qtyEl.addEventListener('input', calcTotal);
                uprEl.addEventListener('input', calcTotal);
            }, 50);
        };

        window._submitRelSales = async function(caseId) {
            const desc = document.getElementById('rqsl_desc').value.trim();
            const total = parseFloat(document.getElementById('rqsl_total').value);
            if (!desc) { if (typeof showNotification === 'function') showNotification('Angiv beskrivelse', 'warning'); return; }
            if (!total) { if (typeof showNotification === 'function') showNotification('Angiv beløb', 'warning'); return; }
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) saveBtn.disabled = true;
            try {
                const r = await fetch(`/api/v1/sag/${caseId}/sale-items`, {
                    method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'},
                    body: JSON.stringify({
                        type:        document.getElementById('rqsl_type').value,
                        description: desc,
                        quantity:    parseFloat(document.getElementById('rqsl_qty').value) || 1,
                        unit_price:  parseFloat(document.getElementById('rqsl_uprice').value) || null,
                        amount:      total,
                        line_date:   document.getElementById('rqsl_date').value || null,
                        status:      'draft',
                    })
                });
                if (r.ok) {
                    closeRelQaSurfaceAfterSave();
                    if (typeof showNotification === 'function') showNotification('Varelinje oprettet ✓', 'success');
                } else {
                    const d = await r.json().catch(()=>({}));
                    if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl', 'error');
                    if (saveBtn) saveBtn.disabled = false;
                }
            } catch { if (saveBtn) saveBtn.disabled = false; }
        };

        // ── Quick Abonnement modal ────────────────────────────────────────
        window.openRelSubscriptionModal = function(caseId, caseTitle) {
            const today = new Date().toISOString().split('T')[0];
            _showRelModal(
                `<i class="bi bi-arrow-repeat me-2"></i>Abonnement`,
                `<div class="mb-2"><label class="form-label small fw-semibold">SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <div class="row g-2 mb-2">
                   <div class="col-6">
                     <label class="form-label small fw-semibold">Faktureringsinterval</label>
                     <select id="rqsub_interval" class="form-select form-select-sm">
                       <option value="monthly">Månedlig</option>
                       <option value="quarterly">Kvartalsvis</option>
                       <option value="yearly">Årlig</option>
                       <option value="weekly">Ugentlig</option>
                     </select>
                   </div>
                   <div class="col-3">
                     <label class="form-label small fw-semibold">Fakturering dag</label>
                     <input type="number" id="rqsub_day" class="form-control form-control-sm" min="1" max="28" value="1">
                   </div>
                   <div class="col-3">
                     <label class="form-label small fw-semibold">Startdato</label>
                     <input type="date" id="rqsub_start" class="form-control form-control-sm" value="${today}">
                   </div>
                 </div>
                 <div class="border rounded p-2 mb-2">
                   <div class="small fw-semibold mb-1">Varelinje</div>
                   <div class="row g-1">
                     <div class="col-6"><input type="text" id="rqsub_li_desc" class="form-control form-control-sm" placeholder="Beskrivelse"></div>
                     <div class="col-3"><input type="number" id="rqsub_li_qty" class="form-control form-control-sm" placeholder="Antal" min="1" value="1"></div>
                     <div class="col-3"><input type="number" id="rqsub_li_price" class="form-control form-control-sm" placeholder="Pris" min="0" step="0.01"></div>
                   </div>
                 </div>
                 <div class="mb-2">
                   <label class="form-label small fw-semibold">Note (valgfri)</label>
                   <input type="text" id="rqsub_notes" class="form-control form-control-sm" placeholder="Intern note…">
                 </div>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelSubscription(${caseId})"><i class="bi bi-check2 me-1"></i>Opret</button>`
            );
        };

        window._submitRelSubscription = async function(caseId) {
            const interval  = document.getElementById('rqsub_interval').value;
            const day       = parseInt(document.getElementById('rqsub_day').value);
            const startDate = document.getElementById('rqsub_start').value;
            const liDesc    = document.getElementById('rqsub_li_desc').value.trim();
            const liQty     = parseFloat(document.getElementById('rqsub_li_qty').value) || 1;
            const liPrice   = parseFloat(document.getElementById('rqsub_li_price').value) || 0;
            if (!startDate) { if (typeof showNotification === 'function') showNotification('Angiv startdato', 'warning'); return; }
            if (!liDesc || !liPrice) { if (typeof showNotification === 'function') showNotification('Udfyld varelinje (beskrivelse + pris)', 'warning'); return; }
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) saveBtn.disabled = true;
            try {
                const r = await fetch('/api/v1/sag-subscriptions', {
                    method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'},
                    body: JSON.stringify({
                        sag_id:           caseId,
                        billing_interval: interval,
                        billing_day:      day,
                        start_date:       startDate,
                        notes:            document.getElementById('rqsub_notes').value || null,
                        line_items: [{ description: liDesc, quantity: liQty, unit_price: liPrice }]
                    })
                });
                if (r.ok) {
                    closeRelQaSurfaceAfterSave();
                    if (typeof showNotification === 'function') showNotification('Abonnement oprettet ✓', 'success');
                } else {
                    const d = await r.json().catch(()=>({}));
                    if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl', 'error');
                    if (saveBtn) saveBtn.disabled = false;
                }
            } catch { if (saveBtn) saveBtn.disabled = false; }
        };

        // ── Quick Time modal ──────────────────────────────────────────────
        window.openRelTimeModal = function(caseId, caseTitle) {
            const today = new Date().toISOString().split('T')[0];
            _showRelModal(
                `<i class="bi bi-clock me-2"></i>Tidregistrering`,
                `<div class="mb-2"><label class="form-label small fw-semibold">Sag</label>
                 <input class="form-control form-control-sm" readonly value="SAG-${caseId} – ${esc(caseTitle)}"></div>
                 <div class="row g-2 mb-2">
                   <div class="col-6"><label class="form-label small fw-semibold">Dato</label>
                     <input type="date" id="rqt_date" class="form-control form-control-sm" value="${today}"></div>
                   <div class="col-3"><label class="form-label small fw-semibold">Timer</label>
                     <input type="number" id="rqt_h" class="form-control form-control-sm" min="0" max="23" value="0"></div>
                   <div class="col-3"><label class="form-label small fw-semibold">Min</label>
                     <input type="number" id="rqt_m" class="form-control form-control-sm" min="0" max="59" step="15" value="30"></div>
                 </div>
                 <div class="mb-2"><label class="form-label small fw-semibold">Fakturering</label>
                   <select id="rqt_billing" class="form-select form-select-sm">
                     <option value="invoice">Fakturerbar</option>
                     <option value="internal">Intern</option>
                     <option value="prepaid">Forudbetalt</option>
                   </select></div>
                 <div class="mb-2"><label class="form-label small fw-semibold">Beskrivelse</label>
                   <textarea id="rqt_desc" class="form-control form-control-sm" rows="2"></textarea></div>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelTime(${caseId})"><i class="bi bi-check2 me-1"></i>Gem</button>`
            );
        };

        window._submitRelTime = async function(caseId) {
            const h = parseInt(document.getElementById('rqt_h').value) || 0;
            const m = parseInt(document.getElementById('rqt_m').value) || 0;
            const totalHours = parseFloat((h + m / 60).toFixed(4));
            if (totalHours <= 0) {
                if (typeof showNotification === 'function') showNotification('Angiv tid (timer/minutter)', 'warning');
                return;
            }
            const billing = document.getElementById('rqt_billing')?.value || 'invoice';
            const payload = {
                sag_id: caseId,
                worked_date: document.getElementById('rqt_date').value,
                original_hours: totalHours,
                description: document.getElementById('rqt_desc').value,
                billing_method: billing,
                is_internal: billing === 'internal',
            };
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) { saveBtn.disabled = true; saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>'; }
            try {
                const r = await fetch('/api/v1/timetracking/entries/internal', { method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) });
                if (r.ok) {
                    closeRelQaSurfaceAfterSave();
                    if (typeof showNotification === 'function') showNotification('Tid registreret ✓', 'success');
                } else {
                    const d = await r.json().catch(()=>({}));
                    if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl ved registrering', 'error');
                    if (saveBtn) { saveBtn.disabled = false; saveBtn.innerHTML = '<i class="bi bi-check2 me-1"></i>Gem'; }
                }
            } catch { if (saveBtn) { saveBtn.disabled = false; saveBtn.innerHTML = 'Gem'; } }
        };

        // ── Quick Email modal ─────────────────────────────────────────────
        window.openRelEmailModal = function(caseId, caseTitle) {
            const defaultRecipient = typeof getDefaultCaseRecipient === 'function' ? getDefaultCaseRecipient() : '';
            const defaultSubject = `Sag #${caseId}: `;
            const attachmentOptions = Array.isArray(sagFilesCache) && sagFilesCache.length
                ? sagFilesCache
                    .map((file) => {
                        const fileId = Number(file.id);
                        const filename = esc(file.filename || `Fil ${fileId}`);
                        return `<option value="${fileId}">${filename}</option>`;
                    })
                    .join('')
                : '<option disabled>Ingen sagsfiler</option>';

            _showRelModal(
                `<i class="bi bi-envelope me-2"></i>Email`,
                `<div class="mb-2"><label class="form-label small fw-semibold">Sag: SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <div class="row g-2 mb-2">
                   <div class="col-12"><label class="form-label small fw-semibold">Til</label>
                     <input type="text" id="rqe_to" class="form-control form-control-sm" placeholder="modtager@eksempel.dk" value="${esc(defaultRecipient)}"></div>
                   <div class="col-6"><label class="form-label small fw-semibold">Cc</label>
                     <input type="text" id="rqe_cc" class="form-control form-control-sm" placeholder="cc@eksempel.dk"></div>
                   <div class="col-6"><label class="form-label small fw-semibold">Bcc</label>
                     <input type="text" id="rqe_bcc" class="form-control form-control-sm" placeholder="bcc@eksempel.dk"></div>
                 </div>
                 <div class="mb-2"><label class="form-label small fw-semibold">Emne</label>
                   <input type="text" id="rqe_subject" class="form-control form-control-sm" value="${esc(defaultSubject)}"></div>
                 <div class="mb-2"><label class="form-label small fw-semibold">Vedhaeftninger</label>
                   <select id="rqe_attachment_ids" class="form-select form-select-sm" multiple>${attachmentOptions}</select>
                 </div>
                 <div class="mb-2"><label class="form-label small fw-semibold">Besked</label>
                   <textarea id="rqe_body" class="form-control form-control-sm" rows="6" placeholder="Skriv besked..."></textarea></div>
                 <div id="rqe_status" class="small text-muted"></div>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelEmail(${caseId})"><i class="bi bi-send me-1"></i>Send email</button>`
            );
        };

        window._submitRelEmail = async function(caseId) {
            const toInput = document.getElementById('rqe_to');
            const ccInput = document.getElementById('rqe_cc');
            const bccInput = document.getElementById('rqe_bcc');
            const subjectInput = document.getElementById('rqe_subject');
            const bodyInput = document.getElementById('rqe_body');
            const attachmentSelect = document.getElementById('rqe_attachment_ids');
            const statusEl = document.getElementById('rqe_status');
            const saveBtn = getRelQaPrimaryButton();

            if (!toInput || !subjectInput || !bodyInput || !statusEl) return;

            const to = parseEmailField(toInput.value);
            const cc = parseEmailField(ccInput?.value || '');
            const bcc = parseEmailField(bccInput?.value || '');
            const subject = (subjectInput.value || '').trim();
            const bodyText = (bodyInput.value || '').trim();
            const attachmentFileIds = Array.from(attachmentSelect?.selectedOptions || [])
                .map((opt) => Number(opt.value))
                .filter((id) => Number.isInteger(id) && id > 0);

            if (!to.length) {
                if (typeof showNotification === 'function') showNotification('Udfyld mindst en modtager.', 'warning');
                return;
            }
            if (!subject) {
                if (typeof showNotification === 'function') showNotification('Udfyld emne.', 'warning');
                return;
            }
            if (!bodyText) {
                if (typeof showNotification === 'function') showNotification('Udfyld besked.', 'warning');
                return;
            }

            if (saveBtn) {
                saveBtn.disabled = true;
                saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Sender...';
            }
            statusEl.className = 'small text-muted';
            statusEl.textContent = 'Sender e-mail...';

            try {
                const res = await fetch(`/api/v1/sag/${caseId}/emails/send`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({
                        to,
                        cc,
                        bcc,
                        subject,
                        body_text: bodyText,
                        attachment_file_ids: attachmentFileIds,
                        thread_email_id: selectedLinkedEmailId || null,
                        thread_key: (
                            linkedEmailsCache.find((entry) => Number(entry.id) === Number(selectedLinkedEmailId))?.resolved_thread_key
                            || linkedEmailsCache.find((entry) => Number(entry.id) === Number(selectedLinkedEmailId))?.thread_key
                            || null
                        )
                    })
                });

                if (!res.ok) {
                    let message = `HTTP ${res.status} ${res.statusText || 'Send failed'}`;
                    try {
                        const responseText = await res.text();
                        if (responseText) {
                            try {
                                const err = JSON.parse(responseText);
                                if (err?.detail) {
                                    message = err.detail;
                                } else if (err?.message) {
                                    message = err.message;
                                }
                            } catch (_) {
                                message = responseText.slice(0, 500);
                            }
                        }
                    } catch (_) {
                    }
                    throw new Error(message);
                }

                statusEl.className = 'small text-success';
                statusEl.textContent = 'E-mail sendt.';
                if (typeof loadLinkedEmails === 'function') {
                    loadLinkedEmails();
                }
                if (typeof showNotification === 'function') showNotification('E-mail sendt.', 'success');

                const relModalEl = document.getElementById('relQaModalEl');
                const relModal = relModalEl ? bootstrap.Modal.getInstance(relModalEl) : null;
                if (relModal) relModal.hide();
            } catch (error) {
                statusEl.className = 'small text-danger';
                statusEl.textContent = error?.message || 'Email send failed (ukendt fejl)';
                if (typeof showNotification === 'function') showNotification(statusEl.textContent, 'error');
                if (saveBtn) {
                    saveBtn.disabled = false;
                    saveBtn.innerHTML = '<i class="bi bi-send me-1"></i>Send email';
                }
                return;
            }

            if (saveBtn) {
                saveBtn.disabled = false;
                saveBtn.innerHTML = '<i class="bi bi-send me-1"></i>Send email';
            }
        };

        // ── Quick Kommentar modal ─────────────────────────────────────────
        window.openRelNoteModal = function(caseId, caseTitle) {
            _showRelModal(
                `<i class="bi bi-chat-left-text me-2"></i>Kommentar`,
                `<div class="mb-2"><label class="form-label small fw-semibold">Sag: SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <textarea id="rqn_text" class="form-control" rows="4" placeholder="Skriv kommentar..."></textarea>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelNote(${caseId})"><i class="bi bi-check2 me-1"></i>Gem</button>`
            );
        };

        window._submitRelNote = async function(caseId) {
            const text = document.getElementById('rqn_text').value.trim();
            if (!text) return;
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) { saveBtn.disabled = true; }
            try {
                const r = await fetch(`/api/v1/sag/${caseId}/kommentarer`, {
                    method: 'POST', credentials: 'include',
                    headers: {'Content-Type':'application/json'},
                    body: JSON.stringify({ forfatter: 'Hurtig kommentar', indhold: text })
                });
                if (r.ok) {
                    closeRelQaSurfaceAfterSave();
                    if (typeof showNotification === 'function') showNotification('Kommentar tilføjet ✓', 'success');
                } else {
                    const d = await r.json().catch(()=>({}));
                    if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl ved gemning', 'error');
                    if (saveBtn) saveBtn.disabled = false;
                }
            } catch { if (saveBtn) saveBtn.disabled = false; }
        };

        // ── Quick Opgave modal ────────────────────────────────────────────
        window.openRelTodoModal = function(caseId, caseTitle) {
            const today = new Date().toISOString().split('T')[0];
            _showRelModal(
                `<i class="bi bi-check2-square me-2"></i>Opgave`,
                `<div class="mb-2"><label class="form-label small fw-semibold">Sag: SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <div class="mb-2"><label class="form-label small fw-semibold">Opgavetitel</label>
                   <input type="text" id="rqtd_title" class="form-control form-control-sm" placeholder="Hvad skal gøres?"></div>
                 <div class="mb-2"><label class="form-label small fw-semibold">Frist (valgfri)</label>
                   <input type="date" id="rqtd_due" class="form-control form-control-sm" value="${today}"></div>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelTodo(${caseId})"><i class="bi bi-check2 me-1"></i>Opret</button>`
            );
        };

        window._submitRelTodo = async function(caseId) {
            const title = document.getElementById('rqtd_title').value.trim();
            if (!title) { if (typeof showNotification === 'function') showNotification('Angiv opgavetitel', 'warning'); return; }
            const due = document.getElementById('rqtd_due').value || null;
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) { saveBtn.disabled = true; }
            try {
                const r = await fetch(`/api/v1/sag/${caseId}/todos`, {
                    method: 'POST', credentials: 'include',
                    headers: {'Content-Type':'application/json'},
                    body: JSON.stringify({ titel: title, frist: due, sag_id: caseId })
                });
                if (r.ok) {
                    closeRelQaSurfaceAfterSave();
                    if (typeof showNotification === 'function') showNotification('Opgave oprettet ✓', 'success');
                } else {
                    const d = await r.json().catch(()=>({}));
                    if (typeof showNotification === 'function') showNotification(d.detail || 'Opgave-endpoint ikke tilgængeligt endnu', 'warning');
                    if (saveBtn) saveBtn.disabled = false;
                }
            } catch { if (saveBtn) saveBtn.disabled = false; }
        };

        // ── Quick Tildel sag modal ────────────────────────────────────────
        window.openRelAssignModal = async function(caseId, caseTitle) {
            _showRelModal(
                `<i class="bi bi-person-check me-2"></i>Tildel sag`,
                `<div class="mb-2"><label class="form-label small fw-semibold">SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <label class="form-label small fw-semibold">Ansvarlig bruger</label>
                 <select id="rqa_user" class="form-select form-select-sm"><option>Henter brugere…</option></select>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelAssign(${caseId})"><i class="bi bi-check2 me-1"></i>Tildel</button>`
            );
            try {
                const r = await fetch('/api/v1/users', { credentials: 'include' });
                if (r.ok) {
                    const users = await r.json();
                    const sel = document.getElementById('rqa_user');
                    if (sel) sel.innerHTML = '<option value="">Ingen (fjern tildeling)</option>'
                        + users.map(u => `<option value="${u.user_id}">${esc(u.display_name || u.username || '')}</option>`).join('');
                }
            } catch {}
        };

        window._submitRelAssign = async function(caseId) {
            const userId = document.getElementById('rqa_user')?.value;
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) { saveBtn.disabled = true; }
            try {
                const r = await fetch(`/api/v1/sag/${caseId}`, {
                    method: 'PATCH', credentials: 'include',
                    headers: {'Content-Type':'application/json'},
                    body: JSON.stringify({ ansvarlig_bruger_id: userId ? parseInt(userId) : null })
                });
                if (r.ok) {
                    closeRelQaSurfaceAfterSave();
                    if (typeof showNotification === 'function') showNotification('Sag tildelt ✓', 'success');
                } else {
                    const d = await r.json().catch(()=>({}));
                    if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl ved tildeling', 'error');
                    if (saveBtn) saveBtn.disabled = false;
                }
            } catch { if (saveBtn) saveBtn.disabled = false; }
        };

        // ── Quick Reminder modal ──────────────────────────────────────────
        window.openRelReminderModal = function(caseId, caseTitle) {
            const tmr = new Date(); tmr.setDate(tmr.getDate()+1);
            const tmrStr = tmr.toISOString().slice(0,16);
            _showRelModal(
                `<i class="bi bi-bell me-2"></i>Påmindelse`,
                `<div class="mb-2"><label class="form-label small fw-semibold">Sag: SAG-${caseId} – ${esc(caseTitle)}</label></div>
                 <div class="mb-2"><label class="form-label small fw-semibold">Tidspunkt</label>
                   <input type="datetime-local" id="rqr_at" class="form-control form-control-sm" value="${tmrStr}"></div>
                 <div class="mb-2"><label class="form-label small fw-semibold">Besked</label>
                   <input type="text" id="rqr_msg" class="form-control form-control-sm" placeholder="Husk at…"></div>`,
                `<button class="btn btn-sm btn-primary" onclick="_submitRelReminder(${caseId})"><i class="bi bi-check2 me-1"></i>Gem</button>`
            );
        };

        window._submitRelReminder = async function(caseId) {
            const whenInput = document.getElementById('rqr_at')?.value || '';
            const message = (document.getElementById('rqr_msg')?.value || '').trim();
            if (!whenInput) {
                if (typeof showNotification === 'function') showNotification('Vælg tidspunkt', 'warning');
                return;
            }

            let reminderUserId = null;
            try {
                if (typeof ensureReminderUserId === 'function') {
                    reminderUserId = await ensureReminderUserId();
                } else if (typeof getReminderUserId === 'function') {
                    reminderUserId = getReminderUserId();
                }
            } catch {}

            if (!reminderUserId) {
                if (typeof showNotification === 'function') showNotification('Mangler bruger-id til reminder', 'error');
                return;
            }

            const scheduledAtIso = new Date(whenInput).toISOString();
            const baseTitle = (message || 'Husk opfoelgning').trim();
            const safeTitle = (baseTitle.length >= 3 ? baseTitle : 'Reminder').slice(0, 255);
            const payload = {
                title: safeTitle,
                message: message || null,
                priority: 'normal',
                event_type: 'reminder',
                trigger_type: 'time_based',
                trigger_config: {},
                recipient_user_ids: [Number(reminderUserId)],
                recipient_emails: [],
                notify_mattermost: false,
                notify_email: false,
                notify_frontend: true,
                override_user_preferences: false,
                recurrence_type: 'once',
                recurrence_day_of_week: null,
                recurrence_day_of_month: null,
                scheduled_at: scheduledAtIso,
            };
            const saveBtn = getRelQaPrimaryButton();
            if (saveBtn) { saveBtn.disabled = true; }
            try {
                const r = await fetch(`/api/v1/sag/${caseId}/reminders?user_id=${encodeURIComponent(reminderUserId)}`, {
                    method: 'POST', credentials: 'include',
                    headers: {'Content-Type':'application/json'},
                    body: JSON.stringify(payload)
                });
                if (r.ok) {
                    closeRelQaSurfaceAfterSave();
                    if (typeof showNotification === 'function') showNotification('Påmindelse oprettet', 'success');
                } else { if (saveBtn) saveBtn.disabled = false; }
            } catch { if (saveBtn) saveBtn.disabled = false; }
        };

        // ── shared modal helper ───────────────────────────────────────────
        window._showRelModal = function(title, bodyHtml, footerBtns) {
            let el = document.querySelector('body > #relQaModalEl.modal');
            if (!el) {
                const nonModal = document.getElementById('relQaModalEl');
                if (nonModal && !nonModal.classList.contains('modal')) {
                    nonModal.remove();
                }
                el = document.createElement('div');
                el.id = 'relQaModalEl';
                el.className = 'modal fade';
                el.tabIndex = -1;
                el.innerHTML = `<div class="modal-dialog modal-dialog-centered"><div class="modal-content">
                    <div class="modal-header py-2 px-3">
                        <h6 class="modal-title mb-0" id="relQaModalTitle"></h6>
                        <button type="button" class="btn-close btn-sm" data-bs-dismiss="modal"></button>
                    </div>
                    <div class="modal-body" id="relQaModalBody"></div>
                    <div class="modal-footer py-2 px-3" id="relQaModalFooter">
                        <button class="btn btn-sm btn-outline-secondary" data-bs-dismiss="modal">Annuller</button>
                    </div>
                </div></div>`;
                document.body.appendChild(el);
            }
            document.getElementById('relQaModalTitle').innerHTML = title;
            document.getElementById('relQaModalBody').innerHTML = bodyHtml;
            const footer = document.getElementById('relQaModalFooter');
            // Remove old action buttons (keep Annuller)
            footer.querySelectorAll('.btn-primary').forEach(b => b.remove());
            if (footerBtns) footer.insertAdjacentHTML('afterbegin', footerBtns);
            new bootstrap.Modal(el).show();
        };

        // ── init on page load ─────────────────────────────────────────────
        document.addEventListener('DOMContentLoaded', loadAllRelationTags);

    })();
    </script>

    <!-- ── Case tags resilient bootstrap ─────────────────────────────────── -->
    <script>
    (function () {
        function getCaseIdFromPath() {
            const match = String(window.location.pathname || '').match(/\/sag\/(\d+)/);
            return match ? Number(match[1]) : null;
        }

        function escapeHtml(value) {
            return String(value || '')
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#39;');
        }

        async function loadCaseTagsFallback(caseId) {
            const moduleContainer = document.getElementById('case-tags-module');
            if (!moduleContainer || !caseId) return;

            try {
                let tags = [];
                const genericResponse = await fetch(`/api/v1/tags/entity/case/${caseId}`, { credentials: 'include' });
                if (genericResponse.ok) {
                    tags = await genericResponse.json();
                }

                if (!Array.isArray(tags) || tags.length === 0) {
                    const legacyResponse = await fetch(`/api/v1/sag/${caseId}/tags`, { credentials: 'include' });
                    if (legacyResponse.ok) {
                        const legacyRows = await legacyResponse.json();
                        tags = (Array.isArray(legacyRows) ? legacyRows : []).map((row) => ({
                            id: row.id || row.tag_id,
                            name: row.tag_navn || row.name || 'Tag',
                            color: row.color || '#0f4c75',
                            icon: row.icon || 'bi-tag'
                        }));
                    }
                }

                if (!Array.isArray(tags) || tags.length === 0) {
                    moduleContainer.innerHTML = '<div class="p-3 text-center text-muted small">Ingen tags paa sagen endnu</div>';
                    return;
                }

                moduleContainer.innerHTML = tags.map((tag) => `
                    <span class="badge me-1 mb-1" style="background-color: ${tag.color || '#0f4c75'};">
                        ${tag.icon ? `<i class="bi ${tag.icon}"></i> ` : ''}${escapeHtml(tag.name)}
                    </span>
                `).join('');
            } catch (error) {
                console.error('Case tags fallback failed:', error);
                moduleContainer.innerHTML = '<div class="p-3 text-center text-danger small">Fejl ved hentning af tags</div>';
            }
        }

        function maybeOpenTemplateModal(tag, addResult, caseId) {
            const actionType = addResult && addResult.action ? addResult.action.type : null;
            const shouldOpen = actionType === 'open_task_template_modal'
                || String((tag && tag.name) || '').toLowerCase() === 'opgave_template';

            if (shouldOpen && typeof window.openTaskTemplateSelectorModal === 'function') {
                window.openTaskTemplateSelectorModal({
                    action: addResult ? addResult.action : null,
                    entity_type: 'case',
                    entity_id: caseId,
                });
            }
        }

        function wireTagsPlusButton(caseId) {
            const tagsCard = document.querySelector('.right-module-card[data-module="tags"]');
            const plusBtn = tagsCard ? tagsCard.querySelector('button.btn.btn-sm.btn-outline-primary') : null;
            if (!plusBtn || !caseId) return;

            plusBtn.onclick = function (event) {
                event.preventDefault();
                event.stopPropagation();
                if (typeof window.showTagPicker !== 'function') return false;

                window.showTagPicker('case', caseId, async function (tag, addResult) {
                    await loadCaseTagsFallback(caseId);
                    maybeOpenTemplateModal(tag, addResult, caseId);
                });
                return false;
            };
        }

        let initialized = false;

        function initCaseTagsFallback() {
            if (initialized) return;
            initialized = true;

            const caseId = getCaseIdFromPath();
            if (!caseId) return;

            loadCaseTagsFallback(caseId);
            wireTagsPlusButton(caseId);

            if (typeof window.setTagPickerContext === 'function') {
                window.setTagPickerContext('case', caseId, async function (tag, addResult) {
                    await loadCaseTagsFallback(caseId);
                    maybeOpenTemplateModal(tag, addResult, caseId);
                });
            }

            window.__caseTagsFallbackReady = true;
        }

        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', initCaseTagsFallback, { once: true });
        } else {
            initCaseTagsFallback();
        }

        window.addEventListener('pageshow', initCaseTagsFallback, { once: true });
    })();
    </script>

    <!-- ── Beskrivelse inline editor ───────────────────────────────────────── -->
    <script>
    (function () {
        const SAG_ID = {{ case.id }};
        let _historyLoaded = false;

        window.rewriteCaseDescriptionWithApproval = async function () {
            const ta = document.getElementById('beskrivelse-textarea');
            const rewriteBtn = document.getElementById('beskrivelse-rewrite-btn');
            if (!ta) return;

            const source = (ta.value || '').trim();
            if (!source) {
                if (typeof showNotification === 'function') showNotification('Skriv en beskrivelse først', 'warning');
                else alert('Skriv en beskrivelse først');
                return;
            }

            const originalHtml = rewriteBtn?.innerHTML || '';
            if (rewriteBtn) {
                rewriteBtn.disabled = true;
                rewriteBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Renskriver...';
            }

            try {
                const rewriteEndpoints = ['/api/v1/rewrite-text', '/api/v1/sag/rewrite-text', '/api/v1/emails/rewrite-text'];
                let payload = null;
                let lastError = null;

                for (const endpoint of rewriteEndpoints) {
                    const response = await fetch(endpoint, {
                        method: 'POST',
                        credentials: 'include',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ text: source, context: 'case' })
                    });

                    if (response.ok) {
                        payload = await response.json();
                        lastError = null;
                        break;
                    }

                    let detail = `HTTP ${response.status}`;
                    try {
                        const err = await response.json();
                        if (err?.detail) detail = err.detail;
                    } catch (_) {}

                    lastError = new Error(detail);

                    // Retry next endpoint for common route mismatch cases.
                    if (![404, 405].includes(response.status)) {
                        break;
                    }
                }

                if (!payload) {
                    throw lastError || new Error('Kunne ikke hente renskrivningsforslag');
                }

                const rewrittenRaw = String(payload?.rewritten_text || '').trim();
                const descMatch = rewrittenRaw.match(/(?:^|\n)Beskrivelse:\s*\n([\s\S]*)$/i);
                const rewritten = descMatch?.[1] ? descMatch[1].trim() : rewrittenRaw;

                openRewriteReviewModal({
                    title: 'Sagsbeskrivelse',
                    originalText: source,
                    rewrittenText: rewritten,
                    applyToTarget: (nextText) => {
                        ta.value = nextText;
                        bootstrap.Modal.getOrCreateInstance(document.getElementById('rewritePreviewModal')).hide();
                    }
                });
            } catch (e) {
                console.error(e);
                if (typeof showNotification === 'function') showNotification('Kunne ikke renskrive beskrivelse', 'error');
                else alert(`Kunne ikke renskrive beskrivelse: ${e.message || 'Ukendt fejl'}`);
            } finally {
                if (rewriteBtn) {
                    rewriteBtn.disabled = false;
                    rewriteBtn.innerHTML = originalHtml;
                }
            }
        };

        // ── Sag titel inline edit ────────────────────────────────────────────
        window.startTitelEdit = function () {
            document.getElementById('sag-titel-view').classList.add('d-none');
            document.getElementById('sag-titel-editor').classList.remove('d-none');
            const input = document.getElementById('sag-titel-input');
            input.focus();
            input.select();
        };

        window.cancelTitelEdit = function () {
            document.getElementById('sag-titel-editor').classList.add('d-none');
            document.getElementById('sag-titel-view').classList.remove('d-none');
        };

        window.saveTitelEdit = async function () {
            const input = document.getElementById('sag-titel-input');
            const saveBtn = document.getElementById('sag-titel-save-btn');
            const newVal = input.value.trim();
            if (!newVal) { alert('Overskrift må ikke være tom.'); return; }
            if (saveBtn) { saveBtn.disabled = true; saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Gemmer...'; }
            try {
                const res = await fetch(`/api/v1/sag/${caseIds}`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ titel: newVal })
                });
                if (!res.ok) throw new Error((await res.json()).detail || 'Fejl');
                document.getElementById('sag-titel-text').textContent = newVal;
                document.title = newVal;
                // update narrative-lead if present
                const lead = document.querySelector('.narrative-lead');
                if (lead) lead.textContent = newVal;
                cancelTitelEdit();
                if (typeof showNotification === 'function') showNotification('Overskrift gemt', 'success');
            } catch (e) {
                if (typeof showNotification === 'function') showNotification('Kunne ikke gemme overskrift: ' + e.message, 'error');
                else alert('Fejl: ' + e.message);
            } finally {
                if (saveBtn) { saveBtn.disabled = false; saveBtn.innerHTML = '<i class="bi bi-check2 me-1"></i>Gem'; }
            }
        };

        // ── Enter key closes titel edit ──────────────────────────────────────
        document.addEventListener('DOMContentLoaded', () => {
            const inp = document.getElementById('sag-titel-input');
            if (inp) {
                inp.addEventListener('keydown', e => {
                    if (e.key === 'Enter') { e.preventDefault(); saveTitelEdit(); }
                    if (e.key === 'Escape') cancelTitelEdit();
                });
            }
        });

        window.startBeskrivelsEdit = function () {
            const current = document.getElementById('beskrivelse-text').innerText.trim();
            document.getElementById('beskrivelse-textarea').value = current;
            document.getElementById('beskrivelse-view').classList.add('d-none');
            document.getElementById('beskrivelse-edit-btn')?.classList.add('d-none');
            document.getElementById('beskrivelse-editor').classList.remove('d-none');
            document.getElementById('beskrivelse-textarea').focus();
        };

        window.cancelBeskrivelsEdit = function () {
            document.getElementById('beskrivelse-editor').classList.add('d-none');
            document.getElementById('beskrivelse-view').classList.remove('d-none');
            document.getElementById('beskrivelse-edit-btn')?.classList.remove('d-none');
        };

        window.saveBeskrivelsEdit = async function () {
            const ta = document.getElementById('beskrivelse-textarea');
            const saveBtn = document.getElementById('beskrivelse-save-btn');
            const newVal = ta.value;
            if (saveBtn) { saveBtn.disabled = true; saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Gemmer...'; }
            try {
                const res = await fetch(`/api/v1/sag/${SAG_ID}/beskrivelse`, {
                    method: 'PATCH',
                    credentials: 'include',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ beskrivelse: newVal })
                });
                if (!res.ok) throw new Error(await res.text());
                const data = await res.json();
                // Update view
                const textEl = document.getElementById('beskrivelse-text');
                textEl.innerText = data.beskrivelse || '';
                const emptyEl = document.getElementById('beskrivelse-empty');
                if (emptyEl) emptyEl.style.display = data.beskrivelse ? 'none' : '';
                cancelBeskrivelsEdit();
                // Show history and mark stale
                document.getElementById('beskrivelse-history-wrap').classList.remove('d-none');
                _historyLoaded = false;
                if (typeof showNotification === 'function') showNotification('Beskrivelse gemt', 'success');
            } catch (e) {
                console.error(e);
                if (typeof showNotification === 'function') showNotification('Kunne ikke gemme beskrivelse', 'error');
            } finally {
                if (saveBtn) { saveBtn.disabled = false; saveBtn.innerHTML = '<i class="bi bi-check2 me-1"></i>Gem'; }
            }
        };

        window.loadBeskrivelsHistory = async function () {
            if (_historyLoaded) return;
            const list = document.getElementById('beskrivelse-history-list');
            try {
                const res = await fetch(`/api/v1/sag/${SAG_ID}/beskrivelse/history`, { credentials: 'include' });
                if (!res.ok) throw new Error('failed');
                const rows = await res.json();
                _historyLoaded = true;
                const label = document.getElementById('beskrivelse-history-label');
                if (!rows.length) {
                    label.textContent = 'Historik (0)';
                    list.innerHTML = '<div class="list-group-item text-muted text-center py-2 small">Ingen historik endnu.</div>';
                    return;
                }
                label.textContent = `Historik (${rows.length})`;
                const esc = s => String(s || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
                const trunc = (s, n) => s && s.length > n ? s.substring(0, n) + '…' : (s || '');
                list.innerHTML = rows.map(h => {
                    const d = new Date(h.changed_at);
                    const when = d.toLocaleDateString('da-DK', {day:'2-digit',month:'2-digit',year:'numeric'})
                               + ' ' + d.toLocaleTimeString('da-DK', {hour:'2-digit',minute:'2-digit'});
                    const who = esc(h.changed_by_name || 'Ukendt');
                    const before = h.beskrivelse_before ? esc(trunc(h.beskrivelse_before, 150)) : '<em class="text-muted">tom</em>';
                    const after  = h.beskrivelse_after  ? esc(trunc(h.beskrivelse_after,  150)) : '<em class="text-muted">tom</em>';
                    return `<div class="list-group-item px-3 py-2">
                        <div class="d-flex justify-content-between mb-1">
                            <span class="fw-semibold small">${who}</span>
                            <span class="text-muted small">${when}</span>
                        </div>
                        <div class="d-flex gap-3" style="font-size:.85rem">
                            <div style="flex:1"><span class="badge text-bg-danger me-1" style="font-size:.7rem">Før</span>${before}</div>
                            <div style="flex:1"><span class="badge text-bg-success me-1" style="font-size:.7rem">Efter</span>${after}</div>
                        </div>
                    </div>`;
                }).join('');
            } catch (e) {
                list.innerHTML = '<div class="list-group-item text-muted text-center py-2 small">Kunne ikke indlæse historik.</div>';
            }
        };

        // Keyboard shortcuts
        document.addEventListener('keydown', function (e) {
            const editor = document.getElementById('beskrivelse-editor');
            if (!editor || editor.classList.contains('d-none')) return;
            if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); saveBeskrivelsEdit(); }
            if (e.key === 'Escape') { e.preventDefault(); cancelBeskrivelsEdit(); }
        });

        // Show history toggle if description already exists on page load
        if ((document.getElementById('beskrivelse-text').innerText || '').trim()) {
            document.getElementById('beskrivelse-history-wrap').classList.remove('d-none');
        }
    })();
    </script>

</div>
{% endblock %}
