{% extends '@MauticCore/Default/content.html.twig' %}

{% block headerTitle deal.getTitle() %}

{% block preHeader %}
    <nav style="font-size:12px;color:#5e6278;">
        <a href="{{ path('mautic_dealflow_index') }}" data-toggle="ajax" style="color:#5e6278;">Deals</a>
        <span style="margin:0 5px;">&rsaquo;</span>
        {% if deal.getPipeline() %}
            <a href="{{ path('mautic_dealflow_pipeline', {'pipelineId': deal.getPipeline().getId()}) }}" data-toggle="ajax" style="color:#5e6278;">{{ deal.getPipeline().getName() }}</a>
            <span style="margin:0 5px;">&rsaquo;</span>
        {% endif %}
        <span>{{ deal.getTitle() }}</span>
    </nav>
{% endblock %}

{% block indexButton %}
    <nav style="font-size:12px;color:#5e6278;">
        <a href="{{ path('mautic_dealflow_index') }}" data-toggle="ajax" style="color:#5e6278;">Deals</a>
        <span style="margin:0 5px;">&rsaquo;</span>
        {% if deal.getPipeline() %}
            <a href="{{ path('mautic_dealflow_pipeline', {'pipelineId': deal.getPipeline().getId()}) }}" data-toggle="ajax" style="color:#5e6278;">{{ deal.getPipeline().getName() }}</a>
            <span style="margin:0 5px;">&rsaquo;</span>
        {% endif %}
        <span>{{ deal.getTitle() }}</span>
    </nav>
{% endblock %}

{% block actions %}
    <style>
        .dv-action-btn {
            display: inline-flex; align-items: center; gap: 5px;
            padding: 6px 14px; font-size: 12px; font-weight: 600;
            border: 1px solid #d0d3da; border-radius: 4px; cursor: pointer;
            background: #fff; color: #1a1a2e; white-space: nowrap;
            text-decoration: none; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            transition: background 0.15s, border-color 0.15s;
        }
        .dv-action-btn:hover { background: #f4f5f7; border-color: var(--button-primary); color: #1a1a2e; text-decoration: none; }
        .dv-action-btn-primary {
            background: var(--button-primary); color: #fff; border-color: var(--button-primary);
        }
        .dv-action-btn-primary:hover { background: color-mix(in srgb, var(--button-primary) 80%, #000); border-color: color-mix(in srgb, var(--button-primary) 80%, #000); color: #fff; text-decoration: none; }
        .dv-action-btn-danger {
            color: #c5221f; border-color: #c5221f;
        }
        .dv-action-btn-danger:hover { background: #fce8e6; }
    </style>
    <div style="display:flex;gap:8px;align-items:center;">
        {% if canEditDeal %}
            <button class="dv-action-btn" type="button" onclick="mQuery('#dealflowAddNote').modal('show');">+ Add Note</button>
            <button class="dv-action-btn" type="button" onclick="mQuery('#dealflowAddTask').modal('show');">+ Add Task</button>
            <a class="dv-action-btn dv-action-btn-primary" href="{{ path('mautic_dealflow_edit', {'objectId': deal.getId()}) }}" data-toggle="ajax">Edit Deal</a>
            <button class="dv-action-btn dv-action-btn-danger" type="button" onclick="mQuery('#dealflowDeleteDeal').modal('show');">Delete</button>
        {% endif %}
    </div>
{% endblock %}

{% block content %}
    {{ include('@DealFlow/_styles.html.twig') }}

    {# ======= Compute health signals in Twig ======= #}
    {% set updatedDaysAgo = deal.getDateModified() ? date().diff(deal.getDateModified()).days : date().diff(deal.getDateAdded()).days %}
    {% set updatedColor = updatedDaysAgo < 3 ? 'green' : (updatedDaysAgo <= 7 ? 'yellow' : 'red') %}

    {% set hasCloseDate = deal.getExpectedCloseDate() is not null %}
    {% if hasCloseDate %}
        {% set daysToCloseRaw = date().diff(deal.getExpectedCloseDate()).days %}
        {% set closeInPast = deal.getExpectedCloseDate() < date() %}
        {% set daysToClose = closeInPast ? 0 - daysToCloseRaw : daysToCloseRaw %}
        {% set closeColor = daysToClose > 30 ? 'green' : (daysToClose >= 14 ? 'yellow' : 'red') %}
    {% endif %}

    {% set overdueTasks = [] %}
    {% set openTasks = [] %}
    {% set completedTasks = [] %}
    {% for task in deal.getTasks() %}
        {% if task.getStatus() == 'completed' %}
            {% set completedTasks = completedTasks|merge([task]) %}
        {% else %}
            {% set openTasks = openTasks|merge([task]) %}
            {% if task.getDueAt() and task.getDueAt() < date() %}
                {% set overdueTasks = overdueTasks|merge([task]) %}
            {% endif %}
        {% endif %}
    {% endfor %}

    {% set overdueCount = overdueTasks|length %}
    {% set overdueColor = overdueCount > 0 ? 'red' : 'green' %}

    {% set confidence = deal.getConfidence() %}
    {% set confidenceColor = confidence is not null ? (confidence > 70 ? 'green' : (confidence >= 40 ? 'yellow' : 'red')) : 'gray' %}

    {# Determine current stage index for stage bar #}
    {% set currentStageId = deal.getStage() ? deal.getStage().getId() : null %}
    {% set currentStageIndex = -1 %}
    {% for stage in stages %}
        {% if stage.getId() == currentStageId %}
            {% set currentStageIndex = loop.index0 %}
        {% endif %}
    {% endfor %}

    <style>
        /* === Deal View: Design V2 — matching approved mockup === */
        /* Override Mautic theme vars within our scope to match approved design */
        .dealflow-view {
            --layer-01: #ffffff;
            --layer-02: #f4f5f7;
            --text-primary: #1a1a2e;
            --text-secondary: #5e6278;
            --border-subtle-01: #e1e3e8;
            --border-subtle-02: #d0d3da;
            --background: #f0f1f3;
            --field-01: #ffffff;
            /* button-primary, link-primary, border-interactive inherited from Mautic theme */
            --label-background-blue: #e8f0fe;
            --label-color-blue: #1a56db;
            --label-background-green: #e6f4ea;
            --label-color-green: #137333;
            --label-background-red: #fce8e6;
            --label-color-red: #c5221f;
            --label-background-gray: #f1f3f4;
            --label-color-gray: #5f6368;
            /* Accent colors derived from Mautic theme */
            --red: #c5221f;
            --yellow: #e8a317;
            --green: #137333;
        }

        /* === Mautic cascade overrides === */
        .dealflow-view,
        .dealflow-view * {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            box-sizing: border-box;
        }
        .dealflow-view h1,
        .dealflow-view h2,
        .dealflow-view h3,
        .dealflow-view h4,
        .dealflow-view p {
            margin-top: 0;
            margin-bottom: 0;
        }
        .dealflow-view ul,
        .dealflow-view ol {
            list-style: none;
            margin: 0;
            padding: 0;
        }
        .dealflow-view a {
            color: var(--link-primary);
            text-decoration: none;
        }
        .dealflow-view a:hover {
            color: color-mix(in srgb, var(--link-primary) 80%, #000);
            text-decoration: underline;
        }

        /* Page Header */
        .dv-page-header {
            padding: 0 0 4px 15px;
            margin: -10px 0 0;
        }
        .dv-breadcrumb {
            font-size: 12px;
            color: var(--text-secondary);
            margin-bottom: 8px;
        }
        .dv-breadcrumb a { color: var(--text-secondary); text-decoration: none; }
        .dv-breadcrumb a:hover { color: var(--link-primary); text-decoration: underline; }
        .dv-breadcrumb .dv-sep { margin: 0 5px; }

        .dv-header-row {
            display: flex;
            align-items: flex-start;
            justify-content: space-between;
            gap: 16px;
            flex-wrap: wrap;
        }
        .dv-header-left { flex: 1; min-width: 0; }
        .dv-header-left h1 {
            font-size: 20px;
            font-weight: 700;
            line-height: 1.3;
            margin: 0 0 4px;
        }
        .dv-header-meta {
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
            font-size: 12px;
            color: var(--text-secondary);
            align-items: center;
        }
        .dv-header-meta .dv-amount {
            font-size: 16px;
            font-weight: 700;
            color: var(--text-primary);
        }
        .dv-header-actions {
            display: flex;
            gap: 8px;
            flex-shrink: 0;
            align-items: flex-start;
        }

        /* Buttons */
        .dv-btn {
            display: inline-flex;
            align-items: center;
            gap: 5px;
            padding: 6px 14px;
            font-size: 12px;
            font-weight: 600;
            border: 1px solid var(--border-subtle-02);
            border-radius: 4px;
            cursor: pointer;
            background: var(--layer-01);
            color: var(--text-primary);
            white-space: nowrap;
            transition: background 0.15s, border-color 0.15s;
            font-family: inherit;
            text-decoration: none;
        }
        .dv-btn:hover { background: var(--layer-02); border-color: var(--border-interactive); text-decoration: none; color: var(--text-primary); }
        .dv-btn-primary {
            background: var(--button-primary);
            color: #fff;
            border-color: var(--button-primary);
        }
        .dv-btn-primary:hover { background: color-mix(in srgb, var(--button-primary) 80%, #000); border-color: color-mix(in srgb, var(--button-primary) 80%, #000); color: #fff; }
        .dv-btn-sm { padding: 4px 10px; font-size: 11px; }
        .dv-btn-danger { color: var(--red); border-color: var(--red); }
        .dv-btn-danger:hover { background: var(--label-background-red); }

        /* Badges */
        .dv-badge {
            display: inline-block;
            padding: 2px 8px;
            border-radius: 3px;
            font-size: 11px;
            font-weight: 600;
            line-height: 1.5;
        }
        .dv-badge-green { background: var(--label-background-green); color: var(--label-color-green); }
        .dv-badge-blue { background: var(--label-background-blue); color: var(--label-color-blue); }
        .dv-badge-red { background: var(--label-background-red); color: var(--label-color-red); }
        .dv-badge-gray { background: var(--label-background-gray); color: var(--label-color-gray); }
        .dv-badge-yellow { background: #fef3cd; color: #856404; }

        /* Stage Pipeline Bar */
        .dv-stage-bar-wrapper {
            padding: 6px 0 6px 15px;
            margin-bottom: 8px;
        }
        .dv-stage-bar {
            display: flex;
            gap: 2px;
        }
        .dv-stage-bar .dv-stage {
            flex: 1;
            text-align: center;
            padding: 6px 4px;
            font-size: 11px;
            font-weight: 600;
            background: var(--layer-02);
            color: var(--text-secondary);
            cursor: pointer;
            position: relative;
            transition: background 0.15s, color 0.15s;
            border: 1px solid transparent;
            user-select: none;
        }
        .dv-stage-bar .dv-stage:first-child { border-radius: 4px 0 0 4px; }
        .dv-stage-bar .dv-stage:last-child { border-radius: 0 4px 4px 0; }
        .dv-stage-bar .dv-stage:hover {
            background: color-mix(in srgb, var(--button-primary) 10%, #fff);
            color: var(--button-primary);
            border-color: var(--border-interactive);
        }
        .dv-stage-bar .dv-stage.dv-completed {
            background: var(--button-primary);
            color: #fff;
        }
        .dv-stage-bar .dv-stage.dv-completed:hover {
            background: color-mix(in srgb, var(--button-primary) 80%, #000);
            color: #fff;
            border-color: color-mix(in srgb, var(--button-primary) 80%, #000);
        }
        .dv-stage-bar .dv-stage.dv-current {
            background: var(--button-primary);
            color: #fff;
            box-shadow: 0 0 0 2px var(--button-primary), 0 0 0 4px color-mix(in srgb, var(--button-primary) 10%, #fff);
        }
        .dv-stage-bar .dv-stage.dv-current:hover {
            background: color-mix(in srgb, var(--button-primary) 80%, #000);
        }
        /* Mobile: dropdown instead of bar */
        .dv-stage-dropdown { display: none; }
        @media (max-width: 600px) {
            .dv-stage-bar { display: none; }
            .dv-stage-dropdown {
                display: block;
                font-size: 13px;
                color: var(--text-primary);
            }
            .dv-stage-dropdown select {
                padding: 6px 10px;
                border: 1px solid var(--border-subtle-02);
                border-radius: 4px;
                background: var(--field-01);
                font-size: 13px;
                color: var(--text-primary);
                margin-left: 6px;
            }
        }

        /* Overdue Alert */
        .dv-overdue-alert {
            background: var(--label-background-red);
            border: 1px solid #f5c6c4;
            border-radius: 4px;
            padding: 8px 14px;
            margin: 12px 20px 0;
            font-size: 12px;
            font-weight: 600;
            color: var(--label-color-red);
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 6px;
            transition: background 0.15s;
            max-width: fit-content;
        }
        .dv-overdue-alert:hover { background: #f9d6d5; }
        .dv-overdue-alert .dv-chevron-icon {
            transition: transform 0.2s;
            font-size: 10px;
        }
        .dv-overdue-alert.dv-expanded .dv-chevron-icon { transform: rotate(90deg); }
        .dv-overdue-tasks-detail {
            max-height: 0;
            overflow: hidden;
            transition: max-height 0.3s ease;
            margin: 0 20px;
        }
        .dv-overdue-tasks-detail.dv-open { max-height: 300px; }
        .dv-overdue-tasks-detail .dv-overdue-task-item {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 8px 14px;
            background: var(--layer-01);
            border: 1px solid #f5c6c4;
            border-top: none;
            font-size: 12px;
        }
        .dv-overdue-tasks-detail .dv-overdue-task-item:first-child { border-top: 1px solid #f5c6c4; margin-top: 4px; border-radius: 4px 4px 0 0; }
        .dv-overdue-tasks-detail .dv-overdue-task-item:last-child { border-radius: 0 0 4px 4px; }
        .dv-overdue-task-item .dv-task-name { font-weight: 600; color: var(--red); }
        .dv-overdue-task-item .dv-task-due { color: var(--text-secondary); margin-left: 12px; }

        /* Two-column layout */
        .dv-content-wrap {
            display: flex;
            gap: 16px;
            padding: 8px 0 0 15px;
            align-items: flex-start;
        }
        .dv-col-main { flex: 7; min-width: 0; }
        .dv-col-side { flex: 3; min-width: 260px; max-width: 340px; }

        @media (max-width: 900px) {
            .dv-content-wrap { flex-direction: column; }
            .dv-col-main, .dv-col-side { flex: none; width: 100%; max-width: 100%; min-width: 0; }
        }

        /* Card/Section */
        .dv-card {
            background: var(--layer-01);
            border: 1px solid var(--border-subtle-01);
            border-radius: 6px;
            margin-bottom: 12px;
        }
        .dv-card-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 10px 14px;
            border-bottom: 1px solid var(--border-subtle-01);
            cursor: pointer;
            user-select: none;
            transition: background 0.1s;
        }
        .dv-card-header:hover { background: var(--layer-02); }
        .dv-card-header h3 {
            font-size: 12px;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            color: var(--text-secondary);
            display: flex;
            align-items: center;
            gap: 6px;
            margin: 0;
        }
        .dv-card-header .dv-count {
            font-weight: 400;
            color: var(--text-secondary);
            font-size: 11px;
        }
        .dv-card-header-actions {
            display: flex;
            gap: 6px;
            align-items: center;
        }
        .dv-chevron {
            display: inline-block;
            width: 16px;
            height: 16px;
            transition: transform 0.25s ease;
            color: var(--text-secondary);
            flex-shrink: 0;
        }
        .dv-chevron svg { display: block; }
        .dv-card.dv-collapsed .dv-chevron { transform: rotate(-90deg); }
        .dv-card-body {
            padding: 12px 14px;
            overflow: hidden;
            transition: max-height 0.3s ease, padding 0.3s ease, opacity 0.2s ease;
            opacity: 1;
        }
        .dv-card:not(.dv-collapsed) .dv-card-body {
            overflow: visible;
        }
        .dv-card.dv-collapsed .dv-card-body {
            max-height: 0 !important;
            padding-top: 0;
            padding-bottom: 0;
            opacity: 0;
            overflow: hidden;
        }

        /* Health Signals */
        .dv-health-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 8px;
        }
        .dv-health-item {
            padding: 8px 10px;
            border-radius: 4px;
            background: var(--layer-02);
        }
        .dv-health-item .dv-label {
            font-size: 10px;
            text-transform: uppercase;
            letter-spacing: 0.4px;
            color: var(--text-secondary);
            margin-bottom: 2px;
        }
        .dv-health-item .dv-value {
            font-size: 14px;
            font-weight: 700;
        }
        .dv-health-item .dv-value.dv-green { color: var(--green); }
        .dv-health-item .dv-value.dv-yellow { color: var(--yellow); }
        .dv-health-item .dv-value.dv-red { color: var(--red); }
        .dv-health-item .dv-value.dv-gray { color: var(--text-secondary); }

        /* Detail list */
        .dv-detail-list { list-style: none; margin: 0; padding: 0; }
        .dv-detail-list li {
            display: flex;
            justify-content: space-between;
            padding: 5px 0;
            border-bottom: 1px solid var(--border-subtle-01);
            font-size: 12px;
        }
        .dv-detail-list li:last-child { border-bottom: none; }
        .dv-detail-list .dv-dl-label { color: var(--text-secondary); flex-shrink: 0; margin-right: 12px; }
        .dv-detail-list .dv-dl-value { text-align: right; font-weight: 500; word-break: break-word; }

        /* Description */
        .dv-description-text {
            font-size: 13px;
            line-height: 1.6;
            color: var(--text-primary);
            white-space: pre-line;
        }

        /* Buying Committee */
        .dv-committee-table {
            width: 100%;
            border-collapse: collapse;
            font-size: 12px;
        }
        .dv-committee-table th {
            text-align: left;
            padding: 6px 8px;
            font-size: 10px;
            text-transform: uppercase;
            letter-spacing: 0.4px;
            color: var(--text-secondary);
            background: var(--layer-02);
            border-bottom: 1px solid var(--border-subtle-01);
        }
        .dv-committee-table td {
            padding: 8px 8px;
            border-bottom: 1px solid var(--border-subtle-01);
            vertical-align: middle;
        }
        .dv-committee-table tr:last-child td { border-bottom: none; }
        .dv-committee-table tr:hover { background: var(--layer-02); }
        .dv-committee-table .dv-contact-name a { font-weight: 600; color: var(--link-primary); text-decoration: none; }
        .dv-committee-table .dv-contact-name a:hover { text-decoration: underline; }
        .dv-committee-table .dv-contact-email { color: var(--text-secondary); font-size: 11px; }
        .dv-committee-table .dv-contact-date { color: var(--text-secondary); font-size: 11px; white-space: nowrap; }

        /* Tasks */
        .dv-task-list { list-style: none; margin: 0; padding: 0; }
        .dv-task-item {
            display: flex;
            align-items: flex-start;
            gap: 8px;
            padding: 8px 0;
            border-bottom: 1px solid var(--border-subtle-01);
            font-size: 12px;
        }
        .dv-task-item:last-child { border-bottom: none; }
        .dv-task-checkbox {
            width: 14px;
            height: 14px;
            border: 2px solid var(--border-subtle-02);
            border-radius: 3px;
            flex-shrink: 0;
            margin-top: 2px;
            cursor: pointer;
        }
        .dv-task-item.dv-completed-task .dv-task-checkbox {
            background: var(--button-primary);
            border-color: var(--button-primary);
            position: relative;
        }
        .dv-task-item.dv-completed-task .dv-task-checkbox::after {
            content: "\2713";
            color: #fff;
            font-size: 10px;
            position: absolute;
            top: -1px;
            left: 1px;
        }
        .dv-task-content { flex: 1; min-width: 0; }
        .dv-task-title { font-weight: 500; }
        .dv-task-item.dv-completed-task .dv-task-title {
            text-decoration: line-through;
            color: var(--text-secondary);
        }
        .dv-task-meta {
            display: flex;
            gap: 8px;
            font-size: 11px;
            color: var(--text-secondary);
            margin-top: 2px;
            flex-wrap: wrap;
            align-items: center;
        }
        .dv-task-due-overdue { color: var(--red); font-weight: 600; }
        .dv-completed-tasks-wrapper {
            display: none;
            border-top: 1px solid var(--border-subtle-01);
            padding-top: 4px;
            margin-top: 4px;
        }
        .dv-completed-tasks-wrapper.dv-visible { display: block; }
        .dv-completed-tasks-wrapper .dv-task-item { opacity: 0.6; }
        .dv-show-completed-link {
            display: inline-block;
            font-size: 11px;
            color: var(--link-primary);
            cursor: pointer;
            padding: 6px 0 0;
            border: none;
            background: none;
            font-family: inherit;
        }
        .dv-show-completed-link:hover { text-decoration: underline; }

        /* Notes */
        .dv-note-item {
            padding: 10px 0;
            border-bottom: 1px solid var(--border-subtle-01);
        }
        .dv-note-item:last-child { border-bottom: none; }
        .dv-note-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 4px;
        }
        .dv-note-date { font-size: 11px; color: var(--text-secondary); }
        .dv-note-author { font-size: 11px; font-weight: 600; }
        .dv-note-body {
            font-size: 12px;
            line-height: 1.6;
            color: var(--text-primary);
        }
        .dv-note-body.dv-truncated {
            display: -webkit-box;
            -webkit-line-clamp: 3;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }
        .dv-note-body a { color: var(--link-primary); text-decoration: underline; }
        .dv-note-body b, .dv-note-body strong { font-weight: 600; }
        .dv-show-more-note {
            font-size: 11px;
            color: var(--link-primary);
            cursor: pointer;
            border: none;
            background: none;
            padding: 2px 0 0;
            font-family: inherit;
        }
        .dv-show-more-note:hover { text-decoration: underline; }
        .dv-note-edit-icon {
            opacity: 0;
            transition: opacity 0.15s;
            color: var(--text-secondary);
            cursor: pointer;
            background: none;
            border: none;
            font-size: 13px;
            padding: 2px 4px;
            margin-left: 8px;
            flex-shrink: 0;
        }
        .dv-note-item:hover .dv-note-edit-icon { opacity: 1; }

        /* Activity */
        .dv-activity-list { list-style: none; margin: 0; padding: 0; }
        .dv-activity-item {
            padding: 7px 0;
            border-bottom: 1px solid var(--border-subtle-01);
            font-size: 12px;
            display: flex;
            justify-content: space-between;
            gap: 12px;
        }
        .dv-activity-item:last-child { border-bottom: none; }
        .dv-activity-desc { flex: 1; }
        .dv-activity-desc .dv-action { font-weight: 600; }
        .dv-activity-desc .dv-transition { color: var(--text-secondary); }
        .dv-activity-time { color: var(--text-secondary); font-size: 11px; white-space: nowrap; }
        .dv-show-all-link {
            display: inline-block;
            font-size: 11px;
            color: var(--link-primary);
            cursor: pointer;
            padding: 6px 0 0;
            border: none;
            background: none;
            font-family: inherit;
        }
        .dv-show-all-link:hover { text-decoration: underline; }

        /* Files */
        .dv-file-list { list-style: none; margin: 0; padding: 0; }
        .dv-file-item {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 7px 0;
            border-bottom: 1px solid var(--border-subtle-01);
            font-size: 12px;
        }
        .dv-file-item:last-child { border-bottom: none; }
        .dv-file-icon { margin-right: 8px; font-size: 14px; flex-shrink: 0; }
        .dv-file-info { flex: 1; min-width: 0; }
        .dv-file-name a { font-weight: 500; color: var(--link-primary); text-decoration: none; }
        .dv-file-name a:hover { text-decoration: underline; }
        .dv-file-meta { font-size: 11px; color: var(--text-secondary); }
        .dv-file-actions { flex-shrink: 0; margin-left: 8px; }
        .dv-file-upload-area {
            border: 2px dashed var(--border-subtle-02);
            border-radius: 4px;
            padding: 12px;
            text-align: center;
            color: var(--text-secondary);
            font-size: 12px;
            margin-top: 8px;
            cursor: pointer;
            transition: border-color 0.15s, background 0.15s;
        }
        .dv-file-upload-area:hover {
            border-color: var(--border-interactive);
            background: color-mix(in srgb, var(--button-primary) 10%, #fff);
        }

        /* Associate contact form */
        .dv-associate-form {
            border-bottom: 1px solid var(--border-subtle-01);
            margin-bottom: 12px;
            padding-bottom: 12px;
        }

        /* Inline editing */
        .dv-inline-editable { cursor: pointer; border-bottom: 1px dashed var(--border-subtle-01); }
        .dv-inline-editable:hover { background: var(--layer-02); }
        .dv-inline-editing { border-bottom: none; }
        .dv-inline-editing input, .dv-inline-editing select {
            width: 100%; padding: 2px 4px; font-size: 12px; border: 1px solid var(--border-interactive, #0d6efd); border-radius: 3px;
        }

        /* Delete modal */
        .dv-delete-input {
            background: var(--field-01);
            border: 1px solid var(--border-subtle-02);
            border-radius: 4px;
            color: var(--text-primary);
            font-size: 14px;
            padding: 6px 10px;
            width: 100%;
            margin-top: 8px;
        }

        /* Print */
        @media print {
            body { background: #fff; font-size: 11px; }
            .dv-page-header { border-bottom: 2px solid #000; padding: 8px 0; }
            .dv-header-actions, .dv-btn, .dv-stage-bar-wrapper, .dv-overdue-alert, .dv-overdue-tasks-detail,
            .dv-file-upload-area, .dv-show-completed-link, .dv-show-more-note, .dv-show-all-link,
            .dv-card-header-actions .dv-btn, .dv-chevron, .dv-note-edit-icon { display: none !important; }
            .dv-content-wrap { flex-direction: column; padding: 0; gap: 8px; }
            .dv-col-side { max-width: 100%; }
            .dv-card { break-inside: avoid; border: 1px solid #ccc; margin-bottom: 8px; }
            .dv-card.dv-collapsed .dv-card-body { max-height: none !important; opacity: 1 !important; padding: 8px 14px !important; }
            .dv-note-body.dv-truncated { -webkit-line-clamp: unset; overflow: visible; }
            .dv-completed-tasks-wrapper { display: block !important; opacity: 0.6; }
            .dv-stage-dropdown { display: none; }
            a { color: #000 !important; text-decoration: none !important; }
            .dv-badge { border: 1px solid #999; }
        }
    </style>

    <div class="dealflow-view">

        {# ======= Page Header (meta row only — title/breadcrumb in Mautic chrome) ======= #}
        <div class="dv-page-header">
            <div class="dv-header-row">
                <div class="dv-header-left">
                    <div class="dv-header-meta">
                        <span class="dv-amount">{{ include('@DealFlow/Deal/_amount.html.twig', {amount: deal.getAmount(), currency: deal.getCurrency()}, false) }}</span>
                        {% set statusBadge = deal.getStatus() == 'lost' ? 'dv-badge-red' : 'dv-badge-green' %}
                        <span class="dv-badge {{ statusBadge }}">{{ deal.getStatus()|capitalize }}</span>
                        {% if dealContext.companyName %}
                            <span>{{ dealContext.companyName }}</span>
                        {% endif %}
                        {% if dealContext.ownerName %}
                            <span>Owner: {{ dealContext.ownerName }}</span>
                        {% endif %}
                    </div>
                </div>
                <div class="dv-header-actions">
                </div>
            </div>
        </div>

        {# ======= Stage Pipeline Bar ======= #}
        {% if stages|length > 0 %}
            <div class="dv-stage-bar-wrapper">
                <div class="dv-stage-bar" role="navigation" aria-label="Pipeline stages">
                    {% for stage in stages %}
                        {% set stageClass = '' %}
                        {% if currentStageIndex >= 0 and loop.index0 < currentStageIndex %}
                            {% set stageClass = 'dv-completed' %}
                        {% elseif loop.index0 == currentStageIndex %}
                            {% set stageClass = 'dv-current' %}
                        {% endif %}
                        <div class="dv-stage {{ stageClass }}"
                             data-stage-id="{{ stage.getId() }}"
                             data-deal-id="{{ deal.getId() }}"
                             title="{{ loop.index0 == currentStageIndex ? 'Current stage: ' ~ stage.getName() : 'Move to ' ~ stage.getName() }}"
                             {{ loop.index0 == currentStageIndex ? 'aria-current="step"' : '' }}>
                            {{ stage.getName() }}
                        </div>
                    {% endfor %}
                </div>
                <div class="dv-stage-dropdown">
                    Stage:
                    <select aria-label="Current stage" data-deal-id="{{ deal.getId() }}" id="dvStageDropdown" class="not-chosen">
                        {% for stage in stages %}
                            <option value="{{ stage.getId() }}" {{ stage.getId() == currentStageId ? 'selected' : '' }}>{{ stage.getName() }} ({{ loop.index }} of {{ stages|length }})</option>
                        {% endfor %}
                    </select>
                </div>
            </div>
        {% endif %}

        {# ======= Overdue Alert ======= #}
        {% if overdueCount > 0 %}
            <div class="dv-overdue-alert" id="dvOverdueAlert">
                <span>&#9888;&#65039;</span>
                <span>{{ overdueCount }} overdue task{{ overdueCount > 1 ? 's' : '' }}</span>
                <span class="dv-chevron-icon">&#9656;</span>
            </div>
            <div class="dv-overdue-tasks-detail" id="dvOverdueDetail">
                {% for task in overdueTasks %}
                    <div class="dv-overdue-task-item">
                        <div>
                            <span class="dv-task-name">{{ task.getTitle() }}</span>
                            <span class="dv-task-due">&mdash; Due {{ task.getDueAt() ? task.getDueAt().format('M j') : '?' }} ({{ task.getDueAt() ? date().diff(task.getDueAt()).days : 0 }} days overdue){% if task.getOwnerId() %} &middot; {{ taskOwnerLabels[task.getOwnerId()] ?? ('User #' ~ task.getOwnerId()) }}{% endif %}</span>
                        </div>
                        {% if canEditDeal %}
                            <form class="dealflow-inline-form" method="post" action="{{ path('mautic_dealflow_task_complete', {'objectId': deal.getId(), 'taskId': task.getId()}) }}" style="margin:0;">
                                <input type="hidden" name="_token" value="{{ csrf_token('dealflow_complete_task_' ~ task.getId()) }}">
                                <button class="dv-btn dv-btn-sm" type="submit" onclick="event.stopPropagation();">Mark Done</button>
                            </form>
                        {% endif %}
                    </div>
                {% endfor %}
            </div>
        {% endif %}

        {# ======= Two-column layout ======= #}
        <div class="dv-content-wrap">

            {# ======= Main Column (70%) ======= #}
            <div class="dv-col-main">

                {# --- Description --- #}
                {% if deal.getDescription() %}
                    <div class="dv-card" id="dvCardDescription">
                        <div class="dv-card-header" onclick="DealView.toggleCard('dvCardDescription')">
                            <h3>Description <span class="dv-chevron"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 0-.708z"/></svg></span></h3>
                        </div>
                        <div class="dv-card-body">
                            <div class="dv-description-text">{{ deal.getDescription()|purify_allow_target_blank }}</div>
                        </div>
                    </div>
                {% endif %}

                {# --- Buying Committee --- #}
                <div class="dv-card" id="dvCardCommittee">
                    <div class="dv-card-header" onclick="DealView.toggleCard('dvCardCommittee')">
                        <h3>Buying Committee <span class="dv-count">({{ dealContext.contacts|length }})</span> <span class="dv-chevron"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 0-.708z"/></svg></span></h3>
                        {% if canEditDeal %}
                            <div class="dv-card-header-actions">
                                <button class="dv-btn dv-btn-sm" type="button" onclick="event.stopPropagation(); mQuery('#dealflowAssociateContact').modal('show');">+ Associate</button>
                            </div>
                        {% endif %}
                    </div>
                    <div class="dv-card-body" style="padding: 0;">
                        {% if dealContext.contacts is empty %}
                            <div style="padding: 12px 14px; color: var(--text-secondary);">No contacts associated yet.</div>
                        {% else %}
                            <table class="dv-committee-table">
                                <thead>
                                    <tr>
                                        <th>Name</th>
                                        <th>Role</th>
                                        <th>Email</th>
                                        <th>Added</th>
                                        {% if canEditDeal %}<th style="width:30px;"></th>{% endif %}
                                    </tr>
                                </thead>
                                <tbody>
                                    {% for contact in dealContext.contacts %}
                                        <tr style="cursor:pointer;" onclick="window.location.href='{{ path('mautic_contact_action', {'objectAction': 'view', 'objectId': contact.id}) }}'">
                                            <td class="dv-contact-name">
                                                <a href="{{ path('mautic_contact_action', {'objectAction': 'view', 'objectId': contact.id}) }}" data-toggle="ajax" onclick="event.stopPropagation();">{{ contact.name }}</a>
                                            </td>
                                            <td>
                                                {% if contact.label %}
                                                    {% set roleBadgeMap = {'Decision Maker': 'dv-badge-red', 'Champion': 'dv-badge-blue', 'Technical Evaluator': 'dv-badge-yellow', 'Influencer': 'dv-badge-green', 'Budget Holder': 'dv-badge-red', 'End User': 'dv-badge-blue'} %}
                                                    <span class="dv-badge {{ roleBadgeMap[contact.label] ?? 'dv-badge-gray' }}">{{ contact.label }}</span>
                                                {% else %}
                                                    <span style="color:var(--text-secondary);">&mdash;</span>
                                                {% endif %}
                                            </td>
                                            <td class="dv-contact-email">{{ contact.email ?: '&mdash;' }}</td>
                                            <td class="dv-contact-date">{{ contact.createdAt|date('M j, Y') }}</td>
                                            {% if canEditDeal %}
                                                <td style="width:30px; text-align:center;">
                                                    <button type="button" class="btn btn-xs btn-link" style="color:var(--text-secondary);padding:0;"
                                                            onclick="event.stopPropagation(); DealView.confirmDetachContact({{ contact.id }}, '{{ contact.name|default('this contact')|e('js') }}');"
                                                            title="Remove from deal">
                                                        <i class="fa fa-times"></i>
                                                    </button>
                                                </td>
                                            {% endif %}
                                        </tr>
                                    {% endfor %}
                                </tbody>
                            </table>
                        {% endif %}
                    </div>
                </div>

                {# --- Tasks --- #}
                <div class="dv-card" id="dvCardTasks">
                    <div class="dv-card-header" onclick="DealView.toggleCard('dvCardTasks')">
                        <h3>Tasks <span class="dv-count">({{ openTasks|length }} open)</span> <span class="dv-chevron"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 0-.708z"/></svg></span></h3>
                        {% if canEditDeal %}
                            <div class="dv-card-header-actions">
                                <button class="dv-btn dv-btn-sm" type="button" onclick="event.stopPropagation(); mQuery('#dealflowAddTask').modal('show');">+ Add Task</button>
                            </div>
                        {% endif %}
                    </div>
                    <div class="dv-card-body">
                        {% if openTasks is empty and completedTasks is empty %}
                            <p style="color:var(--text-secondary);margin:0;">No tasks yet.</p>
                        {% else %}
                            {# Open tasks: overdue first, then by due date #}
                            {% if openTasks is not empty %}
                                <ul class="dv-task-list">
                                    {# Overdue tasks first #}
                                    {% for task in overdueTasks %}
                                        <li class="dv-task-item">
                                            {% if canEditDeal %}
                                                <form class="dealflow-inline-form" method="post" action="{{ path('mautic_dealflow_task_complete', {'objectId': deal.getId(), 'taskId': task.getId()}) }}" style="margin:0;">
                                                    <input type="hidden" name="_token" value="{{ csrf_token('dealflow_complete_task_' ~ task.getId()) }}">
                                                    <button class="dv-task-checkbox" type="submit" title="Mark complete" onclick="event.stopPropagation();"></button>
                                                </form>
                                            {% else %}
                                                <div class="dv-task-checkbox"></div>
                                            {% endif %}
                                            <div class="dv-task-content" style="cursor:pointer;" onclick="DealView.openEditTask({{ task.getId() }}, '{{ task.getTitle()|e('js') }}', '{{ task.getPriority()|e('js') }}', '{{ task.getDueAt() ? task.getDueAt()|date('Y-m-d') : '' }}', '{{ task.getOwnerId() ?? '' }}', '{{ task.getDescription()|default('')|e('js') }}', '{{ task.getStatus()|e('js') }}');">
                                                <div class="dv-task-title">{{ task.getTitle() }}</div>
                                                <div class="dv-task-meta">
                                                    {% set priBadge = task.getPriority() == 'urgent' ? 'dv-badge-red' : (task.getPriority() == 'high' ? 'dv-badge-yellow' : 'dv-badge-gray') %}
                                                    <span class="dv-badge {{ priBadge }}" style="font-size:10px;">{{ task.getPriority()|capitalize }}</span>
                                                    <span class="dv-task-due-overdue">Due {{ task.getDueAt() ? task.getDueAt().format('M j') : '?' }} (overdue)</span>
                                                    {% if task.getOwnerId() %}
                                                        <span>{{ taskOwnerLabels[task.getOwnerId()] ?? ('User #' ~ task.getOwnerId()) }}</span>
                                                    {% endif %}
                                                </div>
                                            </div>
                                        </li>
                                    {% endfor %}
                                    {# Non-overdue open tasks #}
                                    {% for task in openTasks %}
                                        {% if not (task.getDueAt() and task.getDueAt() < date()) %}
                                            <li class="dv-task-item">
                                                {% if canEditDeal %}
                                                    <form class="dealflow-inline-form" method="post" action="{{ path('mautic_dealflow_task_complete', {'objectId': deal.getId(), 'taskId': task.getId()}) }}" style="margin:0;">
                                                        <input type="hidden" name="_token" value="{{ csrf_token('dealflow_complete_task_' ~ task.getId()) }}">
                                                        <button class="dv-task-checkbox" type="submit" title="Mark complete" onclick="event.stopPropagation();"></button>
                                                    </form>
                                                {% else %}
                                                    <div class="dv-task-checkbox"></div>
                                                {% endif %}
                                                <div class="dv-task-content" style="cursor:pointer;" onclick="DealView.openEditTask({{ task.getId() }}, '{{ task.getTitle()|e('js') }}', '{{ task.getPriority()|e('js') }}', '{{ task.getDueAt() ? task.getDueAt()|date('Y-m-d') : '' }}', '{{ task.getOwnerId() ?? '' }}', '{{ task.getDescription()|default('')|e('js') }}', '{{ task.getStatus()|e('js') }}');">
                                                    <div class="dv-task-title">{{ task.getTitle() }}</div>
                                                    <div class="dv-task-meta">
                                                        {% set priBadge = task.getPriority() == 'urgent' ? 'dv-badge-red' : (task.getPriority() == 'high' ? 'dv-badge-yellow' : 'dv-badge-gray') %}
                                                        <span class="dv-badge {{ priBadge }}" style="font-size:10px;">{{ task.getPriority()|capitalize }}</span>
                                                        {% if task.getDueAt() %}
                                                            <span>Due {{ task.getDueAt().format('M j') }}</span>
                                                        {% else %}
                                                            <span>No due date</span>
                                                        {% endif %}
                                                        {% if task.getOwnerId() %}
                                                            <span>{{ taskOwnerLabels[task.getOwnerId()] ?? ('User #' ~ task.getOwnerId()) }}</span>
                                                        {% endif %}
                                                    </div>
                                                </div>
                                            </li>
                                        {% endif %}
                                    {% endfor %}
                                </ul>
                            {% endif %}
                            {% if completedTasks|length > 0 %}
                                <button class="dv-show-completed-link" id="dvShowCompletedBtn">Show completed ({{ completedTasks|length }})</button>
                                <div class="dv-completed-tasks-wrapper" id="dvCompletedTasks">
                                    <ul class="dv-task-list">
                                        {% for task in completedTasks %}
                                            <li class="dv-task-item dv-completed-task">
                                                {% if canEditDeal %}
                                                    <div class="dv-task-checkbox" title="Mark incomplete" onclick="event.stopPropagation(); DealView.uncompleteTask({{ task.getId() }});"></div>
                                                {% else %}
                                                    <div class="dv-task-checkbox"></div>
                                                {% endif %}
                                                <div class="dv-task-content" style="cursor:pointer;" onclick="DealView.openEditTask({{ task.getId() }}, '{{ task.getTitle()|e('js') }}', '{{ task.getPriority()|e('js') }}', '{{ task.getDueAt() ? task.getDueAt()|date('Y-m-d') : '' }}', '{{ task.getOwnerId() ?? '' }}', '{{ task.getDescription()|default('')|e('js') }}', '{{ task.getStatus()|e('js') }}');">
                                                    <div class="dv-task-title">{{ task.getTitle() }}</div>
                                                    <div class="dv-task-meta">
                                                        <span class="dv-badge dv-badge-gray" style="font-size:10px;">{{ task.getPriority()|capitalize }}</span>
                                                        <span>Completed {{ task.getUpdatedAt().format('M j') }}</span>
                                                        {% if task.getOwnerId() %}
                                                            <span>{{ taskOwnerLabels[task.getOwnerId()] ?? ('User #' ~ task.getOwnerId()) }}</span>
                                                        {% endif %}
                                                    </div>
                                                </div>
                                            </li>
                                        {% endfor %}
                                    </ul>
                                </div>
                            {% endif %}
                        {% endif %}
                    </div>
                </div>

                {# --- Notes --- #}
                <div class="dv-card" id="dvCardNotes">
                    <div class="dv-card-header" onclick="DealView.toggleCard('dvCardNotes')">
                        <h3>Notes <span class="dv-count">({{ deal.getNotes()|length }})</span> <span class="dv-chevron"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 0-.708z"/></svg></span></h3>
                        {% if canEditDeal %}
                            <div class="dv-card-header-actions">
                                <button class="dv-btn dv-btn-sm" type="button" onclick="event.stopPropagation(); mQuery('#dealflowAddNote').modal('show');">+ Add Note</button>
                            </div>
                        {% endif %}
                    </div>
                    <div class="dv-card-body">
                        {% if deal.getNotes() is empty %}
                            <p style="color:var(--text-secondary);margin:0;">No notes yet.</p>
                        {% else %}
                            {% for note in deal.getNotes()|reverse %}
                                <div class="dv-note-item">
                                    <div class="dv-note-header">
                                        <span class="dv-note-author">{{ noteAuthorLabels[note.getAuthorUserId()] ?? (note.getAuthorUserId() ? ('User #' ~ note.getAuthorUserId()) : 'System') }}</span>
                                        <span class="dv-note-date">{{ note.getCreatedAt().format('M j, Y') }}</span>
                                        {% if canEditDeal %}
                                            <button class="dv-note-edit-icon" title="Edit note" onclick="event.stopPropagation(); DealView.openEditNote({{ note.getId() }}, this);" data-note-body="{{ note.getBody()|e('html_attr') }}"><i class="ri-pencil-line"></i></button>
                                        {% endif %}
                                    </div>
                                    <div class="dv-note-body dv-truncated" id="dvNote{{ note.getId() }}">{{ note.getBody()|purify_allow_target_blank }}</div>
                                    <button class="dv-show-more-note" id="dvNote{{ note.getId() }}Toggle" onclick="DealView.toggleNote('dvNote{{ note.getId() }}')">Show more</button>
                                </div>
                            {% endfor %}
                        {% endif %}
                    </div>
                </div>

                {# --- Activity --- #}
                <div class="dv-card" id="dvCardActivity">
                    <div class="dv-card-header" onclick="DealView.toggleCard('dvCardActivity')">
                        <h3>Activity <span class="dv-count">({{ timeline|length }})</span> <span class="dv-chevron"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 0-.708z"/></svg></span></h3>
                    </div>
                    <div class="dv-card-body">
                        {% if timeline is empty %}
                            <p style="color:var(--text-secondary);margin:0;">No activity yet.</p>
                        {% else %}
                            <ul class="dv-activity-list" id="dvActivityList">
                                {% for item in timeline %}
                                    {% set timelineLabel = item.label %}
                                    {% if item.type == 'audit' %}
                                        {% set timelineLabel = item.label|replace({'deal.': '', 'dealflow.': '', '_': ' ', '.': ' '})|title %}
                                    {% endif %}
                                    <li class="dv-activity-item" {% if loop.index > 3 %}style="display:none;" data-activity-hidden{% endif %}>
                                        <div class="dv-activity-desc">
                                            <span class="dv-action">{{ timelineLabel }}</span>
                                            {% if item.body %}
                                                <span class="dv-transition">{{ item.body }}</span>
                                            {% endif %}
                                        </div>
                                        <span class="dv-activity-time">{{ item.timestamp.format('M j, Y H:i') }}</span>
                                    </li>
                                {% endfor %}
                            </ul>
                            {% if timeline|length > 3 %}
                                <button class="dv-show-all-link" id="dvShowAllActivity">Show all ({{ timeline|length }})</button>
                            {% endif %}
                        {% endif %}
                    </div>
                </div>

            </div>

            {# ======= Side Column (30%) ======= #}
            <div class="dv-col-side">

                {# --- Health Signals --- #}
                <div class="dv-card" id="dvCardHealth">
                    <div class="dv-card-header" onclick="DealView.toggleCard('dvCardHealth')">
                        <h3>Health Signals <span class="dv-chevron"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 0-.708z"/></svg></span></h3>
                    </div>
                    <div class="dv-card-body">
                        <div class="dv-health-grid">
                            <div class="dv-health-item">
                                <div class="dv-label">Last Updated</div>
                                <div class="dv-value dv-{{ updatedColor }}">{{ updatedDaysAgo == 0 ? 'Today' : updatedDaysAgo ~ ' day' ~ (updatedDaysAgo > 1 ? 's' : '') ~ ' ago' }}</div>
                            </div>
                            <div class="dv-health-item">
                                <div class="dv-label">Days to Close</div>
                                {% if hasCloseDate %}
                                    <div class="dv-value dv-{{ closeColor }}">{{ daysToClose < 0 ? (0 - daysToClose) ~ ' days overdue' : daysToClose ~ ' day' ~ (daysToClose != 1 ? 's' : '') }}</div>
                                {% else %}
                                    <div class="dv-value dv-gray">Not set</div>
                                {% endif %}
                            </div>
                            <div class="dv-health-item">
                                <div class="dv-label">Overdue Tasks</div>
                                <div class="dv-value dv-{{ overdueColor }}">{{ overdueCount }}</div>
                            </div>
                            <div class="dv-health-item">
                                <div class="dv-label">Confidence</div>
                                <div class="dv-value dv-{{ confidenceColor }}">{{ confidence is not null ? confidence ~ '%' : 'Not set' }}</div>
                            </div>
                        </div>
                    </div>
                </div>

                {# --- Deal Details --- #}
                <div class="dv-card" id="dvCardDetails">
                    <div class="dv-card-header" onclick="DealView.toggleCard('dvCardDetails')">
                        <h3>Deal Details <span class="dv-chevron"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 0-.708z"/></svg></span></h3>
                    </div>
                    <div class="dv-card-body">
                        <ul class="dv-detail-list">
                            <li>
                                <span class="dv-dl-label">Pipeline</span>
                                <span class="dv-dl-value">{% if deal.getPipeline() %}<a href="{{ path('mautic_dealflow_pipeline', {'pipelineId': deal.getPipeline().getId()}) }}" data-toggle="ajax">{{ deal.getPipeline().getName() }}</a>{% else %}None{% endif %}</span>
                            </li>
                            <li>
                                <span class="dv-dl-label">Stage</span>
                                <span class="dv-dl-value">{{ deal.getStage() ? deal.getStage().getName() : 'Unassigned' }}{% if stages|length > 0 and currentStageIndex >= 0 %} ({{ currentStageIndex + 1 }} of {{ stages|length }}){% endif %}</span>
                            </li>
                            <li>
                                <span class="dv-dl-label">Amount</span>
                                <span class="dv-dl-value{% if canEditDeal %} dv-inline-editable{% endif %}" {% if canEditDeal %}data-field="amount" data-type="number" data-value="{{ deal.getAmount() ?? '' }}"{% endif %}>{{ include('@DealFlow/Deal/_amount.html.twig', {amount: deal.getAmount(), currency: deal.getCurrency()}, false) }}</span>
                            </li>
                            <li>
                                <span class="dv-dl-label">Currency</span>
                                <span class="dv-dl-value{% if canEditDeal %} dv-inline-editable{% endif %}" {% if canEditDeal %}data-field="currency" data-type="text" data-value="{{ deal.getCurrency() ?? '' }}"{% endif %}>{{ deal.getCurrency() ?: 'Not set' }}</span>
                            </li>
                            <li>
                                <span class="dv-dl-label">Expected Close</span>
                                <span class="dv-dl-value{% if canEditDeal %} dv-inline-editable{% endif %}" {% if canEditDeal %}data-field="expected_close" data-type="date" data-value="{{ deal.getExpectedCloseDate() ? deal.getExpectedCloseDate()|date('Y-m-d') : '' }}"{% endif %}>{{ deal.getExpectedCloseDate() ? deal.getExpectedCloseDate().format('M j, Y') : 'Not set' }}</span>
                            </li>
                            <li>
                                <span class="dv-dl-label">Confidence</span>
                                <span class="dv-dl-value{% if canEditDeal %} dv-inline-editable{% endif %}" {% if canEditDeal %}data-field="confidence" data-type="number" data-value="{{ deal.getConfidence() ?? '' }}"{% endif %}>{{ confidence is not null ? confidence ~ '%' : 'Not set' }}</span>
                            </li>
                            <li>
                                <span class="dv-dl-label">Source</span>
                                <span class="dv-dl-value{% if canEditDeal %} dv-inline-editable{% endif %}" {% if canEditDeal %}data-field="source" data-type="text" data-value="{{ deal.getSource() ?? '' }}"{% endif %}>{{ deal.getSource() ?: 'Not set' }}</span>
                            </li>
                            {% if deal.getExternalRef() %}
                                <li>
                                    <span class="dv-dl-label">External Ref</span>
                                    <span class="dv-dl-value">{{ deal.getExternalRef() }}</span>
                                </li>
                            {% endif %}
                            <li>
                                <span class="dv-dl-label">Company</span>
                                <span class="dv-dl-value{% if canEditDeal %} dv-inline-editable{% endif %}" {% if canEditDeal %}data-field="company_id" data-type="company" data-value="{{ deal.getCompanyId() ?? '' }}"{% endif %}>{{ dealContext.companyName ?: 'Unassigned' }}</span>
                            </li>
                            <li>
                                <span class="dv-dl-label">Owner</span>
                                <span class="dv-dl-value{% if canEditDeal %} dv-inline-editable{% endif %}" {% if canEditDeal %}data-field="owner_id" data-type="select" data-value="{{ deal.getOwnerId() ?? '' }}"{% endif %}>{{ dealContext.ownerName ?: 'Unassigned' }}</span>
                            </li>
                            {# Status removed — shown in header badge #}
                            <li>
                                <span class="dv-dl-label">Created</span>
                                <span class="dv-dl-value">{{ deal.getDateAdded() ? deal.getDateAdded().format('M j, Y') : 'N/A' }}</span>
                            </li>
                            {% for row in customFieldDisplayRows %}
                                <li>
                                    <span class="dv-dl-label">{{ row.label }}</span>
                                    <span class="dv-dl-value">{{ row.displayValue }}</span>
                                </li>
                            {% endfor %}
                        </ul>
                    </div>
                </div>

                {# --- Files --- #}
                <div class="dv-card" id="dvCardFiles">
                    <div class="dv-card-header" onclick="DealView.toggleCard('dvCardFiles')">
                        <h3>Files <span class="dv-count">({{ deal.getAttachments()|length }})</span> <span class="dv-chevron"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 0-.708z"/></svg></span></h3>
                    </div>
                    <div class="dv-card-body">
                        {% if deal.getAttachments() is not empty %}
                            <ul class="dv-file-list">
                                {% for attachment in deal.getAttachments() %}
                                    <li class="dv-file-item">
                                        <span class="dv-file-icon">&#128196;</span>
                                        <div class="dv-file-info">
                                            <div class="dv-file-name"><a href="{{ path('mautic_dealflow_attachment_download', {'attachmentId': attachment.getId()}) }}">{{ attachment.getOriginalFilename() }}</a></div>
                                            <div class="dv-file-meta">{{ (attachment.getSizeBytes() / 1024)|round(0) }} KB &middot; Added {{ attachment.getCreatedAt().format('M j') }}</div>
                                        </div>
                                        {% if canEditDeal %}
                                            <div class="dv-file-actions">
                                                <button class="dv-btn dv-btn-sm dv-btn-danger" type="button" data-toggle="modal" data-target="#dealflowAttachmentDelete{{ attachment.getId() }}">&#10005;</button>
                                            </div>
                                        {% endif %}
                                    </li>
                                {% endfor %}
                            </ul>
                        {% else %}
                            <p style="color:var(--text-secondary);margin:0 0 8px;">No files yet.</p>
                        {% endif %}
                        {% if canEditDeal %}
                            <form method="post" action="{{ path('mautic_dealflow_attachment_add', {'objectId': deal.getId()}) }}" enctype="multipart/form-data" id="dvFileUploadForm">
                                <input type="hidden" name="_token" value="{{ csrf_token('dealflow_add_attachment_' ~ deal.getId()) }}">
                                <input type="file" name="attachment" id="dvFileInput" style="display:none" onchange="document.getElementById('dvFileUploadForm').submit();">
                                <div class="dv-file-upload-area" onclick="document.getElementById('dvFileInput').click()">
                                    &#128206; Drop files here or click to upload
                                </div>
                            </form>
                        {% endif %}
                    </div>
                </div>

            </div>
        </div>
    </div>

    {# ======= Modals ======= #}

    {# Delete Deal Modal #}
    {% if canEditDeal %}
        <div class="modal fade" id="dealflowDeleteDeal" tabindex="-1" role="dialog" aria-labelledby="dealflowDeleteDealLabel">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title" id="dealflowDeleteDealLabel">Delete Deal</h4>
                    </div>
                    <div class="modal-body">
                        <p>Are you sure you want to permanently delete <strong>{{ deal.getTitle() }}</strong>?</p>
                        <p class="text-muted">This action cannot be undone. Type <strong>delete</strong> below to confirm.</p>
                        <input type="text" class="dv-delete-input" id="dvDeleteConfirmInput" placeholder="Type 'delete' to confirm" autocomplete="off">
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                        <form class="dealflow-inline-form" method="post" action="{{ path('mautic_dealflow_batch') }}">
                            <input type="hidden" name="_token" value="{{ csrf_token('dealflow_batch') }}">
                            <input type="hidden" name="batch_action" value="delete">
                            <input type="hidden" name="deal_ids[]" value="{{ deal.getId() }}">
                            <input type="hidden" name="return_url" value="{{ path('mautic_dealflow_index') }}">
                            <button class="btn btn-danger" type="submit" id="dvDeleteConfirmBtn" disabled>Delete Deal</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    {% endif %}

    {# Add Note Modal #}
    {% if canEditDeal %}
        <div class="modal fade" id="dealflowAddNote" tabindex="-1" role="dialog" aria-labelledby="dealflowAddNoteLabel">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title" id="dealflowAddNoteLabel">Add Note</h4>
                    </div>
                    <div class="modal-body">
                        <div class="alert alert-danger" id="dealflowAddNoteError" style="display:none;"></div>
                        <div class="form-group">
                            <textarea class="form-control" id="dealflow_note_body" rows="6" placeholder="Add a note to the deal timeline"></textarea>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                        <button class="btn btn-primary" id="dealflowAddNoteSubmit" type="button">Save Note</button>
                    </div>
                </div>
            </div>
        </div>

        {# Edit Note Modal #}
        <div class="modal fade" id="dealflowEditNote" tabindex="-1" role="dialog" aria-labelledby="dealflowEditNoteLabel">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title" id="dealflowEditNoteLabel">Edit Note</h4>
                    </div>
                    <div class="modal-body">
                        <input type="hidden" id="editNoteId" value="">
                        <div class="alert alert-danger" id="dealflowEditNoteError" style="display:none;"></div>
                        <div class="form-group">
                            <textarea class="form-control" id="editNoteBody" rows="6"></textarea>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-danger pull-left" id="deleteNoteBtn">Delete Note</button>
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                        <button class="btn btn-primary" id="dealflowEditNoteSubmit" type="button">Save Note</button>
                    </div>
                </div>
            </div>
        </div>
    {% endif %}

    {# Add Task Modal #}
    {% if canEditDeal %}
        <div class="modal fade" id="dealflowAddTask" tabindex="-1" role="dialog" aria-labelledby="dealflowAddTaskLabel">
            <div class="modal-dialog modal-lg" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title" id="dealflowAddTaskLabel">Add Task</h4>
                    </div>
                    <form method="post" action="{{ path('mautic_dealflow_task_add', {'objectId': deal.getId()}) }}">
                        <input type="hidden" name="_token" value="{{ csrf_token('dealflow_add_task_' ~ deal.getId()) }}">
                        <div class="modal-body">
                            <div class="row">
                                <div class="col-md-6">
                                    <div class="form-group">
                                        <label class="control-label">Task title</label>
                                        <input class="form-control" type="text" name="title" placeholder="Task title" required>
                                    </div>
                                </div>
                                <div class="col-md-3">
                                    <div class="form-group">
                                        <label class="control-label">Priority</label>
                                        <select class="form-control not-chosen" name="priority">
                                            <option value="normal">Normal</option>
                                            <option value="urgent">Urgent</option>
                                            <option value="high">High</option>
                                            <option value="low">Low</option>
                                        </select>
                                    </div>
                                </div>
                                <div class="col-md-3">
                                    <div class="form-group">
                                        <label class="control-label">Due date</label>
                                        <input class="form-control" type="date" name="due_at">
                                    </div>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-md-6">
                                    <div class="form-group">
                                        <label class="control-label">Owner</label>
                                        <select class="form-control not-chosen" name="owner_id">
                                            <option value="">No owner assigned</option>
                                            {% for label, ownerId in taskOwnerChoices %}
                                                <option value="{{ ownerId }}">{{ label }}</option>
                                            {% endfor %}
                                        </select>
                                    </div>
                                </div>
                                <div class="col-md-6">
                                    <div class="form-group">
                                        <label class="control-label">Reminder</label>
                                        <input class="form-control" type="datetime-local" name="reminder_at">
                                    </div>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="control-label">Description</label>
                                <textarea class="form-control" name="description" id="dealflow_task_description" rows="3" placeholder="Task details"></textarea>
                            </div>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                            <button class="btn btn-primary" type="submit">Create Task</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    {% endif %}

    {# Attachment Delete Modals #}
    {% if canEditDeal %}
        {% for attachment in deal.getAttachments() %}
            <div class="modal fade" id="dealflowAttachmentDelete{{ attachment.getId() }}" tabindex="-1" role="dialog" aria-labelledby="dealflowAttachmentDeleteLabel{{ attachment.getId() }}">
                <div class="modal-dialog" role="document">
                    <div class="modal-content">
                        <div class="modal-header">
                            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                            <h4 class="modal-title" id="dealflowAttachmentDeleteLabel{{ attachment.getId() }}">Delete attachment</h4>
                        </div>
                        <div class="modal-body">
                            <p>Delete <strong>{{ attachment.getOriginalFilename() }}</strong> from this deal?</p>
                            <p class="text-muted">This removes the file from Deal Flow and deletes the stored upload.</p>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                            <form class="dealflow-inline-form" method="post" action="{{ path('mautic_dealflow_attachment_delete', {'objectId': deal.getId(), 'attachmentId': attachment.getId()}) }}">
                                <input type="hidden" name="_token" value="{{ csrf_token('dealflow_delete_attachment_' ~ attachment.getId()) }}">
                                <button class="btn btn-danger" type="submit">Delete attachment</button>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        {% endfor %}
    {% endif %}

    {# Edit Task Modal #}
    {% if canEditDeal %}
        <div class="modal fade" id="dealflowEditTask" tabindex="-1" role="dialog">
            <div class="modal-dialog" role="document">
                <div class="modal-content" style="border-radius:8px;">
                    <div class="modal-header" style="border-bottom:1px solid var(--border-subtle-01);">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title">Edit Task</h4>
                    </div>
                    <div class="modal-body">
                        <input type="hidden" id="editTaskId" value="">
                        <div class="form-group">
                            <label>Title</label>
                            <input type="text" class="form-control" id="editTaskTitle" required>
                        </div>
                        <div class="row">
                            <div class="col-md-6">
                                <div class="form-group">
                                    <label>Priority</label>
                                    <select class="form-control not-chosen" id="editTaskPriority">
                                        <option value="low">Low</option>
                                        <option value="normal">Normal</option>
                                        <option value="high">High</option>
                                        <option value="urgent">Urgent</option>
                                    </select>
                                </div>
                            </div>
                            <div class="col-md-6">
                                <div class="form-group">
                                    <label>Due Date</label>
                                    <input type="date" class="form-control" id="editTaskDueAt">
                                </div>
                            </div>
                        </div>
                        <div class="form-group">
                            <label>Owner</label>
                            <select class="form-control not-chosen" id="editTaskOwner">
                                <option value="">Unassigned</option>
                                {% for label, ownerId in taskOwnerChoices %}
                                    <option value="{{ ownerId }}">{{ label }}</option>
                                {% endfor %}
                            </select>
                        </div>
                        <div class="form-group">
                            <label>Description</label>
                            <textarea class="form-control" id="editTaskDescription" rows="3"></textarea>
                        </div>
                        <div class="form-group">
                            <label>Status</label>
                            <select class="form-control not-chosen" id="editTaskStatus">
                                <option value="open">Open</option>
                                <option value="completed">Completed</option>
                            </select>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-danger pull-left" id="deleteTaskBtn" onclick="DealView.deleteTask();">Delete Task</button>
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                        <button type="button" class="btn btn-primary" onclick="DealView.saveTask();">Save</button>
                    </div>
                </div>
            </div>
        </div>
    {% endif %}

    {# Detach Contact Confirmation Modal #}
    {% if canEditDeal %}
        <div class="modal fade" id="dealflowDetachContact" tabindex="-1" role="dialog">
            <div class="modal-dialog modal-sm" role="document">
                <div class="modal-content" style="border-radius:8px;">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title">Remove Contact</h4>
                    </div>
                    <div class="modal-body">
                        <p>Remove <strong id="detachContactName"></strong> from this deal?</p>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                        <button type="button" class="btn btn-danger" id="detachContactBtn" onclick="DealView.detachContact();">Remove</button>
                    </div>
                </div>
            </div>
        </div>
    {% endif %}

    {# Associate Contact Modal #}
    {% if canEditDeal %}
        <div class="modal fade" id="dealflowAssociateContact" tabindex="-1" role="dialog">
            <div class="modal-dialog" role="document">
                <div class="modal-content" style="border-radius:8px;">
                    <div class="modal-header" style="border-bottom:1px solid var(--border-subtle-01);">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title">Associate Contact</h4>
                    </div>
                    <form class="dealflow-form" method="post" action="{{ path('mautic_dealflow_contact_attach', {'objectId': deal.getId()}) }}">
                        <input type="hidden" name="_token" value="{{ csrf_token('dealflow_attach_contact_' ~ deal.getId()) }}">
                        <div class="modal-body">
                            <div class="form-group">
                                <label class="control-label" for="dealflow_associate_contact_display">Contact</label>
                                <input
                                    class="form-control"
                                    id="dealflow_associate_contact_display"
                                    type="text"
                                    autocomplete="off"
                                    placeholder="Start typing a contact name"
                                    data-toggle="field-lookup"
                                    data-callback="activateDealFlowContactLookupField"
                                    data-lookup-callback="updateDealFlowContactLookupListFilter"
                                    data-chosen-lookup="lead:contactList"
                                    data-target="undefined"
                                    data-no-record-message="No matching contacts found"
                                >
                                <input id="dealflow_associate_contact_id" type="hidden" name="contact_id">
                            </div>
                            <div class="form-group">
                                <label class="control-label" for="dealflow_associate_contact_label">Role</label>
                                <input type="text" class="form-control" id="dealflow_associate_contact_label" name="label"
                                       list="dealflow_role_suggestions" placeholder="e.g., Decision Maker">
                                <datalist id="dealflow_role_suggestions">
                                    <option value="Decision Maker">
                                    <option value="Champion">
                                    <option value="Technical Evaluator">
                                    <option value="Influencer">
                                    <option value="Budget Holder">
                                    <option value="End User">
                                </datalist>
                            </div>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                            <button class="btn btn-primary" type="submit">Associate</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    {% endif %}

    {# ======= JavaScript ======= #}
    {{ include('@DealFlow/_scripts.html.twig') }}
    <script>
        (function () {
            /* ---- DealView namespace (must be first — other code assigns methods to it) ---- */
            var DealView = window.DealView = {};

            /* ---- CSRF-resilient XHR wrapper ---- */

            /**
             * Singleton promise to prevent parallel CSRF refresh requests.
             * If multiple XHR calls fail simultaneously, only one refresh fires.
             * @type {Promise<string>|null}
             */
            var _csrfRefreshing = null;

            /**
             * Fetches a fresh mautic_ajax_post CSRF token from the server.
             * Updates the global mauticAjaxCsrf variable on success.
             * @returns {Promise<string>}
             */
            function refreshCsrfToken() {
                if (_csrfRefreshing) return _csrfRefreshing;
                _csrfRefreshing = new Promise(function(resolve, reject) {
                    var xhr = new XMLHttpRequest();
                    xhr.open('GET', '{{ path("mautic_dealflow_csrf_token") }}');
                    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                    xhr.onload = function() {
                        _csrfRefreshing = null;
                        if (xhr.status === 200) {
                            try {
                                var resp = JSON.parse(xhr.responseText);
                                if (resp.token) {
                                    mauticAjaxCsrf = resp.token;
                                    resolve(resp.token);
                                    return;
                                }
                            } catch(e) {}
                        }
                        reject(new Error('Token refresh failed'));
                    };
                    xhr.onerror = function() { _csrfRefreshing = null; reject(new Error('Network error')); };
                    xhr.send();
                });
                return _csrfRefreshing;
            }

            /**
             * Detects whether an XHR response is a CSRF failure.
             * Two patterns:
             *   1. RequestSubscriber: HTTP 200 with {flashes: "..."} but NO success key
             *   2. DealController:   HTTP 403 with {success: false, error: "...CSRF..."}
             * @param {XMLHttpRequest} xhr
             * @returns {boolean}
             */
            function isCsrfError(xhr) {
                if (xhr.status === 200) {
                    try {
                        var r = JSON.parse(xhr.responseText);
                        if (r.flashes && typeof r.success === 'undefined') return true;
                    } catch(e) {}
                }
                if (xhr.status === 403) {
                    try {
                        var r403 = JSON.parse(xhr.responseText);
                        if (r403.error && r403.error.toLowerCase().indexOf('csrf') !== -1) return true;
                    } catch(e) {}
                }
                return false;
            }

            /**
             * CSRF-resilient XHR wrapper. On CSRF failure, refreshes the token
             * and retries the original request exactly once.
             *
             * @param {string} method - HTTP method (POST, PATCH, DELETE)
             * @param {string} url - Request URL
             * @param {FormData|string|null} body - Request body
             * @param {Object} opts - Options:
             *   opts.headers   {Object}   - Extra headers (e.g. Content-Type)
             *   opts.onSuccess {Function} - Called with raw xhr on success
             *   opts.onError   {Function} - Called with {status, response, isCsrf} on failure
             */
            function dealflowFetch(method, url, body, opts) {
                opts = opts || {};
                var headers = opts.headers || {};

                function doRequest(isRetry) {
                    var xhr = new XMLHttpRequest();
                    xhr.open(method, url);
                    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                    xhr.setRequestHeader('X-CSRF-Token', mauticAjaxCsrf);
                    for (var k in headers) {
                        if (headers.hasOwnProperty(k)) xhr.setRequestHeader(k, headers[k]);
                    }
                    xhr.onload = function() {
                        if (isCsrfError(xhr) && !isRetry) {
                            refreshCsrfToken().then(function() {
                                doRequest(true);
                            }).catch(function() {
                                if (opts.onError) opts.onError({status: xhr.status, response: xhr.responseText, isCsrf: true});
                            });
                            return;
                        }
                        if (xhr.status >= 200 && xhr.status < 300) {
                            if (opts.onSuccess) opts.onSuccess(xhr);
                        } else {
                            if (opts.onError) opts.onError({status: xhr.status, response: xhr.responseText, isCsrf: false});
                        }
                    };
                    xhr.onerror = function() {
                        if (opts.onError) opts.onError({status: 0, response: null, isCsrf: false});
                    };
                    xhr.send(body || null);
                }

                doRequest(false);
            }

            window.dealflowFetch = dealflowFetch;
            window.refreshCsrfToken = refreshCsrfToken;
            window._csrfRefreshing = _csrfRefreshing;

            /* ---- Contact Lookup ---- */
            Mautic.updateDealFlowContactLookupListFilter = function (field, item) {
                if (item && item.id) {
                    mQuery('#dealflow_associate_contact_id').val(item.id);
                    mQuery('#' + field).val(item.value || item.name || '');
                }
            };

            Mautic.activateDealFlowContactLookupField = function () {
                var lookupElementId = 'dealflow_associate_contact_display';
                var fieldEl = mQuery('#' + lookupElementId);
                if (!fieldEl.length) return;
                var action = fieldEl.attr('data-chosen-lookup');
                var options = { limit: 20, searchKey: 'lead.lead' };
                Mautic.activateFieldTypeahead(lookupElementId, 'undefined', options, action);
                fieldEl.off('change.dealflow').on('change.dealflow', function (event) {
                    if (event.target.value === '') {
                        mQuery('#dealflow_associate_contact_id').val('');
                    }
                });
            };
            Mautic.activateDealFlowContactLookupField();

            /* ---- WYSIWYG for Add Note modal ---- */
            mQuery('#dealflowAddNote').on('shown.bs.modal', function () {
                var textarea = document.getElementById('dealflow_note_body');
                if (textarea && !textarea._editorInit) {
                    textarea._editorInit = true;
                    if (typeof Mautic.InitCkEditor === 'function') {
                        var basicToolbar = ['bold', 'italic', 'underline', '|', 'numberedList', 'bulletedList', '|', 'link', 'removeFormat'];
                        var opts = (typeof Mautic.GetCkEditorConfigOptions === 'function')
                            ? Mautic.GetCkEditorConfigOptions(basicToolbar, null, mQuery(textarea))
                            : { toolbar: basicToolbar };
                        Mautic.InitCkEditor(mQuery(textarea), opts);
                    }
                }
            });

            /* ---- Add Note: AJAX submit ---- */
            mQuery('#dealflowAddNoteSubmit').on('click', function () {
                var textarea = document.getElementById('dealflow_note_body');
                var body = textarea ? textarea.value : '';
                // If CKEditor is active, get its content
                if (typeof ckEditors !== 'undefined' && textarea && ckEditors.has(textarea)) {
                    body = ckEditors.get(textarea).getData();
                } else if (window.CKEDITOR && window.CKEDITOR.instances && window.CKEDITOR.instances['dealflow_note_body']) {
                    body = window.CKEDITOR.instances['dealflow_note_body'].getData();
                }
                mQuery('#dealflowAddNoteError').hide();
                if (!body || !body.trim()) {
                    mQuery('#dealflowAddNoteError').text('Note body cannot be empty.').show();
                    return;
                }
                var addUrl = '{{ path("mautic_dealflow_note_add", {"objectId": deal.getId()}) }}';
                var data = new FormData();
                data.append('body', body);
                data.append('_token', '{{ csrf_token("dealflow_add_note_" ~ deal.getId()) }}');
                dealflowFetch('POST', addUrl, data, {
                    onSuccess: function(xhr) {
                        if (xhr.status === 200) {
                            try {
                                var resp = JSON.parse(xhr.responseText);
                                if (resp.success) {
                                    mQuery('#dealflowAddNote').modal('hide');
                                    window.location.reload();
                                } else {
                                    mQuery('#dealflowAddNoteError').text(resp.error || 'Failed to save note.').show();
                                }
                            } catch (e) {
                                mQuery('#dealflowAddNote').modal('hide');
                                window.location.reload();
                            }
                        } else {
                            try {
                                var errResp = JSON.parse(xhr.responseText);
                                mQuery('#dealflowAddNoteError').text(errResp.error || 'Failed to save note.').show();
                            } catch (e) {
                                mQuery('#dealflowAddNoteError').text('Failed to save note.').show();
                            }
                        }
                    },
                    onError: function() { mQuery('#dealflowAddNoteError').text('Failed to save note.').show(); }
                });
            });

            /* Clear Add Note modal on hide */
            mQuery('#dealflowAddNote').on('hidden.bs.modal', function () {
                mQuery('#dealflowAddNoteError').hide();
                var textarea = document.getElementById('dealflow_note_body');
                if (textarea) {
                    if (typeof ckEditors !== 'undefined' && ckEditors.has(textarea)) {
                        ckEditors.get(textarea).setData('');
                    } else {
                        textarea.value = '';
                    }
                }
            });

            /* ---- WYSIWYG for Edit Note modal ---- */
            mQuery('#dealflowEditNote').on('shown.bs.modal', function () {
                var textarea = document.getElementById('editNoteBody');
                if (textarea && typeof Mautic.InitCkEditor === 'function') {
                    if (typeof ckEditors !== 'undefined' && ckEditors.has(textarea)) {
                        ckEditors.get(textarea).destroy();
                        ckEditors.delete(textarea);
                    }
                    var basicToolbar = ['bold', 'italic', 'underline', '|', 'numberedList', 'bulletedList', '|', 'link', 'removeFormat'];
                    var opts = (typeof Mautic.GetCkEditorConfigOptions === 'function')
                        ? Mautic.GetCkEditorConfigOptions(basicToolbar, null, mQuery(textarea))
                        : { toolbar: basicToolbar };
                    Mautic.InitCkEditor(mQuery(textarea), opts);
                }
            });

            /* ---- Open Edit Note modal ---- */
            DealView.openEditNote = function (noteId, btn) {
                document.getElementById('editNoteId').value = noteId;
                var body = btn ? btn.getAttribute('data-note-body') : '';
                var textarea = document.getElementById('editNoteBody');
                if (textarea) { textarea.value = body || ''; }
                mQuery('#dealflowEditNoteError').hide();
                var deleteBtn = document.getElementById('deleteNoteBtn');
                if (deleteBtn) { deleteBtn.dataset.confirming = ''; deleteBtn.textContent = 'Delete Note'; }
                mQuery('#dealflowEditNote').modal('show');
            };

            /* ---- Edit Note: AJAX submit ---- */
            mQuery('#dealflowEditNoteSubmit').on('click', function () {
                var noteId = document.getElementById('editNoteId').value;
                var textarea = document.getElementById('editNoteBody');
                var body = textarea ? textarea.value : '';
                if (typeof ckEditors !== 'undefined' && textarea && ckEditors.has(textarea)) {
                    body = ckEditors.get(textarea).getData();
                }
                mQuery('#dealflowEditNoteError').hide();
                if (!body || !body.trim()) {
                    mQuery('#dealflowEditNoteError').text('Note body cannot be empty.').show();
                    return;
                }
                var editUrl = '{{ path("mautic_dealflow_note_edit", {"objectId": deal.getId(), "noteId": 999999}) }}'.replace('999999', noteId);
                var data = new FormData();
                data.append('body', body);
                dealflowFetch('POST', editUrl, data, {
                    onSuccess: function(xhr) {
                        if (xhr.status === 200) {
                            try {
                                var resp = JSON.parse(xhr.responseText);
                                if (resp.success) {
                                    mQuery('#dealflowEditNote').modal('hide');
                                    window.location.reload();
                                } else {
                                    mQuery('#dealflowEditNoteError').text(resp.error || 'Failed to save note.').show();
                                }
                            } catch (e) {
                                mQuery('#dealflowEditNote').modal('hide');
                                window.location.reload();
                            }
                        } else {
                            try {
                                var errResp = JSON.parse(xhr.responseText);
                                mQuery('#dealflowEditNoteError').text(errResp.error || 'Failed to save note.').show();
                            } catch (e) {
                                mQuery('#dealflowEditNoteError').text('Failed to save note.').show();
                            }
                        }
                    },
                    onError: function() { mQuery('#dealflowEditNoteError').text('Failed to save note.').show(); }
                });
            });

            /* ---- Delete Note ---- */
            mQuery('#deleteNoteBtn').on('click', function () {
                var btn = this;
                if (btn.dataset.confirming === 'true') {
                    var noteId = document.getElementById('editNoteId').value;
                    var deleteUrl = '{{ path("mautic_dealflow_note_delete", {"objectId": deal.getId(), "noteId": 999999}) }}'.replace('999999', noteId);
                    dealflowFetch('POST', deleteUrl, null, {
                        onSuccess: function(xhr) {
                            if (xhr.status === 200) {
                                mQuery('#dealflowEditNote').modal('hide');
                                window.location.reload();
                            }
                        }
                    });
                } else {
                    btn.dataset.confirming = 'true';
                    btn.textContent = 'Confirm Delete?';
                    setTimeout(function () { btn.dataset.confirming = ''; btn.textContent = 'Delete Note'; }, 3000);
                }
            });

            /* Reset delete button state when Edit Note modal is hidden */
            mQuery('#dealflowEditNote').on('hidden.bs.modal', function () {
                var btn = document.getElementById('deleteNoteBtn');
                if (btn) { btn.dataset.confirming = ''; btn.textContent = 'Delete Note'; }
                mQuery('#dealflowEditNoteError').hide();
            });

            /* ---- WYSIWYG for Add Task modal ---- */
            mQuery('#dealflowAddTask').on('shown.bs.modal', function () {
                var textarea = document.getElementById('dealflow_task_description');
                if (textarea && !textarea._editorInit && typeof Mautic.InitCkEditor === 'function') {
                    textarea._editorInit = true;
                    var basicToolbar = ['bold', 'italic', 'underline', '|', 'numberedList', 'bulletedList', '|', 'link', 'removeFormat'];
                    var opts = (typeof Mautic.GetCkEditorConfigOptions === 'function')
                        ? Mautic.GetCkEditorConfigOptions(basicToolbar, null, mQuery(textarea))
                        : { toolbar: basicToolbar };
                    Mautic.InitCkEditor(mQuery(textarea), opts);
                }
            });

            /* ---- WYSIWYG for Edit Task modal ---- */
            mQuery('#dealflowEditTask').on('shown.bs.modal', function () {
                var textarea = document.getElementById('editTaskDescription');
                if (textarea && typeof Mautic.InitCkEditor === 'function') {
                    // Destroy previous instance if exists
                    if (typeof ckEditors !== 'undefined' && ckEditors.has(textarea)) {
                        ckEditors.get(textarea).destroy();
                        ckEditors.delete(textarea);
                    }
                    var basicToolbar = ['bold', 'italic', 'underline', '|', 'numberedList', 'bulletedList', '|', 'link', 'removeFormat'];
                    var opts = (typeof Mautic.GetCkEditorConfigOptions === 'function')
                        ? Mautic.GetCkEditorConfigOptions(basicToolbar, null, mQuery(textarea))
                        : { toolbar: basicToolbar };
                    Mautic.InitCkEditor(mQuery(textarea), opts);
                }
            });

            /* ---- Associate Contact modal typeahead ---- */
            mQuery('#dealflowAssociateContact').on('shown.bs.modal', function () {
                Mautic.activateDealFlowContactLookupField();
            });

            /* ---- Task Edit ---- */
            DealView.openEditTask = function(taskId, title, priority, dueAt, ownerId, description, status) {
                document.getElementById('editTaskId').value = taskId;
                document.getElementById('editTaskTitle').value = title;
                document.getElementById('editTaskPriority').value = priority;
                document.getElementById('editTaskDueAt').value = dueAt;
                document.getElementById('editTaskOwner').value = ownerId;
                document.getElementById('editTaskDescription').value = description;
                document.getElementById('editTaskStatus').value = status;
                mQuery('#dealflowEditTask').modal('show');
            };

            DealView.saveTask = function() {
                var taskId = document.getElementById('editTaskId').value;
                var editTextarea = document.getElementById('editTaskDescription');
                var ckInstance = (typeof ckEditors !== 'undefined' && editTextarea) ? ckEditors.get(editTextarea) : null;
                var desc = ckInstance
                    ? ckInstance.getData()
                    : document.getElementById('editTaskDescription').value;
                var data = new FormData();
                data.append('title', document.getElementById('editTaskTitle').value);
                data.append('priority', document.getElementById('editTaskPriority').value);
                data.append('due_at', document.getElementById('editTaskDueAt').value);
                data.append('owner_id', document.getElementById('editTaskOwner').value);
                data.append('description', desc);
                data.append('status', document.getElementById('editTaskStatus').value);

                var editUrl = '{{ path("mautic_dealflow_task_edit", {"objectId": deal.getId(), "taskId": 999999}) }}'.replace('999999', taskId);
                dealflowFetch('POST', editUrl, data, {
                    onSuccess: function(xhr) {
                        if (xhr.status === 200) {
                            try {
                                var resp = JSON.parse(xhr.responseText);
                                if (resp.success) {
                                    mQuery('#dealflowEditTask').modal('hide');
                                    window.location.reload();
                                } else {
                                    alert(resp.error || 'Failed to save task.');
                                }
                            } catch (e) {
                                mQuery('#dealflowEditTask').modal('hide');
                                window.location.reload();
                            }
                        } else {
                            alert('Failed to save task.');
                        }
                    },
                    onError: function() { alert('Failed to save task.'); }
                });
            };

            /* ---- Task Delete ---- */
            DealView.deleteTask = function() {
                var btn = document.getElementById('deleteTaskBtn');
                if (btn.dataset.confirming === 'true') {
                    var taskId = document.getElementById('editTaskId').value;
                    dealflowFetch('POST', '{{ path("mautic_dealflow_task_delete", {"objectId": deal.getId(), "taskId": 999999}) }}'.replace('999999', taskId), null, {
                        onSuccess: function(xhr) {
                            if (xhr.status === 200) {
                                mQuery('#dealflowEditTask').modal('hide');
                                window.location.reload();
                            }
                        }
                    });
                } else {
                    btn.dataset.confirming = 'true';
                    btn.textContent = 'Confirm Delete?';
                    setTimeout(function() { btn.dataset.confirming = ''; btn.textContent = 'Delete Task'; }, 3000);
                }
            };

            /* Reset delete button state when modal is hidden */
            mQuery('#dealflowEditTask').on('hidden.bs.modal', function () {
                var btn = document.getElementById('deleteTaskBtn');
                if (btn) { btn.dataset.confirming = ''; btn.textContent = 'Delete Task'; }
            });

            /* ---- Task Uncomplete ---- */
            DealView.uncompleteTask = function(taskId) {
                var uncompleteUrl = '{{ path("mautic_dealflow_task_uncomplete", {"objectId": deal.getId(), "taskId": 999999}) }}'.replace('999999', taskId);
                dealflowFetch('POST', uncompleteUrl, null, {
                    onSuccess: function(xhr) {
                        if (xhr.status === 200) {
                            window.location.reload();
                        }
                    }
                });
            };

            /* ---- Contact Detach ---- */
            DealView._detachContactId = null;

            DealView.confirmDetachContact = function(contactId, contactName) {
                DealView._detachContactId = contactId;
                document.getElementById('detachContactName').textContent = contactName;
                mQuery('#dealflowDetachContact').modal('show');
            };

            DealView.detachContact = function() {
                var contactId = DealView._detachContactId;
                dealflowFetch('POST', '{{ path("mautic_dealflow_contact_detach", {"objectId": deal.getId(), "contactId": 999999}) }}'.replace('999999', contactId), null, {
                    onSuccess: function(xhr) {
                        if (xhr.status === 200) {
                            mQuery('#dealflowDetachContact').modal('hide');
                            window.location.reload();
                        }
                    }
                });
            };

            /* ---- Inline Editing ---- */
            DealView.initInlineEditing = function() {
                document.querySelectorAll('.dv-inline-editable').forEach(function(el) {
                    el.addEventListener('click', function() {
                        if (el.classList.contains('dv-inline-editing')) return;

                        var field = el.dataset.field;
                        var type = el.dataset.type;
                        var currentValue = el.dataset.value;
                        var originalHtml = el.innerHTML;

                        el.classList.add('dv-inline-editing');

                        var input;
                        if (type === 'select' && field === 'owner_id') {
                            input = document.createElement('select');
                            input.className = 'form-control input-sm';
                            var blankOpt = document.createElement('option');
                            blankOpt.value = '';
                            blankOpt.textContent = 'Unassigned';
                            input.appendChild(blankOpt);
                            var ownerSelect = document.getElementById('editTaskOwner');
                            if (ownerSelect) {
                                for (var i = 0; i < ownerSelect.options.length; i++) {
                                    var opt = document.createElement('option');
                                    opt.value = ownerSelect.options[i].value;
                                    opt.textContent = ownerSelect.options[i].textContent;
                                    if (opt.value === currentValue) opt.selected = true;
                                    if (opt.value !== '') input.appendChild(opt);
                                }
                            }
                        } else if (type === 'date') {
                            input = document.createElement('input');
                            input.type = 'date';
                            input.className = 'form-control input-sm';
                            input.value = currentValue;
                        } else if (type === 'number') {
                            input = document.createElement('input');
                            input.type = 'number';
                            input.className = 'form-control input-sm';
                            input.value = currentValue;
                            if (field === 'confidence') { input.min = 0; input.max = 100; }
                        } else if (type === 'company') {
                            var ctWrapper = document.createElement('span');
                            ctWrapper.style.cssText = 'position:relative;display:block;';
                            input = document.createElement('input');
                            input.type = 'text';
                            input.className = 'form-control input-sm';
                            input.placeholder = 'Type to search companies...';
                            input.value = '';
                            var ctSuggestions = document.createElement('span');
                            ctSuggestions.style.cssText = 'position:absolute;top:100%;left:0;right:0;background:#fff;border:1px solid var(--dv-border,#ddd);border-radius:0 0 4px 4px;max-height:160px;overflow-y:auto;z-index:1050;display:none;box-shadow:0 4px 8px rgba(0,0,0,.1);';
                            ctWrapper.appendChild(input);
                            ctWrapper.appendChild(ctSuggestions);
                            el.innerHTML = '';
                            el.appendChild(ctWrapper);
                            input.focus();

                            var ctDebounce;
                            var ctSaveCompany = function(companyId) {
                                dealflowFetch('POST', '{{ path("mautic_dealflow_inline_edit", {"objectId": deal.getId()}) }}', 'field=company_id&value=' + encodeURIComponent(companyId), {
                                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                                    onSuccess: function() { window.location.reload(); }
                                });
                            };

                            var ctBuildItems = function(companies) {
                                ctSuggestions.innerHTML = '';
                                // Always show "None" option to clear the company
                                var noneItem = document.createElement('span');
                                noneItem.textContent = '— None (clear) —';
                                noneItem.style.cssText = 'display:block;padding:6px 8px;cursor:pointer;font-size:12px;color:var(--text-secondary,#666);font-style:italic;';
                                noneItem.addEventListener('mouseenter', function() { noneItem.style.background = '#f5f5f5'; });
                                noneItem.addEventListener('mouseleave', function() { noneItem.style.background = ''; });
                                noneItem.addEventListener('mousedown', function(e) { e.preventDefault(); ctSaveCompany(''); });
                                ctSuggestions.appendChild(noneItem);
                                if (companies.length > 0) {
                                    var divider = document.createElement('span');
                                    divider.style.cssText = 'display:block;border-top:1px solid var(--dv-border,#eee);margin:2px 0;';
                                    ctSuggestions.appendChild(divider);
                                }
                                companies.forEach(function(c) {
                                    var item = document.createElement('span');
                                    item.textContent = c.name;
                                    item.style.cssText = 'display:block;padding:6px 8px;cursor:pointer;font-size:12px;';
                                    item.addEventListener('mouseenter', function() { item.style.background = '#f5f5f5'; });
                                    item.addEventListener('mouseleave', function() { item.style.background = ''; });
                                    item.addEventListener('mousedown', function(e) { e.preventDefault(); ctSaveCompany(c.id); });
                                    ctSuggestions.appendChild(item);
                                });
                                ctSuggestions.style.display = 'block';
                            };

                            var ctFetch = function(q) {
                                var xhr2 = new XMLHttpRequest();
                                xhr2.open('GET', '{{ path("mautic_dealflow_company_search") }}?q=' + encodeURIComponent(q));
                                xhr2.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                                xhr2.onload = function() {
                                    if (xhr2.status === 200) {
                                        try {
                                            var companies = JSON.parse(xhr2.responseText);
                                            ctBuildItems(companies);
                                        } catch (e) { /* ignore parse errors */ }
                                    }
                                };
                                xhr2.send();
                            };

                            // Load top companies immediately on open
                            ctFetch('');

                            input.addEventListener('input', function() {
                                clearTimeout(ctDebounce);
                                ctDebounce = setTimeout(function() { ctFetch(input.value.trim()); }, 200);
                            });

                            input.addEventListener('blur', function() {
                                setTimeout(function() {
                                    ctSuggestions.style.display = 'none';
                                    el.innerHTML = originalHtml;
                                    el.classList.remove('dv-inline-editing');
                                }, 250);
                            });

                            input.addEventListener('keydown', function(e) {
                                if (e.key === 'Escape') { el.innerHTML = originalHtml; el.classList.remove('dv-inline-editing'); }
                            });

                            return; // Company typeahead handles its own save flow
                        } else {
                            input = document.createElement('input');
                            input.type = 'text';
                            input.className = 'form-control input-sm';
                            input.value = currentValue;
                        }

                        el.innerHTML = '';
                        el.appendChild(input);
                        input.focus();

                        var save = function() {
                            var newValue = input.value;
                            dealflowFetch('POST', '{{ path("mautic_dealflow_inline_edit", {"objectId": deal.getId()}) }}', 'field=' + encodeURIComponent(field) + '&value=' + encodeURIComponent(newValue), {
                                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                                onSuccess: function(xhr) {
                                    if (xhr.status === 200) {
                                        try {
                                            var resp = JSON.parse(xhr.responseText);
                                            if (resp.success) {
                                                window.location.reload();
                                            } else {
                                                el.innerHTML = originalHtml;
                                                el.classList.remove('dv-inline-editing');
                                                if (window.DealFlow && window.DealFlow.showToast) {
                                                    window.DealFlow.showToast(resp.error || 'Save failed', 'error');
                                                }
                                            }
                                        } catch (e) {
                                            window.location.reload();
                                        }
                                    } else {
                                        el.innerHTML = originalHtml;
                                        el.classList.remove('dv-inline-editing');
                                    }
                                },
                                onError: function() { el.innerHTML = originalHtml; el.classList.remove('dv-inline-editing'); }
                            });
                        };

                        input.addEventListener('blur', save);
                        input.addEventListener('keydown', function(e) {
                            if (e.key === 'Enter') { e.preventDefault(); save(); }
                            if (e.key === 'Escape') { el.innerHTML = originalHtml; el.classList.remove('dv-inline-editing'); }
                        });
                    });
                });
            };

            /* Section collapse/expand */
            DealView.toggleCard = function (id) {
                var card = document.getElementById(id);
                if (!card) return;
                var body = card.querySelector('.dv-card-body');
                if (card.classList.contains('dv-collapsed')) {
                    card.classList.remove('dv-collapsed');
                    body.style.maxHeight = body.scrollHeight + 'px';
                    setTimeout(function () { body.style.maxHeight = 'none'; }, 300);
                } else {
                    body.style.maxHeight = body.scrollHeight + 'px';
                    body.offsetHeight; // force reflow
                    card.classList.add('dv-collapsed');
                    body.style.maxHeight = '0';
                }
            };

            /* Init card bodies */
            document.querySelectorAll('.dv-card-body').forEach(function (body) {
                body.style.maxHeight = 'none';
            });

            /* Overdue tasks expand/collapse */
            var overdueAlert = document.getElementById('dvOverdueAlert');
            if (overdueAlert) {
                overdueAlert.addEventListener('click', function () {
                    overdueAlert.classList.toggle('dv-expanded');
                    document.getElementById('dvOverdueDetail').classList.toggle('dv-open');
                });
            }

            /* Show/hide completed tasks */
            var showCompletedBtn = document.getElementById('dvShowCompletedBtn');
            if (showCompletedBtn) {
                showCompletedBtn.addEventListener('click', function () {
                    var wrapper = document.getElementById('dvCompletedTasks');
                    wrapper.classList.toggle('dv-visible');
                    var count = wrapper.querySelectorAll('.dv-task-item').length;
                    showCompletedBtn.textContent = wrapper.classList.contains('dv-visible')
                        ? 'Hide completed (' + count + ')'
                        : 'Show completed (' + count + ')';
                    var cardBody = wrapper.closest('.dv-card-body');
                    if (cardBody) cardBody.style.maxHeight = 'none';
                });
            }

            /* Note truncation toggle */
            DealView.toggleNote = function (id) {
                var note = document.getElementById(id);
                var toggle = document.getElementById(id + 'Toggle');
                if (!note || !toggle) return;
                if (note.classList.contains('dv-truncated')) {
                    note.classList.remove('dv-truncated');
                    toggle.textContent = 'Show less';
                } else {
                    note.classList.add('dv-truncated');
                    toggle.textContent = 'Show more';
                }
                var cardBody = note.closest('.dv-card-body');
                if (cardBody) cardBody.style.maxHeight = 'none';
            };

            /* Show all activity */
            var showAllBtn = document.getElementById('dvShowAllActivity');
            if (showAllBtn) {
                showAllBtn.addEventListener('click', function () {
                    document.querySelectorAll('[data-activity-hidden]').forEach(function (el) {
                        el.style.display = '';
                        el.removeAttribute('data-activity-hidden');
                    });
                    showAllBtn.style.display = 'none';
                    var cardBody = showAllBtn.closest('.dv-card-body');
                    if (cardBody) cardBody.style.maxHeight = 'none';
                });
            }

            /* Stage bar click -> AJAX move stage */
            var moveStageUrl = '{{ path("mautic_dealflow_move_stage", {"objectId": "__ID__"}) }}';
            var stageCsrf = '{{ csrf_token("dealflow_move_stage_" ~ deal.getId()) }}';

            function moveStage(stageId) {
                var dealId = '{{ deal.getId() }}';
                var formData = new FormData();
                formData.append('stage_id', stageId);
                formData.append('_token', stageCsrf);
                formData.append('return_url', window.location.pathname);

                dealflowFetch('POST', moveStageUrl.replace('__ID__', dealId), formData, {
                    onSuccess: function(xhr) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            window.DealFlow.showToast('Stage updated.');
                            /* Update bar visually */
                            var stageEls = document.querySelectorAll('.dv-stage-bar .dv-stage');
                            var found = false;
                            stageEls.forEach(function (el) {
                                el.classList.remove('dv-completed', 'dv-current');
                                if (el.getAttribute('data-stage-id') == stageId) {
                                    el.classList.add('dv-current');
                                    found = true;
                                } else if (!found) {
                                    el.classList.add('dv-completed');
                                }
                            });
                            /* Update dropdown */
                            var dropdown = document.getElementById('dvStageDropdown');
                            if (dropdown) dropdown.value = stageId;
                        } else {
                            window.DealFlow.showToast('Failed to update stage.');
                        }
                    },
                    onError: function() { window.DealFlow.showToast('Network error updating stage.'); }
                });
            }

            document.querySelectorAll('.dv-stage-bar .dv-stage').forEach(function (el) {
                el.addEventListener('click', function () {
                    moveStage(el.getAttribute('data-stage-id'));
                });
            });

            var stageDropdown = document.getElementById('dvStageDropdown');
            if (stageDropdown) {
                stageDropdown.addEventListener('change', function () {
                    moveStage(stageDropdown.value);
                });
            }

            /* Inline status change */
            document.querySelectorAll('[data-dealflow-inline-status]').forEach(function (select) {
                select.addEventListener('change', function () {
                    var dealId = select.getAttribute('data-deal-id');
                    var csrf = select.getAttribute('data-csrf');
                    var status = select.value;
                    var formData = new FormData();
                    formData.append('deal[status]', status);
                    formData.append('deal[_token]', csrf);

                    dealflowFetch('PATCH', '{{ path("mautic_api_dealflow_deal", {"id": "__ID__"}) }}'.replace('__ID__', dealId), formData, {
                        onSuccess: function(xhr) {
                            if (xhr.status >= 200 && xhr.status < 300) {
                                window.DealFlow.showToast('Status updated.');
                            } else {
                                window.DealFlow.showToast('Failed to update status.');
                            }
                        },
                        onError: function() { window.DealFlow.showToast('Network error updating status.'); }
                    });
                });
            });

            /* Delete confirmation: enable button only when user types "delete" */
            var deleteInput = document.getElementById('dvDeleteConfirmInput');
            var deleteBtn = document.getElementById('dvDeleteConfirmBtn');
            if (deleteInput && deleteBtn) {
                deleteInput.addEventListener('input', function () {
                    deleteBtn.disabled = deleteInput.value.toLowerCase().trim() !== 'delete';
                });
            }

            /* Init inline editing */
            DealView.initInlineEditing();
        })();
    </script>
{% endblock %}
