<?php

// =========================================================================
// MOTOR AJAX: ACTUALIZACION RAPIDA DE ETAPA (DRAG & DROP / MENU)
// =========================================================================
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax_update_stage'])) {
    require_once '../../core/config.php';
    require_once '../../core/session.php';
    require_once '../../core/permissions.php';
    require_once '../../services/crm/OpportunityLifecycleService.php';

    header('Content-Type: application/json; charset=utf-8');
    require_login();
    require_permission('module.crm');
    csrf_require_valid_request();

    try {
        $service = new OpportunityLifecycleService();
        $result = $service->moveStage(
            $_POST['id'] ?? 0,
            $_POST['stage'] ?? '',
            current_user() ?: array(),
            'kanban'
        );
        echo json_encode(array('success' => true, 'result' => $result, 'stage' => $result['stage'] ?? null), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    } catch (OpportunityAuthorizationException $e) {
        http_response_code(403);
        echo json_encode(array('success' => false, 'error' => $e->getMessage()), JSON_UNESCAPED_UNICODE);
    } catch (InvalidArgumentException $e) {
        http_response_code(422);
        echo json_encode(array('success' => false, 'error' => $e->getMessage()), JSON_UNESCAPED_UNICODE);
    } catch (Throwable $e) {
        error_log('ICYLAB kanban stage update failed: ' . $e->getMessage());
        http_response_code(500);
        echo json_encode(array('success' => false, 'error' => 'No fue posible actualizar la etapa.'), JSON_UNESCAPED_UNICODE);
    }
    exit;
}

require_once '../../core/config.php';
require_once '../../core/session.php';
require_once '../../core/permissions.php'; 
require_once '../../core/format.php';
require_once __DIR__ . '/../customers/_customer_quick_fields.php';
require_once '../../services/crm/CrmService.php';
require_once '../../services/crm/PaymentStatusService.php';

require_login();
require_permission('module.crm'); 

$page_title = 'Embudo Comercial';
PaymentStatusService::processOverdueOpportunities(db());
$crm = new CrmService();
$embudo = $crm->getEmbudo();
$customers = $crm->getCustomers();
$assignableUsers = $crm->getAssignableUsers();
$currentUser = current_user();

$formErrors = $_SESSION['form_errors'] ?? array();
$formOld = $_SESSION['form_old'] ?? array();
unset($_SESSION['form_errors'], $_SESSION['form_old']);

function field_error($field, $formErrors) { return isset($formErrors[$field]) ? $formErrors[$field] : ''; }
function field_class($field, $formErrors, $required = false) {
    $classes = array('form-field');
    if ($required) $classes[] = 'is-required';
    if (isset($formErrors[$field])) $classes[] = 'has-error';
    return implode(' ', $classes);
}

$ownerValue = $formOld['owner_name'] ?? $currentUser['name'] ?? '';

$stages = array('nuevo' => 'Nuevo', 'contactado' => 'Contactado', 'cotizando' => 'Cotizando', 'negociacion' => 'Negociación', 'ganada' => 'Ganada', 'perdida' => 'Perdida', 'facturada' => 'Facturada');
$opportunityCreateStages = array('nuevo', 'contactado', 'cotizando', 'negociacion');

$activeOpportunityCount = 0;
$activePipelineValue = 0.0;
foreach ($embudo as $stageRows) {
    $activeOpportunityCount += count($stageRows);
    foreach ($stageRows as $stageRow) {
        $activePipelineValue += (float)($stageRow['expected_value'] ?? 0);
    }
}

$paymentStatusOptions = ['no_facturado' => 'No facturado', 'por_cobrar' => 'Por cobrar', 'pagado' => 'Pagado', 'atrasado' => 'Atrasado', 'incobrable' => 'Incobrable'];
$sourceOptions = ['Instagram' => 'Instagram', 'Web' => 'Web', 'OpenLab' => 'OpenLab', 'Recomendación' => 'Recomendación', 'Email' => 'Email', 'Llamada' => 'Llamada', 'Distribuidor' => 'Distribuidor', 'Reposicion predictiva' => 'Reposición predictiva', 'Otro' => 'Otro'];
$competitorOptions = ['' => 'No identificado', 'Abstrax' => 'Abstrax', 'HopBurst' => 'HopBurst', 'Pellets' => 'Pellets', 'Proveedor tradicional' => 'Proveedor tradicional', 'Otro' => 'Otro'];
$nextActionOptions = array('' => 'Sin acción', 'Llamar' => 'Llamar', 'Enviar cotización' => 'Enviar cotización', 'Enviar muestra' => 'Enviar muestra', 'Agendar reunión' => 'Agendar reunión', 'Despachar' => 'Despachar', 'Hacer seguimiento' => 'Hacer seguimiento', 'Esperar respuesta' => 'Esperar respuesta');

$openModalId = isset($_GET['open_modal']) ? (int) $_GET['open_modal'] : 0;
$closeModalId = isset($_GET['close_id']) ? (int) $_GET['close_id'] : 0;
$closeModalOpportunity = null;
if ($closeModalId > 0) {
    $candidate = $crm->getOpportunity($closeModalId);
    if ($candidate && empty($candidate['archived_at'])) $closeModalOpportunity = $candidate;
}

require_once '../../layouts/header.php';
require_once '../../layouts/sidebar.php';
?>

<main class="app-main no-scroll-main" id="embudo-main">
    
    <style>
    /* =========================================================
       Embudo CRM - mobile/desktop UX contained in this module
       Desktop: page locked, internal kanban/card scroll.
       Mobile: horizontal kanban swipe + internal column scroll.
       ========================================================= */
    body #embudo-main {
        min-width: 0 !important;
        height: 100vh !important;
        height: 100dvh !important;
        min-height: 0 !important;
        overflow: hidden !important;
        display: flex !important;
        flex-direction: column !important;
    }

    body #embudo-main > .content.flex-content,
    body #embudo-main > .flex-content {
        flex: 1 1 0% !important;
        min-height: 0 !important;
        height: auto !important;
        overflow: hidden !important;
        display: flex !important;
        flex-direction: column !important;
        padding-bottom: 24px !important;
    }

    #embudo-main .header-responsive,
    #embudo-main .filter-bar-container,
    #embudo-main .alert {
        flex: 0 0 auto !important;
    }

    #embudo-main .header-responsive {
        display: flex !important;
        align-items: flex-start !important;
        justify-content: space-between !important;
        gap: 16px !important;
        margin-bottom: 16px !important;
    }

    #embudo-main .page-header-content {
        min-width: 0 !important;
    }

    #embudo-main .page-header-content h2 {
        line-height: 1.1 !important;
        margin-bottom: 4px !important;
    }

    #embudo-main .top-actions-cluster {
        flex: 0 0 auto !important;
        display: flex !important;
        align-items: center !important;
        justify-content: flex-end !important;
        gap: 10px !important;
        flex-wrap: nowrap !important;
    }

    #embudo-main .filter-bar-container {
        position: relative !important;
        z-index: 50 !important;
        display: flex !important;
        gap: 12px !important;
        flex-wrap: nowrap !important;
        padding: 12px 16px !important;
        background: var(--surface-1) !important;
        border: 1px solid var(--border-default) !important;
        border-radius: var(--radius-xl) !important;
        margin-bottom: 16px !important;
        align-items: center !important;
    }

    #embudo-main .filter-bar-container .form-field {
        margin: 0 !important;
        min-width: 0 !important;
    }

    #embudo-main .input-with-icon {
        position: relative !important;
        display: flex !important;
        align-items: center !important;
        width: 100% !important;
    }

    #embudo-main .input-with-icon svg {
        position: absolute !important;
        left: 14px !important;
        top: 50% !important;
        transform: translateY(-50%) !important;
        width: 18px !important;
        height: 18px !important;
        color: var(--text-muted) !important;
        pointer-events: none !important;
    }

    #embudo-main .input-with-icon input {
        padding-left: 42px !important;
        width: 100% !important;
        min-width: 0 !important;
    }

    #embudo-main .crm-kanban-wrapper {
        flex: 1 1 0% !important;
        min-height: 0 !important;
        width: 100% !important;
        max-width: 100% !important;
        overflow-x: auto !important;
        overflow-y: hidden !important;
        scroll-behavior: auto !important;
        overscroll-behavior-x: contain !important;
        -webkit-overflow-scrolling: touch !important;
        scrollbar-width: thin !important;
        scrollbar-color: var(--border-strong) transparent !important;
        touch-action: auto !important;
    }

    #embudo-main .crm-kanban-wrapper::-webkit-scrollbar { height: 8px !important; }
    #embudo-main .crm-kanban-wrapper::-webkit-scrollbar-track { background: transparent !important; }
    #embudo-main .crm-kanban-wrapper::-webkit-scrollbar-thumb { background: var(--border-strong) !important; border-radius: 4px !important; }
    #embudo-main .crm-kanban-wrapper::-webkit-scrollbar-thumb:hover { background: var(--text-muted) !important; }

    #embudo-main .crm-kanban-track {
        display: flex !important;
        align-items: stretch !important;
        gap: 16px !important;
        height: 100% !important;
        min-height: 0 !important;
        width: max-content !important;
        min-width: max-content !important;
        padding-bottom: 8px !important;
    }

    #embudo-main .crm-column {
        flex: 0 0 320px !important;
        width: 320px !important;
        max-width: 320px !important;
        min-width: 320px !important;
        height: 100% !important;
        min-height: 0 !important;
        display: flex !important;
        flex-direction: column !important;
        background: var(--surface-1) !important;
        border: 1px solid var(--border-default) !important;
        border-radius: var(--radius-xl) !important;
        overflow: hidden !important;
    }

    #embudo-main .crm-column-header {
        flex: 0 0 54px !important;
        min-height: 54px !important;
        padding: 0 var(--space-4) !important;
        display: flex !important;
        align-items: center !important;
        justify-content: space-between !important;
        border-bottom: 1px solid var(--border-subtle) !important;
        background: var(--surface-2) !important;
        z-index: 4 !important;
    }

    #embudo-main .crm-column-body {
        flex: 1 1 0% !important;
        min-height: 0 !important;
        overflow-y: auto !important;
        overflow-x: hidden !important;
        padding: 12px !important;
        display: flex !important;
        flex-direction: column !important;
        gap: 12px !important;
        transition: background 0.2s !important;
        -webkit-overflow-scrolling: touch !important;
        overscroll-behavior: contain !important;
        scrollbar-width: thin !important;
        scrollbar-color: var(--border-default) transparent !important;
        touch-action: auto !important;
    }

    #embudo-main .crm-column-body.drag-over {
        background: color-mix(in srgb, var(--color-primary) 5%, var(--surface-1)) !important;
    }

    #embudo-main .crm-column-body::-webkit-scrollbar { width: 5px !important; }
    #embudo-main .crm-column-body::-webkit-scrollbar-track { background: transparent !important; }
    #embudo-main .crm-column-body::-webkit-scrollbar-thumb { background: var(--border-default) !important; border-radius: 4px !important; }

    #embudo-main .crm-opportunity-card {
        position: relative !important;
        flex: 0 0 auto !important;
        padding: 14px !important;
        background: var(--surface-2) !important;
        border: 1px solid var(--border-default) !important;
        border-radius: var(--radius-lg) !important;
        cursor: grab !important;
        transition: transform 0.1s, box-shadow 0.1s, border-color 0.1s, background 0.1s !important;
        user-select: none !important;
        overflow: visible !important;
    }

    #embudo-main .crm-opportunity-card:active { cursor: grabbing !important; }
    #embudo-main .crm-opportunity-card:hover { border-color: var(--border-strong) !important; background: var(--surface-3) !important; }
    #embudo-main .crm-opportunity-card.is-dragging { opacity: 0.5 !important; transform: scale(0.96) !important; box-shadow: var(--shadow-md) !important; z-index: 100 !important; }
    #embudo-main .crm-opportunity-card.is-hidden { display: none !important; }

    #embudo-main .crm-opportunity-header {
        display: flex !important;
        align-items: flex-start !important;
        justify-content: space-between !important;
        margin-bottom: 4px !important;
        gap: 8px !important;
    }

    #embudo-main .block-truncate {
        display: block !important;
        width: 100% !important;
        min-width: 0 !important;
    }

    #embudo-main .crm-empty {
        flex: 0 0 auto !important;
        text-align: center !important;
        padding: 24px 12px !important;
        color: var(--text-muted) !important;
        font-size: 0.85rem !important;
        border: 1px dashed var(--border-default) !important;
        border-radius: var(--radius-md) !important;
        margin-top: 8px !important;
    }

    #embudo-main .btn-invisible {
        position: absolute !important;
        top: 10px !important;
        right: 10px !important;
        background: transparent !important;
        border: none !important;
        padding: 4px !important;
        border-radius: 6px !important;
        color: var(--text-muted) !important;
        cursor: pointer !important;
        z-index: 10 !important;
    }

    #embudo-main .btn-invisible:hover {
        background: var(--border-subtle) !important;
        color: var(--text-primary) !important;
    }

    #embudo-main .btn-invisible i { width: 18px !important; height: 18px !important; }

    #embudo-main .btn-sort-col {
        background: transparent !important;
        border: 1px solid var(--border-default) !important;
        padding: 4px 6px !important;
        border-radius: 6px !important;
        color: var(--text-muted) !important;
        cursor: pointer !important;
        display: inline-flex !important;
        align-items: center !important;
        justify-content: center !important;
        transition: all 0.2s !important;
    }

    #embudo-main .btn-sort-col:hover {
        background: var(--surface-3) !important;
        color: var(--text-primary) !important;
        border-color: var(--border-strong) !important;
    }

    #embudo-main .crm-column-header-actions {
        display: flex !important;
        align-items: center !important;
        gap: 8px !important;
    }

    #embudo-main .btn-create-col {
        width: 30px !important;
        height: 30px !important;
        min-width: 30px !important;
        padding: 0 !important;
        display: inline-flex !important;
        align-items: center !important;
        justify-content: center !important;
        border: 1px solid color-mix(in srgb, var(--color-success) 45%, var(--border-default)) !important;
        border-radius: 8px !important;
        background: color-mix(in srgb, var(--color-success) 8%, var(--surface-1)) !important;
        color: var(--color-success) !important;
        cursor: pointer !important;
        transition: background .16s ease, border-color .16s ease, transform .16s ease !important;
        touch-action: manipulation !important;
    }

    #embudo-main .btn-create-col:hover,
    #embudo-main .btn-create-col:focus-visible {
        background: color-mix(in srgb, var(--color-success) 16%, var(--surface-1)) !important;
        border-color: var(--color-success) !important;
        outline: none !important;
    }

    #embudo-main .btn-create-col:active { transform: scale(.94) !important; }
    #embudo-main .btn-create-col i { width: 16px !important; height: 16px !important; }

    #embudo-main .crm-column-body.is-create-enabled .crm-empty.is-create-empty {
        cursor: pointer !important;
        border-color: color-mix(in srgb, var(--color-success) 58%, var(--border-default)) !important;
        background: color-mix(in srgb, var(--color-success) 4%, transparent) !important;
    }

    #embudo-main .crm-column-body.is-create-enabled .crm-empty.is-create-empty:hover {
        background: color-mix(in srgb, var(--color-success) 8%, var(--surface-1)) !important;
        border-color: var(--color-success) !important;
    }

    #embudo-main .stage-dropdown-menu {
        position: absolute !important;
        top: 36px !important;
        right: 10px !important;
        width: 160px !important;
        background: var(--surface-1) !important;
        border: 1px solid var(--border-default) !important;
        border-radius: 12px !important;
        box-shadow: var(--shadow-lg) !important;
        z-index: 80 !important;
        display: none !important;
        flex-direction: column !important;
        padding: 6px !important;
    }

    #embudo-main .stage-dropdown-menu.is-open { display: flex !important; }

    #embudo-main .stage-dropdown-btn {
        background: transparent !important;
        border: none !important;
        padding: 9px 12px !important;
        text-align: left !important;
        font-size: 0.85rem !important;
        color: var(--text-primary) !important;
        border-radius: 8px !important;
        cursor: pointer !important;
    }

    #embudo-main .stage-dropdown-btn:hover {
        background: var(--surface-2) !important;
        color: var(--color-primary) !important;
    }

    /* Create opportunity modal: same height and footer pattern as CRM Index. */
    body #embudo-main #opportunityModal.product-modal-backdrop {
        position: fixed !important;
        inset: 0 !important;
        background: rgba(0,0,0,0.70) !important;
        backdrop-filter: blur(5px) !important;
        z-index: 9999 !important;
        display: none;
        align-items: center !important;
        justify-content: center !important;
        opacity: 0;
        padding: 24px !important;
        overflow: hidden !important;
        transition: opacity 0.2s ease !important;
    }

    body #embudo-main #opportunityModal.product-modal-backdrop.show {
        display: flex !important;
        opacity: 1 !important;
    }

    body #embudo-main #opportunityModal .product-modal-box {
        background: var(--surface-1) !important;
        width: min(1080px, calc(100vw - 48px)) !important;
        max-width: calc(100vw - 48px) !important;
        height: min(700px, calc(100dvh - 48px)) !important;
        min-height: min(560px, calc(100dvh - 100px)) !important;
        max-height: calc(100dvh - 100px) !important;
        border: 1px solid var(--border-default) !important;
        border-radius: var(--radius-xl) !important;
        box-shadow: var(--shadow-lg) !important;
        display: flex !important;
        flex-direction: column !important;
        overflow: hidden !important;
        transform: translateY(20px) !important;
        transition: transform 0.2s ease !important;
    }

    body #embudo-main #opportunityModal.product-modal-backdrop.show .product-modal-box {
        transform: translateY(0) !important;
    }

    body #embudo-main #opportunityModal .product-modal-header,
    body #embudo-main #opportunityModal .product-modal-footer {
        flex: 0 0 auto !important;
    }

    body #embudo-main #opportunityModal .product-modal-header {
        padding: var(--space-5) !important;
        border-bottom: 1px solid var(--border-subtle) !important;
        display: flex !important;
        justify-content: space-between !important;
        align-items: flex-start !important;
        gap: var(--space-4) !important;
    }

    body #embudo-main #opportunityModal .product-modal-body {
        flex: 1 1 auto !important;
        min-height: 0 !important;
        max-height: none !important;
        padding: var(--space-5) !important;
        margin-left: 0 !important;
        overflow-y: auto !important;
        overflow-x: hidden !important;
        -webkit-overflow-scrolling: touch !important;
    }

    body #embudo-main #opportunityModal .product-modal-footer {
        min-height: 76px !important;
        height: auto !important;
        max-height: none !important;
        padding: 14px 20px !important;
        border-top: 1px solid var(--border-subtle) !important;
        display: flex !important;
        flex-direction: row !important;
        align-items: center !important;
        justify-content: flex-end !important;
        gap: 12px !important;
        flex-wrap: nowrap !important;
        background: var(--surface-0) !important;
        border-radius: 0 0 var(--radius-xl) var(--radius-xl) !important;
        overflow: visible !important;
    }

    body #embudo-main #opportunityModal .product-modal-footer .btn {
        width: auto !important;
        min-width: 118px !important;
        max-width: none !important;
        height: 48px !important;
        min-height: 48px !important;
        padding: 0 18px !important;
        display: inline-flex !important;
        align-items: center !important;
        justify-content: center !important;
        gap: 8px !important;
        flex: 0 0 auto !important;
        white-space: nowrap !important;
        text-align: center !important;
        overflow: visible !important;
        text-overflow: clip !important;
    }

    body #embudo-main #opportunityModal #saveOpportunityBtn {
        min-width: 178px !important;
    }

    body #embudo-main #opportunityModal .product-modal-footer .btn span {
        display: inline-flex !important;
        align-items: center !important;
        justify-content: center !important;
        min-width: 0 !important;
        max-width: none !important;
        overflow: visible !important;
        text-overflow: clip !important;
        white-space: nowrap !important;
        text-align: center !important;
    }

    #embudo-main #modalNewCustomerBlock {
        padding: 16px !important;
        background: var(--surface-2) !important;
        border-radius: var(--radius-lg) !important;
        margin-bottom: 16px !important;
        border: 1px solid var(--border-default) !important;
    }

    @media (pointer: coarse) {
        #embudo-main .crm-kanban-wrapper,
        #embudo-main .crm-kanban-track,
        #embudo-main .crm-column,
        #embudo-main .crm-column-body,
        #embudo-main .crm-opportunity-card {
            touch-action: none !important;
        }

        #embudo-main .crm-opportunity-card {
            -webkit-touch-callout: none !important;
            user-select: none !important;
            -webkit-user-select: none !important;
        }
    }

    #embudo-main .crm-kanban-wrapper.is-touch-dragging {
        cursor: grabbing !important;
        user-select: none !important;
        -webkit-user-select: none !important;
    }

    #embudo-main .crm-opportunity-card.is-touch-drag-source {
        opacity: 0.34 !important;
        transform: scale(0.985) !important;
    }

    body #embudo-main .crm-opportunity-card.kanban-touch-drag-ghost {
        position: fixed !important;
        z-index: 2200 !important;
        pointer-events: none !important;
        margin: 0 !important;
        opacity: 0.96 !important;
        transform: translate3d(-50%, -50%, 0) rotate(1deg) scale(1.02) !important;
        box-shadow: 0 18px 45px rgba(0, 0, 0, 0.22) !important;
        transition: none !important;
        will-change: left, top !important;
    }

    @media (max-width: 760px) {
        body #embudo-main > .content.flex-content,
        body #embudo-main > .flex-content {
            padding: 16px 12px calc(16px + env(safe-area-inset-bottom)) !important;
            gap: 12px !important;
        }

        #embudo-main .header-responsive {
            display: grid !important;
            grid-template-columns: minmax(0, 1fr) auto !important;
            align-items: start !important;
            gap: 10px !important;
            margin-bottom: 0 !important;
        }

        #embudo-main .page-header-content {
            padding-right: 0 !important;
        }

        #embudo-main .page-header-content .label {
            font-size: 0.66rem !important;
        }

        #embudo-main .page-header-content h2 {
            font-size: clamp(1.28rem, 6vw, 1.55rem) !important;
            line-height: 1.08 !important;
            margin: 0 !important;
        }

        #embudo-main .page-header-content p {
            display: none !important;
        }

        #embudo-main .top-actions-cluster {
            gap: 8px !important;
            margin-left: 0 !important;
        }

        #embudo-main .mobile-hidden {
            display: none !important;
        }

        #embudo-main .btn-icon-mobile {
            width: 42px !important;
            min-width: 42px !important;
            max-width: 42px !important;
            height: 42px !important;
            padding: 0 !important;
            display: inline-flex !important;
            align-items: center !important;
            justify-content: center !important;
        }

        #embudo-main .filter-bar-container {
            flex-direction: row !important;
            padding: 10px !important;
            gap: 8px !important;
            margin-bottom: 0 !important;
            border-radius: 16px !important;
        }

        #embudo-main .filter-bar-container .form-field:nth-child(1) {
            flex: 1 1 auto !important;
            min-width: 0 !important;
        }

        #embudo-main .filter-bar-container .form-field:nth-child(2) {
            flex: 0 0 118px !important;
            width: 118px !important;
            min-width: 118px !important;
        }

        #embudo-main .filter-bar-container select.select {
            padding-left: 10px !important;
            padding-right: 28px !important;
            font-size: 0.85rem !important;
            text-overflow: ellipsis !important;
            white-space: nowrap !important;
            overflow: hidden !important;
        }

        #embudo-main .input-with-icon svg {
            left: 12px !important;
            width: 17px !important;
            height: 17px !important;
        }

        #embudo-main .input-with-icon input {
            padding-left: 38px !important;
            font-size: 0.9rem !important;
        }

        #embudo-main .crm-kanban-wrapper {
            scroll-snap-type: x mandatory !important;
            padding: 0 !important;
        }

        #embudo-main .crm-kanban-track {
            gap: 12px !important;
            height: 100% !important;
            padding: 0 2px 12px 0 !important;
        }

        #embudo-main .crm-column {
            scroll-snap-align: start !important;
            flex: 0 0 calc(100vw - 34px) !important;
            width: calc(100vw - 34px) !important;
            min-width: calc(100vw - 34px) !important;
            max-width: calc(100vw - 34px) !important;
            border-radius: 18px !important;
        }

        #embudo-main .crm-column-header {
            min-height: 50px !important;
            flex-basis: 50px !important;
            padding: 0 12px !important;
        }

        #embudo-main .crm-column-header strong {
            font-size: 0.92rem !important;
        }

        #embudo-main .crm-column-body {
            padding: 10px !important;
            gap: 10px !important;
        }

        #embudo-main .crm-opportunity-card {
            padding: 12px !important;
            cursor: pointer !important;
        }

        #embudo-main .stage-dropdown-menu {
            width: min(172px, calc(100vw - 84px)) !important;
            right: 8px !important;
        }

        body #embudo-main #opportunityModal.product-modal-backdrop {
            padding: 12px !important;
        }

        body #embudo-main #opportunityModal .product-modal-box {
            width: calc(100vw - 24px) !important;
            max-width: calc(100vw - 24px) !important;
            height: calc(100dvh - 24px) !important;
            min-height: 0 !important;
            max-height: calc(100dvh - 200px) !important;
            border-radius: 18px !important;
        }

        body #embudo-main #opportunityModal .product-modal-header {
            padding: 16px !important;
        }

        body #embudo-main #opportunityModal .product-modal-body {
            padding: 16px !important;
            max-height: none !important;
        }

        body #embudo-main #opportunityModal .product-modal-footer {
            min-height: 68px !important;
            padding: 10px 12px calc(10px + env(safe-area-inset-bottom)) !important;
            gap: 10px !important;
        }

        body #embudo-main #opportunityModal .product-modal-footer .btn {
            height: 44px !important;
            min-height: 44px !important;
            min-width: 106px !important;
            max-width: none !important;
            padding: 0 14px !important;
            font-size: 0.94rem !important;
        }

        body #embudo-main #opportunityModal #saveOpportunityBtn {
            min-width: 124px !important;
        }

        body #embudo-main #opportunityModal #saveOpportunityBtn .mobile-hidden {
            display: none !important;
        }

        #embudo-main #form-create-opportunity .form-grid,
        #embudo-main #form-create-opportunity .form-grid-4,
        #embudo-main #form-create-opportunity .form-grid-client {
            grid-template-columns: minmax(0, 1fr) !important;
            gap: 12px !important;
        }

        #embudo-main #modalNewCustomerBlock {
            padding: 14px !important;
            margin-bottom: 14px !important;
        }

        #embudo-main #modalCustomerResults {
            max-height: min(36dvh, 260px) !important;
        }
    }

    /* =========================================================
       Kanban V8: command bar compacta + interacción de tablero
       ========================================================= */
    #embudo-main .content.flex-content {
        padding-top: 14px !important;
        gap: 10px !important;
    }

    #embudo-main .kanban-commandbar {
        flex: 0 0 auto !important;
        min-width: 0 !important;
        display: flex !important;
        align-items: center !important;
        gap: 10px !important;
        padding: 8px 10px !important;
        margin: 0 !important;
        background: var(--surface-1) !important;
        border: 1px solid var(--border-default) !important;
        border-radius: var(--radius-xl) !important;
        box-shadow: var(--shadow-sm) !important;
    }

    #embudo-main .kanban-command-title {
        flex: 0 0 170px !important;
        min-width: 0 !important;
        padding: 0 4px !important;
    }

    #embudo-main .kanban-title-row {
        display: flex !important;
        align-items: center !important;
        gap: 8px !important;
    }

    #embudo-main .kanban-title-row h1 {
        margin: 0 !important;
        font-size: 1.08rem !important;
        line-height: 1.1 !important;
        letter-spacing: -0.02em !important;
    }

    #embudo-main .kanban-live-dot {
        width: 7px !important;
        height: 7px !important;
        border-radius: 50% !important;
        background: var(--color-success) !important;
        box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-success) 14%, transparent) !important;
    }

    #embudo-main .kanban-summary {
        margin-top: 3px !important;
        color: var(--text-muted) !important;
        font-size: 0.73rem !important;
        line-height: 1.2 !important;
        white-space: nowrap !important;
        overflow: hidden !important;
        text-overflow: ellipsis !important;
    }

    #embudo-main .kanban-summary strong { color: var(--text-secondary) !important; }

    #embudo-main .kanban-search {
        flex: 1 1 420px !important;
        min-width: 180px !important;
        margin: 0 !important;
    }

    #embudo-main .kanban-owner {
        flex: 0 0 190px !important;
        margin: 0 !important;
    }

    #embudo-main .kanban-commandbar .input,
    #embudo-main .kanban-commandbar .select,
    #embudo-main .kanban-commandbar .btn,
    #embudo-main .kanban-commandbar .icon-btn {
        min-height: 40px !important;
        height: 40px !important;
    }

    #embudo-main .kanban-command-actions {
        flex: 0 0 auto !important;
        display: flex !important;
        align-items: center !important;
        justify-content: flex-end !important;
        gap: 8px !important;
    }

    #embudo-main .kanban-icon-action {
        width: 40px !important;
        min-width: 40px !important;
        border: 1px solid var(--border-default) !important;
        background: var(--surface-1) !important;
    }

    #embudo-main .kanban-archive-btn,
    #embudo-main .kanban-new-btn { padding-inline: 13px !important; }

    #embudo-main .kanban-report-menu {
        position: relative !important;
        flex: 0 0 auto !important;
    }

    #embudo-main .kanban-report-menu > summary {
        list-style: none !important;
        flex: 0 0 auto !important;
        white-space: nowrap !important;
        cursor: pointer !important;
    }

    #embudo-main .kanban-report-menu > summary::-webkit-details-marker {
        display: none !important;
    }

    #embudo-main .kanban-report-menu[open] > summary {
        background: var(--surface-2) !important;
        border-color: var(--border-strong) !important;
    }

    #embudo-main .kanban-report-panel {
        position: absolute !important;
        top: calc(100% + 7px) !important;
        right: 0 !important;
        z-index: 140 !important;
        display: grid !important;
        width: 270px !important;
        padding: 7px !important;
        background: var(--surface-1) !important;
        border: 1px solid var(--border-default) !important;
        border-radius: var(--radius-lg) !important;
        box-shadow: var(--shadow-lg) !important;
    }

    #embudo-main .kanban-report-link {
        display: grid !important;
        grid-template-columns: 19px minmax(0, 1fr) !important;
        gap: 0 10px !important;
        align-items: center !important;
        padding: 10px 11px !important;
        border-radius: var(--radius-md) !important;
        color: var(--text-primary) !important;
        text-decoration: none !important;
    }

    #embudo-main .kanban-report-link:hover,
    #embudo-main .kanban-report-link:focus-visible {
        background: var(--surface-2) !important;
    }

    #embudo-main .kanban-report-link svg {
        grid-row: 1 / span 2 !important;
        width: 18px !important;
        height: 18px !important;
        color: var(--text-muted) !important;
    }

    #embudo-main .kanban-report-link strong {
        font-size: 0.82rem !important;
        line-height: 1.25 !important;
    }

    #embudo-main .kanban-report-link small {
        margin-top: 2px !important;
        color: var(--text-muted) !important;
        font-size: 0.7rem !important;
        line-height: 1.3 !important;
    }

    #embudo-main .crm-kanban-wrapper {
        border-radius: var(--radius-xl) !important;
        cursor: grab !important;
        scroll-snap-type: none !important;
        outline: none !important;
    }

    #embudo-main .crm-kanban-wrapper:focus-visible {
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 20%, transparent) !important;
    }

    #embudo-main .crm-kanban-wrapper.is-panning,
    #embudo-main .crm-kanban-wrapper.is-touch-dragging {
        cursor: grabbing !important;
        scroll-behavior: auto !important;
        scroll-snap-type: none !important;
    }

    #embudo-main .crm-kanban-track {
        gap: 12px !important;
        padding: 0 2px 6px !important;
    }

    #embudo-main .crm-column {
        flex-basis: clamp(300px, 23vw, 350px) !important;
        width: clamp(300px, 23vw, 350px) !important;
        min-width: clamp(300px, 23vw, 350px) !important;
        max-width: clamp(300px, 23vw, 350px) !important;
        scroll-snap-align: start !important;
        border-radius: 16px !important;
    }

    #embudo-main .crm-column-header {
        flex-basis: 46px !important;
        min-height: 46px !important;
        padding-inline: 14px !important;
    }

    #embudo-main .crm-column-body {
        padding: 10px !important;
        gap: 10px !important;
        cursor: default !important;
    }

    #embudo-main .crm-opportunity-card {
        padding: 12px !important;
        border-radius: 13px !important;
        box-shadow: 0 1px 0 color-mix(in srgb, var(--text-primary) 4%, transparent) !important;
    }

    #embudo-main .crm-opportunity-card.has-overdue-action {
        border-left: 3px solid var(--color-warning) !important;
    }

    #embudo-main .crm-close-card {
        right: 37px !important;
        color: var(--text-muted) !important;
    }

    #embudo-main .crm-close-card:hover {
        color: var(--color-success) !important;
        background: color-mix(in srgb, var(--color-success) 10%, transparent) !important;
    }

    #embudo-main .stage-menu-trigger { right: 8px !important; }

    #embudo-main .stage-dropdown-separator {
        height: 1px !important;
        margin: 5px 4px !important;
        background: var(--border-subtle) !important;
    }

    #embudo-main .stage-dropdown-close {
        display: flex !important;
        align-items: center !important;
        gap: 8px !important;
        color: var(--text-primary) !important;
    }

    #embudo-main .stage-dropdown-close svg { width: 15px !important; height: 15px !important; color: var(--color-success) !important; }

    #embudo-main .crm-overdue-chip {
        display: inline-flex !important;
        align-items: center !important;
        padding: 2px 7px !important;
        border-radius: 999px !important;
        font-size: 0.69rem !important;
        font-weight: 700 !important;
        color: var(--color-warning) !important;
        background: color-mix(in srgb, var(--color-warning) 11%, transparent) !important;
        border: 1px solid color-mix(in srgb, var(--color-warning) 24%, transparent) !important;
    }

    #embudo-main .crm-card-owner-row {
        display: flex !important;
        align-items: center !important;
        gap: 6px !important;
        min-width: 0 !important;
        margin-top: 8px !important;
        color: var(--text-muted) !important;
        font-size: 0.72rem !important;
    }

    #embudo-main .crm-card-owner-row svg { flex: 0 0 auto !important; width: 13px !important; height: 13px !important; }

    #embudo-main .crm-empty {
        min-height: 100px !important;
        display: flex !important;
        flex-direction: column !important;
        align-items: center !important;
        justify-content: center !important;
        cursor: pointer !important;
        transition: border-color .15s, background .15s, color .15s !important;
    }

    #embudo-main .crm-empty:hover {
        border-color: var(--color-primary) !important;
        background: color-mix(in srgb, var(--color-primary) 4%, transparent) !important;
        color: var(--text-primary) !important;
    }

    #embudo-main .crm-empty strong { font-size: .83rem !important; color: var(--text-secondary) !important; }
    #embudo-main .crm-empty span { margin-top: 2px !important; font-size: .72rem !important; }

    #embudo-main #closeOpportunityModal .product-modal-box { width: min(520px, calc(100vw - 28px)) !important; max-width: 520px !important; }
    #embudo-main #closeOpportunityModal .close-outcome-grid { display:grid !important; grid-template-columns:repeat(2,minmax(0,1fr)) !important; gap:9px !important; }
    #embudo-main #closeOpportunityModal .close-outcome-option { position:relative !important; }
    #embudo-main #closeOpportunityModal .close-outcome-option input { position:absolute !important; opacity:0 !important; pointer-events:none !important; }
    #embudo-main #closeOpportunityModal .close-outcome-option label {
        min-height:62px !important;
        display:flex !important;
        align-items:center !important;
        gap:10px !important;
        padding:11px !important;
        border:1px solid var(--border-default) !important;
        border-radius:12px !important;
        cursor:pointer !important;
        background:var(--surface-1) !important;
    }
    #embudo-main #closeOpportunityModal .close-outcome-option label svg { width:18px !important; height:18px !important; color:var(--text-muted) !important; }
    #embudo-main #closeOpportunityModal .close-outcome-option label span { display:flex !important; flex-direction:column !important; gap:2px !important; }
    #embudo-main #closeOpportunityModal .close-outcome-option label small { color:var(--text-muted) !important; font-size:.69rem !important; }
    #embudo-main #closeOpportunityModal .close-outcome-option input:checked + label {
        border-color:var(--color-primary) !important;
        background:color-mix(in srgb, var(--color-primary) 7%, var(--surface-1)) !important;
        box-shadow:0 0 0 2px color-mix(in srgb, var(--color-primary) 12%, transparent) !important;
    }
    #embudo-main #closeOpportunityModal .close-outcome-option input:checked + label svg { color:var(--color-primary) !important; }

    @media (max-width: 1440px) {
        #embudo-main .kanban-command-title { flex-basis: 130px !important; }
        #embudo-main .kanban-summary { display: none !important; }
        #embudo-main .kanban-owner { flex-basis: 170px !important; }
        #embudo-main .kanban-archive-btn,
        #embudo-main .kanban-report-menu > summary { width:40px !important; min-width:40px !important; padding:0 !important; justify-content:center !important; }
        #embudo-main .kanban-archive-btn span,
        #embudo-main .kanban-report-menu > summary span { display:none !important; }
    }

    @media (max-width: 760px) {
        #embudo-main .content.flex-content { padding-top: 8px !important; gap: 8px !important; }
        #embudo-main .kanban-commandbar {
            display: grid !important;
            grid-template-columns: minmax(0, 1fr) auto !important;
            gap: 8px !important;
            padding: 8px !important;
            border-radius: 15px !important;
        }
        #embudo-main .kanban-command-title { display:none !important; }
        #embudo-main .kanban-search { grid-column:1 / -1 !important; min-width:0 !important; }
        #embudo-main .kanban-owner { grid-column:1 / 2 !important; min-width:0 !important; width:auto !important; }
        #embudo-main .kanban-command-actions { grid-column:2 / 3 !important; gap:6px !important; }
        #embudo-main .kanban-icon-action { display:none !important; }
        #embudo-main .kanban-new-btn { min-width:40px !important; padding-inline:11px !important; }
        #embudo-main .crm-kanban-wrapper {
            scroll-snap-type: x mandatory !important;
            scroll-padding-inline: 0 !important;
            touch-action: none !important;
        }
        #embudo-main .crm-column {
            flex: 0 0 var(--kanban-mobile-column-width, calc(100vw - 24px)) !important;
            flex-basis: var(--kanban-mobile-column-width, calc(100vw - 24px)) !important;
            width: var(--kanban-mobile-column-width, calc(100vw - 24px)) !important;
            min-width: var(--kanban-mobile-column-width, calc(100vw - 24px)) !important;
            max-width: var(--kanban-mobile-column-width, calc(100vw - 24px)) !important;
            scroll-snap-align: start !important;
            scroll-snap-stop: always !important;
        }
        #embudo-main .crm-kanban-track { gap:10px !important; padding-right:0 !important; }
        #embudo-main .crm-column-header { min-height:44px !important; flex-basis:44px !important; }
        #embudo-main #closeOpportunityModal .close-outcome-grid { grid-template-columns:1fr !important; }
    }

    </style>

    <?php require_once '../../layouts/topbar.php'; ?>

    <section class="content flex-content">

        <div class="kanban-commandbar" aria-label="Controles del embudo comercial">
            <div class="kanban-command-title">
                <div class="kanban-title-row">
                    <h1>Embudo</h1>
                    <span class="kanban-live-dot" aria-hidden="true"></span>
                </div>
                <div class="kanban-summary" id="kanbanSummary">
                    <strong id="kanbanActiveCount"><?php echo number_format($activeOpportunityCount, 0, ',', '.'); ?></strong> en tablero ·
                    <strong id="kanbanPipelineValue"><?php echo clp($activePipelineValue); ?></strong>
                </div>
            </div>

            <div class="kanban-search form-field">
                <div class="input-with-icon">
                    <i data-lucide="search"></i>
                    <input type="search" id="filterSearch" class="input" placeholder="Buscar oportunidad, cliente, RUT o ciudad" autocomplete="off" aria-label="Buscar en el embudo">
                </div>
            </div>

            <div class="kanban-owner form-field">
                <select id="filterOwner" class="select" aria-label="Filtrar por responsable">
                    <option value="">Todos los responsables</option>
                    <?php foreach ($assignableUsers as $user): ?>
                        <?php if (in_array($user['role'], ['admin', 'comercial', 'administracion'])): ?>
                            <option value="<?php echo safe_text($user['name']); ?>"><?php echo safe_text($user['name']); ?></option>
                        <?php endif; ?>
                    <?php endforeach; ?>
                </select>
            </div>

            <div class="kanban-command-actions">
                <a class="icon-btn kanban-icon-action" href="/modules/crm/" title="Volver al CRM" aria-label="Volver al CRM"><i data-lucide="arrow-left"></i></a>
                <details class="kanban-report-menu" data-close-outside>
                    <summary class="btn btn-outline" title="Reportes y oportunidades cerradas" aria-label="Abrir reportes del embudo"><i data-lucide="download"></i><span>Reportes</span></summary>
                    <div class="kanban-report-panel">
                        <a class="kanban-report-link" href="/modules/crm/export_pipeline_csv.php" data-no-spa="true">
                            <i data-lucide="file-down"></i><strong>Descargar embudo</strong><small>Exporta las oportunidades visibles y su estado.</small>
                        </a>
                        <a class="kanban-report-link" href="/modules/crm/closed_opportunities.php">
                            <i data-lucide="archive"></i><strong>Oportunidades cerradas</strong><small>Consulta ganadas, perdidas y facturadas.</small>
                        </a>
                    </div>
                </details>
                <a class="btn btn-outline kanban-archive-btn" href="/modules/crm/restock_forecasts.php" title="Reposiciones predictivas"><i data-lucide="calendar-clock"></i><span class="mobile-hidden">Reposiciones</span></a>
                <button type="button" class="btn btn-primary kanban-new-btn" onclick="window.openOpportunityModal('nuevo')" title="Nueva oportunidad"><i data-lucide="plus"></i><span>Nueva <span class="mobile-hidden">oportunidad</span></span></button>
            </div>
        </div>
        
        <?php if (!empty($formErrors)): ?>
            <div class="alert alert-error mb-4" style="flex-shrink: 0;">
                <strong>No fue posible guardar la oportunidad.</strong>
                <span>Revisa los campos e inténtalo nuevamente.</span>
            </div>
        <?php endif; ?>

        <section class="crm-kanban-wrapper" id="kanbanWrapper" tabindex="0" aria-label="Tablero Kanban. Desliza horizontalmente desde cualquier punto. Mantén presionada una tarjeta para moverla entre columnas.">
            <div class="crm-kanban-track" id="kanban-track">

                <?php foreach ($stages as $stageKey => $stageLabel): ?>
                    <div class="crm-column" data-stage="<?php echo $stageKey; ?>">

                        <?php $canCreateInStage = in_array($stageKey, $opportunityCreateStages, true); ?>
                        <div class="crm-column-header">
                            <strong style="font-size: 0.95rem;"><?php echo safe_text($stageLabel); ?></strong>
                            <div class="crm-column-header-actions">
                                <?php if ($canCreateInStage): ?>
                                    <button type="button"
                                            class="btn-create-col"
                                            onclick="window.openOpportunityInStage(event, '<?php echo $stageKey; ?>')"
                                            title="Crear oportunidad en <?php echo safe_text($stageLabel); ?>"
                                            aria-label="Crear oportunidad en <?php echo safe_text($stageLabel); ?>">
                                        <i data-lucide="plus"></i>
                                    </button>
                                <?php endif; ?>
                                <button type="button" class="btn-sort-col" onclick="window.sortColumn('<?php echo $stageKey; ?>', this)" title="Ordenar: Más recientes / Más antiguas">
                                    <i data-lucide="arrow-down" style="width: 14px; height: 14px;"></i>
                                </button>
                                <span class="badge badge-counter" style="font-size: 0.8rem; padding: 2px 8px;"><?php echo count($embudo[$stageKey] ?? []); ?></span>
                            </div>
                        </div>

                        <div class="crm-column-body dropzone<?php echo $canCreateInStage ? ' is-create-enabled' : ''; ?>"
                             data-stage="<?php echo $stageKey; ?>"
                             data-create-stage="<?php echo $canCreateInStage ? $stageKey : ''; ?>"
                             data-sort-dir="desc"
                             title="<?php echo $canCreateInStage ? 'Haz clic en un espacio vacío para crear una oportunidad en ' . safe_text($stageLabel) : 'Suelta una tarjeta aquí para cambiarla a ' . safe_text($stageLabel); ?>">
                            <?php if (!empty($embudo[$stageKey])): ?>
                                <?php foreach ($embudo[$stageKey] as $opportunity): 
                                    $oppId = (int) $opportunity['id'];
                                    $sortTimestamp = strtotime($opportunity['updated_at'] ?? $opportunity['created_at'] ?? 'now');
                                    $isOverdue = !empty($opportunity['next_action_date']) && $opportunity['next_action_date'] < date('Y-m-d');
                                ?>
                                    
                                    <div class="crm-opportunity-card<?php echo $isOverdue ? ' has-overdue-action' : ''; ?>" 
                                         draggable="true" 
                                         data-id="<?php echo $oppId; ?>" 
                                         data-stage="<?php echo $stageKey; ?>" 
                                         data-value="<?php echo (float)$opportunity['expected_value']; ?>"
                                         data-date="<?php echo $sortTimestamp; ?>" 
                                         data-title="<?php echo htmlspecialchars(mb_strtolower($opportunity['title'], 'UTF-8'), ENT_QUOTES, 'UTF-8'); ?>"
                                         data-customer="<?php echo htmlspecialchars(mb_strtolower($opportunity['customer_display_name'] ?? $opportunity['customer_name'], 'UTF-8'), ENT_QUOTES, 'UTF-8'); ?>"
                                         data-search="<?php echo htmlspecialchars(mb_strtolower(implode(' ', array_filter(array($opportunity['title'] ?? '', $opportunity['customer_display_name'] ?? '', $opportunity['customer_commercial_name'] ?? '', $opportunity['customer_name'] ?? '', $opportunity['customer_tax_id'] ?? '', $opportunity['customer_legal_name'] ?? '', $opportunity['customer_email'] ?? '', $opportunity['customer_phone'] ?? '', $opportunity['customer_city'] ?? '', $opportunity['customer_district'] ?? '', $opportunity['customer_region'] ?? '', $opportunity['customer_country'] ?? ''))), 'UTF-8'), ENT_QUOTES, 'UTF-8'); ?>"
                                         data-owner="<?php echo safe_text($opportunity['owner_name'] ?: 'Sistema'); ?>"
                                         onclick="window.openOppViewModal(event, <?php echo $oppId; ?>)">
                                        
                                        <div class="crm-opportunity-header">
                                            <strong style="font-size: 0.9rem; color: var(--text-primary); padding-right: 58px; display: block; line-height: 1.3; word-break: break-word;">
                                                <?php echo safe_text($opportunity['title']); ?>
                                            </strong>
                                            
                                            <button type="button" class="btn-invisible crm-close-card" onclick="window.openCloseOpportunityModal(event, <?php echo $oppId; ?>, <?php echo htmlspecialchars(json_encode($opportunity['title'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>)" title="Cerrar oportunidad" aria-label="Cerrar oportunidad">
                                                <i data-lucide="circle-check-big"></i>
                                            </button>
                                            <button type="button" class="btn-invisible stage-menu-trigger" onclick="window.toggleStageMenu(event, <?php echo $oppId; ?>)" title="Cambiar etapa" aria-label="Cambiar etapa">
                                                <i data-lucide="chevron-down"></i>
                                            </button>
                                            
                                            <div class="stage-dropdown-menu" id="stage-menu-<?php echo $oppId; ?>">
                                                <div style="padding: 8px 12px; font-size: 0.7rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase;">Mover a...</div>
                                                <?php foreach ($stages as $sk => $sl): ?>
                                                    <?php if ($sk !== $stageKey): ?>
                                                        <button type="button" class="stage-dropdown-btn" onclick="window.changeStage(event, <?php echo $oppId; ?>, '<?php echo $sk; ?>', this)">
                                                            <?php echo safe_text($sl); ?>
                                                        </button>
                                                    <?php endif; ?>
                                                <?php endforeach; ?>
                                                <div class="stage-dropdown-separator"></div>
                                                <button type="button" class="stage-dropdown-btn stage-dropdown-close" onclick="window.openCloseOpportunityModal(event, <?php echo $oppId; ?>, <?php echo htmlspecialchars(json_encode($opportunity['title'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>)">
                                                    <i data-lucide="archive"></i><span>Cerrar y archivar</span>
                                                </button>
                                            </div>
                                        </div>

                                        <span class="text-truncate block-truncate" style="color: var(--text-secondary); font-size: 0.8rem; margin-top: 4px;">
                                            <?php echo safe_text($opportunity['customer_display_name'] ?? $opportunity['customer_name']); ?>
                                        </span>

                                        <div class="crm-opportunity-meta">
                                            <span style="color: var(--color-success); font-weight: 650;"><?php echo clp($opportunity['expected_value']); ?></span>
                                            <span class="badge" style="font-size: 0.7rem;"><?php echo (int) $opportunity['probability']; ?>%</span>
                                        </div>

                                        <div class="crm-opportunity-meta crm-card-action-row" style="margin-top: 8px; border-top: 1px dashed var(--border-subtle); padding-top: 8px;">
                                            <span class="text-truncate" style="max-width: 58%;" title="<?php echo safe_text($opportunity['next_action'] ?: 'Sin acción'); ?>">
                                                <?php echo !empty($opportunity['next_action']) ? safe_text($opportunity['next_action']) : 'Sin acción'; ?>
                                            </span>
                                            <?php if ($isOverdue): ?>
                                                <span class="crm-overdue-chip" title="Próxima acción vencida"><?php echo safe_text(date('d-m', strtotime($opportunity['next_action_date']))); ?></span>
                                            <?php else: ?>
                                                <span style="font-size: 0.75rem;">
                                                    <?php echo !empty($opportunity['next_action_date']) ? safe_text(date('d-m', strtotime($opportunity['next_action_date']))) : '—'; ?>
                                                </span>
                                            <?php endif; ?>
                                        </div>
                                        <div class="crm-card-owner-row" title="Responsable comercial">
                                            <i data-lucide="user-round"></i><span class="text-truncate"><?php echo safe_text($opportunity['owner_name'] ?: 'Sin responsable'); ?></span>
                                        </div>
                                    </div>

                                <?php endforeach; ?>
                            <?php else: ?>
                                <div class="crm-empty drop-placeholder<?php echo $canCreateInStage ? ' is-create-empty' : ''; ?>">
                                    <i data-lucide="<?php echo $canCreateInStage ? 'plus-circle' : 'inbox'; ?>" style="margin: 0 auto 8px; color: var(--border-strong);"></i>
                                    <?php if ($canCreateInStage): ?>
                                        <strong>Crear oportunidad</strong><br><span>Haz clic o suelta una tarjeta aquí</span>
                                    <?php else: ?>
                                        <strong>Sin oportunidades</strong><br><span>Suelta una tarjeta aquí para cambiarla de etapa</span>
                                    <?php endif; ?>
                                </div>
                            <?php endif; ?>
                        </div>

                    </div>
                <?php endforeach; ?>

            </div>
        </section>

    </section>
    
    <div id="opportunityModal" class="product-modal-backdrop <?php echo !empty($formErrors) ? 'show' : ''; ?>" style="<?php echo !empty($formErrors) ? 'display: flex;' : ''; ?>">
        <div class="product-modal-box">
            <div class="product-modal-header">
                <div><h2 class="h3">Crear Nueva Oportunidad</h2><span class="text-secondary text-sm">Ingresa los datos para sumar al embudo</span></div>
                <button type="button" class="icon-btn" onclick="window.closeOpportunityModal()"><i data-lucide="x"></i></button>
            </div>
            <div class="product-modal-body">
                <form id="form-create-opportunity" action="/modules/crm/opportunity_store.php" method="POST" data-no-spa="true" style="margin: 0;">
                    
                    <div class="form-grid form-grid-client mb-4">
                        <div class="form-field is-required customer-autocomplete">
                            <label class="label">Cliente</label>
                            <div class="form-inline-control" style="display: flex; gap: 8px; align-items: stretch; width: 100%;">
                                <div style="position: relative; flex: 1; min-width: 0;">
                                    <input class="input" type="text" id="modalCustomerSearch" style="width: 100%;" placeholder="Buscar cliente por nombre o RUT" autocomplete="off" value="<?php echo safe_text($formOld['customer_name_search'] ?? ''); ?>">
                                    <div id="modalCustomerResults"></div>
                                </div>
                                <button class="btn btn-outline" type="button" id="modalNewCustomerBtn" style="flex-shrink: 0; width: 42px !important; min-width: 42px !important; height: 42px; padding: 0; display: flex; justify-content: center; align-items: center;" title="Crear Cliente Nuevo">
                                    <i data-lucide="user-plus"></i>
                                </button>
                            </div>
                            <input type="hidden" name="customer_id" id="modalCustomerId" value="<?php echo safe_text($formOld['customer_id'] ?? ''); ?>" required>
                        </div>
                        <div class="form-field is-required">
                            <label class="label">Título de la oportunidad</label>
                            <input class="input" type="text" name="title" required placeholder="Ej: Venta de Insumos Q3" value="<?php echo safe_text($formOld['title'] ?? ''); ?>">
                        </div>
                    </div>

                    <div id="modalNewCustomerBlock" style="display: none; padding: 16px; background: var(--surface-2); border-radius: var(--radius-lg); margin-bottom: 16px; border: 1px solid var(--border-default);">
                        <h4 class="h4 mb-4">Datos mínimos del cliente</h4>
                        <?php icylab_render_customer_quick_fields(array(
                            'name_field' => 'new_customer_name',
                            'tax_field' => 'new_customer_tax_id',
                            'tax_id' => 'modalCustomerTaxId',
                            'phone_prefix_id' => 'modal_opp_phone_prefix',
                            'phone_number_id' => 'modal_opp_phone_number',
                            'phone_hidden_id' => 'modal_opp_real_phone_input',
                            'show_commercial_name' => true,
                            'values' => $formOld,
                            'errors' => $formErrors,
                            'required' => array('new_customer_name', 'country', 'address', 'district', 'city', 'region'),
                        'html_required' => false
                        )); ?>
                    </div>

                    <div class="form-grid form-grid-4">
                        <div class="form-field is-required"><label class="label">Etapa inicial</label><select class="select" name="stage" id="modalInitialStage" required><?php foreach ($stages as $value => $label): ?><option value="<?php echo safe_text($value); ?>"><?php echo safe_text($label); ?></option><?php endforeach; ?></select></div>
                        <div class="form-field"><label class="label">Estado de cobranza</label><select class="select" name="payment_status"><?php foreach ($paymentStatusOptions as $value => $label): ?><option value="<?php echo safe_text($value); ?>"><?php echo safe_text($label); ?></option><?php endforeach; ?></select></div>
                        <div class="form-field"><label class="label">Fecha vencimiento pago</label><input class="input" type="date" name="payment_due_date"></div>
                        <div class="form-field"><label class="label">Fecha de pago</label><input class="input" type="date" name="payment_paid_date"></div>
                        <div class="form-field">
                            <label class="label">Responsable comercial</label>
                            <select class="select" name="owner_user_id" onchange="this.nextElementSibling.value = this.options[this.selectedIndex].getAttribute('data-name') || '';">
                                <option value="">Sin responsable</option>
                                <?php foreach ($assignableUsers as $user): ?>
                                    <option value="<?php echo (int)$user['id']; ?>" data-name="<?php echo safe_text($user['name']); ?>" <?php echo $user['name'] === $ownerValue ? 'selected' : ''; ?>>
                                        <?php echo safe_text($user['name']); ?>
                                    </option>
                                <?php endforeach; ?>
                            </select>
                            <input type="hidden" name="owner_name" value="<?php echo safe_text($ownerValue ?? ''); ?>">
                        </div>
                        <div class="form-field is-required"><label class="label">Origen</label><select class="select" name="source" required><option value="" disabled selected>Seleccionar origen</option><?php foreach ($sourceOptions as $value => $label): ?><option value="<?php echo safe_text($value); ?>"><?php echo safe_text($label); ?></option><?php endforeach; ?></select></div>
                        <div class="form-field"><label class="label">Competidor / Alternativa</label><select class="select" name="competitor"><?php foreach ($competitorOptions as $value => $label): ?><option value="<?php echo safe_text($value); ?>"><?php echo safe_text($label); ?></option><?php endforeach; ?></select></div>
                        <div class="form-field"><label class="label">Valor esperado ($)</label><input class="input" type="number" name="expected_value" min="0" step="1" placeholder="Ej: 500000"></div>
                        <div class="form-field"><label class="label">Probabilidad (%)</label><input class="input" type="number" name="probability" min="0" max="100" value="20"></div>
                        <div class="form-field is-required"><label class="label">Fecha est. de cierre</label><input class="input" type="date" name="expected_close_date" required></div>
                        <div class="form-field is-required"><label class="label">Próxima acción</label><select class="select" name="next_action" required><?php foreach ($nextActionOptions as $value => $label): ?><option value="<?php echo safe_text($value); ?>"><?php echo safe_text($label); ?></option><?php endforeach; ?></select></div>
                        <div class="form-field is-required"><label class="label">Fecha próxima acción</label><input class="input" type="date" name="next_action_date" required></div>
                        <div class="form-field form-field-full"><label class="label">Notas/ Comentarios</label><textarea class="textarea" name="notes" placeholder="Escribe aquí..."></textarea></div>
                    </div>
                </form>
            </div>
            <div class="product-modal-footer opportunity-modal-footer">
                <button type="button" class="btn btn-outline" onclick="window.closeOpportunityModal()">Cancelar</button>
                <button type="submit" form="form-create-opportunity" class="btn btn-primary" id="saveOpportunityBtn">
                    <i data-lucide="save"></i><span>Crear <span class="mobile-hidden">Oportunidad</span></span>
                </button>
            </div>
        </div>
    </div>


    <div id="closeOpportunityModal" class="product-modal-backdrop" style="display:none;">
        <div class="product-modal-box" role="dialog" aria-modal="true" aria-labelledby="closeOpportunityTitle">
            <div class="product-modal-header">
                <div>
                    <h2 class="h3" id="closeOpportunityTitle">Cerrar oportunidad</h2>
                    <span class="text-secondary text-sm" id="closeOpportunitySubtitle">El registro saldrá del tablero activo y quedará disponible para análisis.</span>
                </div>
                <button type="button" class="icon-btn" onclick="window.closeCloseOpportunityModal()" aria-label="Cerrar"><i data-lucide="x"></i></button>
            </div>
            <div class="product-modal-body">
                <form id="closeOpportunityForm" method="POST" action="/modules/crm/opportunity_close.php" data-no-spa="true" style="margin:0;">
                    <input type="hidden" name="_csrf_token" value="<?php echo safe_text(csrf_token()); ?>">
                    <input type="hidden" name="id" id="closeOpportunityId" value="">

                    <div class="form-field is-required">
                        <label class="label">Resultado del cierre</label>
                        <div class="close-outcome-grid">
                            <div class="close-outcome-option">
                                <input type="radio" id="closeOutcomeWon" name="outcome" value="won" required>
                                <label for="closeOutcomeWon"><i data-lucide="trophy"></i><span><strong>Ganada</strong><small>Acuerdo comercial confirmado</small></span></label>
                            </div>
                            <div class="close-outcome-option">
                                <input type="radio" id="closeOutcomeInvoiced" name="outcome" value="invoiced" required>
                                <label for="closeOutcomeInvoiced"><i data-lucide="receipt-text"></i><span><strong>Facturada</strong><small>Venta emitida y a cobranza</small></span></label>
                            </div>
                            <div class="close-outcome-option">
                                <input type="radio" id="closeOutcomeLost" name="outcome" value="lost" required>
                                <label for="closeOutcomeLost"><i data-lucide="circle-x"></i><span><strong>Perdida</strong><small>Se eligió otra alternativa</small></span></label>
                            </div>
                            <div class="close-outcome-option">
                                <input type="radio" id="closeOutcomeNoDecision" name="outcome" value="no_decision" required>
                                <label for="closeOutcomeNoDecision"><i data-lucide="pause-circle"></i><span><strong>Sin decisión</strong><small>No continuará en el horizonte actual</small></span></label>
                            </div>
                            <div class="close-outcome-option">
                                <input type="radio" id="closeOutcomeCancelled" name="outcome" value="cancelled" required>
                                <label for="closeOutcomeCancelled"><i data-lucide="ban"></i><span><strong>Cancelada</strong><small>Proyecto retirado o cancelado</small></span></label>
                            </div>
                        </div>
                    </div>

                    <div class="form-field" id="closeReasonField">
                        <label class="label" for="closeOpportunityReason">Motivo</label>
                        <select class="select" name="reason" id="closeOpportunityReason">
                            <option value="">Seleccionar motivo</option>
                            <option value="Integrado al proceso habitual del cliente">Integrado al proceso habitual del cliente</option>
                            <option value="Venta facturada">Venta facturada</option>
                            <option value="Precio o presupuesto">Precio o presupuesto</option>
                            <option value="Eligió competidor o alternativa">Eligió competidor o alternativa</option>
                            <option value="Sin respuesta">Sin respuesta</option>
                            <option value="Timing o prioridad interna">Timing o prioridad interna</option>
                            <option value="Proyecto cancelado">Proyecto cancelado</option>
                            <option value="No califica para ICP">No califica para ICP</option>
                            <option value="Otro">Otro</option>
                        </select>
                        <span class="text-muted text-sm" id="closeReasonHelp">Obligatorio para oportunidades perdidas o sin decisión.</span>
                    </div>

                    <div class="form-field">
                        <label class="label" for="closeOpportunityNote">Nota de cierre</label>
                        <textarea class="textarea" name="note" id="closeOpportunityNote" rows="3" placeholder="Contexto útil para análisis y aprendizaje comercial"></textarea>
                    </div>
                </form>
            </div>
            <div class="product-modal-footer opportunity-modal-footer">
                <button type="button" class="btn btn-outline" onclick="window.closeCloseOpportunityModal()">Cancelar</button>
                <button type="submit" form="closeOpportunityForm" class="btn btn-primary" id="closeOpportunitySubmit"><i data-lucide="archive"></i><span>Cerrar y archivar</span></button>
            </div>
        </div>
    </div>

<script src="/assets/js/customer-location.js?v=p4_6_0"></script>
<script>
// =========================================================================
// LÓGICA DE APLICACIÓN PROTEGIDA (SPA SAFE)
// =========================================================================
(function() {
    const embudoCsrfToken = <?php echo json_encode(csrf_token(), JSON_UNESCAPED_SLASHES); ?>;
    window.kanbanDidPan = false;

    // --- MAGIA SPA: INTERCEPTOR GLOBAL PARA ELIMINAR OPORTUNIDADES ---
    // Atrapamos cualquier intento de eliminar una oportunidad desde los modales y lo hacemos silenciosamente.
    if (!window.__embudoGlobalDeleteAttached) {
        document.addEventListener('submit', function(e) {
            const deleteForm = e.target.closest('form[action*="opportunity_delete.php"]');
            if (deleteForm) {
                // Si el evento ya fue prevenido (ej. el usuario canceló el confirm nativo), no hacemos nada
                if (e.defaultPrevented) return;
                
                e.preventDefault();
                
                const btn = deleteForm.querySelector('button[type="submit"]');
                const originalHtml = btn ? btn.innerHTML : '';
                if (btn) {
                    btn.disabled = true;
                    btn.innerHTML = '<i data-lucide="loader" class="spin-icon"></i>';
                    if (window.lucide) window.lucide.createIcons();
                }

                // Agregamos la bandera mágica para que opportunity_delete.php nos responda con JSON
                const formData = new FormData(deleteForm);
                formData.append('ajax', '1');
                const oppId = formData.get('id');

                fetch(deleteForm.action, {
                    method: 'POST',
                    body: formData
                })
                .then(res => res.json())
                .then(data => {
                    if (data.success) {
                        if (window.ICY_SPA_CLEAR_CACHE) window.ICY_SPA_CLEAR_CACHE();
                        // 1. Desaparecemos el modal flotante instantáneamente
                        const backdrop = document.getElementById('oppViewModalBackdrop');
                        if (backdrop) backdrop.remove();
                        
                        // 2. Buscamos la tarjeta en el tablero y la eliminamos sin recargar la página
                        const card = document.querySelector(`.crm-opportunity-card[data-id="${oppId}"]`);
                        if (card) {
                            card.remove();
                            // 3. Recalculamos los contadores de la columna
                            window.updateColumnCounts();
                        } else {
                            // Backup: si por algún motivo no encontramos la tarjeta, recargamos
                            (window.ICY_SPA_RELOAD ? window.ICY_SPA_RELOAD({ force: true }) : window.location.reload());
                        }
                    } else {
                        alert(data.error || 'Error al eliminar la oportunidad.');
                        if (btn) { btn.disabled = false; btn.innerHTML = originalHtml; if (window.lucide) window.lucide.createIcons(); }
                    }
                })
                .catch(err => {
                    alert('Error de conexión al eliminar.');
                    if (btn) { btn.disabled = false; btn.innerHTML = originalHtml; if (window.lucide) window.lucide.createIcons(); }
                });
            }
        });
        window.__embudoGlobalDeleteAttached = true;
    }


    window.removeAccents = function(str) {
        return (str || '').toString().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
    };

    window.applyKanbanFilters = function() {
        const searchInput = document.getElementById('filterSearch');
        const ownerSelect = document.getElementById('filterOwner');
        if (!searchInput || !ownerSelect) return;

        const searchQuery = window.removeAccents(searchInput.value.toLowerCase().trim());
        const ownerFilter = ownerSelect.value.trim();
        const cards = document.querySelectorAll('.crm-opportunity-card');

        cards.forEach(card => {
            const title = window.removeAccents(card.dataset.title);
            const customer = window.removeAccents(card.dataset.customer);
            const searchBlob = window.removeAccents(card.dataset.search || '');
            const owner = (card.dataset.owner || '').trim();

            const matchesSearch = searchQuery === '' || title.includes(searchQuery) || customer.includes(searchQuery) || searchBlob.includes(searchQuery);
            const matchesOwner = ownerFilter === '' || owner === ownerFilter;

            if (matchesSearch && matchesOwner) {
                card.classList.remove('is-hidden');
            } else {
                card.classList.add('is-hidden');
            }
        });
        window.updateColumnCounts();
    };

    window.sortColumn = function(stage, btn) {
        const colBody = document.querySelector(`.crm-column-body[data-stage="${stage}"]`);
        if (!colBody) return;

        const cards = Array.from(colBody.querySelectorAll('.crm-opportunity-card'));
        if (cards.length < 2) return; 

        let currentDir = colBody.dataset.sortDir || 'desc';
        let newDir = currentDir === 'desc' ? 'asc' : 'desc';
        colBody.dataset.sortDir = newDir;

        cards.sort((a, b) => {
            let dateA = parseInt(a.dataset.date) || 0;
            let dateB = parseInt(b.dataset.date) || 0;
            return newDir === 'desc' ? (dateB - dateA) : (dateA - dateB);
        });

        cards.forEach(card => colBody.appendChild(card));

        if (newDir === 'desc') {
            btn.innerHTML = '<i data-lucide="arrow-down" style="width: 14px; height: 14px;"></i>';
            btn.setAttribute('title', 'Ordenar: Más recientes / Más antiguas');
        } else {
            btn.innerHTML = '<i data-lucide="arrow-up" style="width: 14px; height: 14px;"></i>';
            btn.setAttribute('title', 'Ordenar: Más antiguas / Más recientes');
        }

        if (window.lucide) lucide.createIcons();
    };

    window.toggleStageMenu = function(e, oppId) {
        e.preventDefault(); e.stopPropagation();
        document.querySelectorAll('.stage-dropdown-menu').forEach(menu => {
            if (menu.id !== 'stage-menu-' + oppId) menu.classList.remove('is-open');
        });
        var menu = document.getElementById('stage-menu-' + oppId);
        if (menu) menu.classList.toggle('is-open');
    };

    window.changeStage = function(e, oppId, newStage, btnElement) {
        e.preventDefault(); e.stopPropagation();
        btnElement.innerHTML = 'Moviendo...'; btnElement.disabled = true;
        const card = document.querySelector(`.crm-opportunity-card[data-id="${oppId}"]`);
        const targetCol = document.querySelector(`.crm-column-body[data-stage="${newStage}"]`);
        if (card && targetCol) {
            const emptyMsg = targetCol.querySelector('.crm-empty');
            if (emptyMsg) emptyMsg.style.display = 'none';
            
            const currentDir = targetCol.dataset.sortDir || 'desc';
            if (currentDir === 'desc' && targetCol.firstChild) {
                targetCol.insertBefore(card, targetCol.firstChild);
            } else {
                targetCol.appendChild(card); 
            }
            card.dataset.stage = newStage;
        }
        window.executeStageUpdate(oppId, newStage);
    };

    window.executeStageUpdate = function(oppId, newStage) {
        var formData = new FormData();
        formData.append('_csrf_token', embudoCsrfToken);
        formData.append('ajax_update_stage', 'true');
        formData.append('id', oppId);
        formData.append('stage', newStage);
        fetch('/modules/crm/embudo.php', { method: 'POST', body: formData })
            .then(function(response) { return response.json().then(function(data) { return { ok: response.ok, data: data }; }); })
            .then(function(result) {
                if (result.ok && result.data.success) {
                    if (window.ICY_SPA_CLEAR_CACHE) window.ICY_SPA_CLEAR_CACHE();
                    window.updateColumnCounts();
                    window.showKanbanToast('Etapa actualizada');
                    return;
                }
                throw new Error(result.data.error || result.data.message || 'No fue posible mover la oportunidad.');
            })
            .catch(function(error) {
                alert(error.message);
                (window.ICY_SPA_RELOAD ? window.ICY_SPA_RELOAD({ force: true }) : window.location.reload());
            });
    };

    window.updateColumnCounts = function() {
        var visibleTotal = 0;
        var visibleValue = 0;
        document.querySelectorAll('.crm-column').forEach(function(col) {
            const visibleCards = col.querySelectorAll('.crm-opportunity-card:not(.is-hidden)');
            const count = visibleCards.length;
            visibleTotal += count;
            visibleCards.forEach(function(card) { visibleValue += parseFloat(card.dataset.value || '0') || 0; });

            const badge = col.querySelector('.badge-counter');
            if (badge) badge.textContent = count;

            const body = col.querySelector('.crm-column-body');
            let emptyMsg = col.querySelector('.crm-empty');

            if (count === 0) {
                if (!emptyMsg) {
                    const div = document.createElement('div');
                    const canCreate = body && body.classList.contains('is-create-enabled');
                    div.className = 'crm-empty drop-placeholder' + (canCreate ? ' is-create-empty' : '');
                    div.innerHTML = canCreate
                        ? '<i data-lucide="plus-circle"></i><strong>Crear oportunidad</strong><span>Haz clic o suelta una tarjeta aquí</span>'
                        : '<i data-lucide="inbox"></i><strong>Sin oportunidades</strong><span>Suelta una tarjeta aquí para cambiarla de etapa</span>';
                    body.appendChild(div);
                    if (typeof lucide !== 'undefined') lucide.createIcons();
                } else {
                    emptyMsg.style.display = 'flex';
                }
            } else if (emptyMsg) {
                emptyMsg.style.display = 'none';
            }
        });

        const totalEl = document.getElementById('kanbanActiveCount');
        const valueEl = document.getElementById('kanbanPipelineValue');
        if (totalEl) totalEl.textContent = new Intl.NumberFormat('es-CL').format(visibleTotal);
        if (valueEl) valueEl.textContent = new Intl.NumberFormat('es-CL', { style: 'currency', currency: 'CLP', maximumFractionDigits: 0 }).format(visibleValue);
    };

    window.showKanbanToast = function(message) {
        var existing = document.getElementById('kanbanToast');
        if (existing) existing.remove();
        var toast = document.createElement('div');
        toast.id = 'kanbanToast';
        toast.setAttribute('role', 'status');
        toast.style.cssText = 'position:fixed;right:22px;bottom:22px;z-index:1300;display:flex;align-items:center;gap:8px;padding:11px 14px;border:1px solid var(--border-default);border-radius:12px;background:var(--surface-1);box-shadow:var(--shadow-lg);color:var(--text-primary);font-size:.84rem;font-weight:650;';
        toast.innerHTML = '<i data-lucide="check-circle-2" style="width:17px;height:17px;color:var(--color-success);"></i><span></span>';
        toast.querySelector('span').textContent = message;
        document.body.appendChild(toast);
        if (window.lucide) window.lucide.createIcons();
        window.setTimeout(function() { if (toast.parentNode) toast.remove(); }, 2400);
    };


    window.openOppViewModal = function(e, oppId) {
        return window.ICY_OPEN_OPPORTUNITY_MODAL(e, oppId);
    };

    window.openOpportunityModal = function(initialStage) {
        var modal = document.getElementById('opportunityModal');
        var allowedStages = ['nuevo', 'contactado', 'cotizando', 'negociacion'];
        var resolvedStage = allowedStages.indexOf(initialStage) !== -1 ? initialStage : 'nuevo';
        if (!modal) return false;

        var form = document.getElementById('form-create-opportunity');
        if (form) form.reset();
        var customerId = document.getElementById('modalCustomerId');
        var customerSearch = document.getElementById('modalCustomerSearch');
        var newCustomerBlock = document.getElementById('modalNewCustomerBlock');
        if (customerId) customerId.value = '';
        if (customerSearch) customerSearch.value = '';
        if (newCustomerBlock) newCustomerBlock.style.display = 'none';

        var stageSelect = document.getElementById('modalInitialStage');
        if (stageSelect) {
            stageSelect.value = resolvedStage;
            stageSelect.dispatchEvent(new Event('change', { bubbles: true }));
        }

        modal.dataset.initialStage = resolvedStage;
        modal.style.display = 'flex';
        window.setTimeout(function() {
            modal.classList.add('show');
            if (customerSearch && window.matchMedia && !window.matchMedia('(pointer: coarse)').matches) customerSearch.focus();
        }, 10);
        return true;
    };

    window.openOpportunityInStage = function(event, stage) {
        if (event) {
            event.preventDefault();
            event.stopPropagation();
        }
        return window.openOpportunityModal(stage);
    };

    window.handleColumnCreate = function(event, stage) {
        if (window.kanbanDidPan || window.draggedCard || window.kanbanTouchDragActive) return false;
        if (!['nuevo', 'contactado', 'cotizando', 'negociacion'].includes(stage)) return false;
        if (event && event.target && event.target.closest('.crm-opportunity-card, button, a, input, select, textarea, label, .stage-dropdown-menu')) return false;
        return window.openOpportunityModal(stage);
    };

    window.closeOpportunityModal = function() {
        var modal = document.getElementById('opportunityModal');
        if (modal) {
            modal.classList.remove('show');
            setTimeout(function() { modal.style.display = 'none'; }, 200);
        }
    };

    window.openCloseOpportunityModal = function(event, opportunityId, opportunityTitle) {
        if (event) { event.preventDefault(); event.stopPropagation(); }
        document.querySelectorAll('.stage-dropdown-menu').forEach(function(menu) { menu.classList.remove('is-open'); });
        var modal = document.getElementById('closeOpportunityModal');
        var form = document.getElementById('closeOpportunityForm');
        if (!modal || !form) return;
        form.reset();
        document.getElementById('closeOpportunityId').value = opportunityId;
        var subtitle = document.getElementById('closeOpportunitySubtitle');
        if (subtitle) subtitle.textContent = '“' + opportunityTitle + '” saldrá del tablero activo y quedará disponible para análisis.';
        var reason = document.getElementById('closeOpportunityReason');
        if (reason) reason.required = false;
        var card = document.querySelector('.crm-opportunity-card[data-id="' + opportunityId + '"]');
        var stage = card ? card.dataset.stage : '';
        var outcomeByStage = { ganada: 'won', facturada: 'invoiced', perdida: 'lost' };
        var selectedOutcome = outcomeByStage[stage] || '';
        var selectedRadio = selectedOutcome ? form.querySelector('input[name="outcome"][value="' + selectedOutcome + '"]') : null;
        if (selectedRadio) {
            selectedRadio.checked = true;
            selectedRadio.dispatchEvent(new Event('change', { bubbles: true }));
        }
        modal.style.display = 'flex';
        setTimeout(function() { modal.classList.add('show'); }, 10);
        if (window.lucide) window.lucide.createIcons();
    };

    window.closeCloseOpportunityModal = function() {
        var modal = document.getElementById('closeOpportunityModal');
        if (!modal) return;
        modal.classList.remove('show');
        setTimeout(function() { modal.style.display = 'none'; }, 180);
    };

    // --- ENLAZAR EVENTOS DE FORMA SEGURA ---
    const filterSearch = document.getElementById('filterSearch');
    const filterOwner = document.getElementById('filterOwner');

    if (filterSearch) {
        filterSearch.addEventListener('input', window.applyKanbanFilters);
        filterSearch.addEventListener('keyup', window.applyKanbanFilters);
    }
    
    if (filterOwner) {
        filterOwner.addEventListener('change', window.applyKanbanFilters);
    }

    if (!window.__embudoGlobalClicksAttached) {
        document.addEventListener('click', function(e) {
            if (!e.target.closest('.stage-menu-trigger') && !e.target.closest('.stage-dropdown-menu')) {
                document.querySelectorAll('.stage-dropdown-menu').forEach(function(menu) { menu.classList.remove('is-open'); });
            }
            var reportAction = e.target.closest('.kanban-report-link');
            if (reportAction) {
                var reportMenu = reportAction.closest('.kanban-report-menu');
                if (reportMenu) reportMenu.removeAttribute('open');
            }
            var oModal = document.getElementById('opportunityModal');
            if (oModal && e.target === oModal) window.closeOpportunityModal();
            var cModal = document.getElementById('closeOpportunityModal');
            if (cModal && e.target === cModal) window.closeCloseOpportunityModal();
        });
        window.__embudoGlobalClicksAttached = true;
    }

    const closeReasonOptions = {
        won: [
            ['Integrado al proceso habitual del cliente', 'Integrado al proceso habitual del cliente'],
            ['Acuerdo comercial confirmado', 'Acuerdo comercial confirmado'],
            ['Piloto convertido a compra', 'Piloto convertido a compra'],
            ['Otro', 'Otro']
        ],
        invoiced: [
            ['Venta facturada', 'Venta facturada'],
            ['Pedido facturado parcialmente', 'Pedido facturado parcialmente'],
            ['Otro', 'Otro']
        ],
        lost: [
            ['Precio o presupuesto', 'Precio o presupuesto'],
            ['Eligió competidor o alternativa', 'Eligió competidor o alternativa'],
            ['Sin respuesta', 'Sin respuesta'],
            ['Timing o prioridad interna', 'Timing o prioridad interna'],
            ['No califica para ICP', 'No califica para ICP'],
            ['Otro', 'Otro']
        ],
        no_decision: [
            ['Sin respuesta', 'Sin respuesta'],
            ['Timing o prioridad interna', 'Timing o prioridad interna'],
            ['Decisión postergada sin fecha', 'Decisión postergada sin fecha'],
            ['Otro', 'Otro']
        ],
        cancelled: [
            ['Proyecto cancelado', 'Proyecto cancelado'],
            ['Cambio de prioridad del cliente', 'Cambio de prioridad del cliente'],
            ['Cliente cerró operaciones', 'Cliente cerró operaciones'],
            ['Otro', 'Otro']
        ]
    };

    window.updateCloseOutcomeFields = function(outcome) {
        var reason = document.getElementById('closeOpportunityReason');
        var help = document.getElementById('closeReasonHelp');
        var submitText = document.querySelector('#closeOpportunitySubmit span');
        var requiresReason = ['lost', 'cancelled', 'no_decision'].indexOf(outcome) !== -1;
        if (reason) {
            var previous = reason.value;
            reason.innerHTML = '<option value="">Seleccionar motivo</option>';
            (closeReasonOptions[outcome] || []).forEach(function(option) {
                var node = document.createElement('option');
                node.value = option[0];
                node.textContent = option[1];
                reason.appendChild(node);
            });
            reason.required = requiresReason;
            if (Array.from(reason.options).some(function(option) { return option.value === previous; })) reason.value = previous;
            if (!reason.value && outcome === 'won') reason.value = 'Integrado al proceso habitual del cliente';
            if (!reason.value && outcome === 'invoiced') reason.value = 'Venta facturada';
        }
        if (help) help.textContent = requiresReason
            ? 'Obligatorio para este resultado.'
            : (outcome === 'invoiced' ? 'Solo se archivará si existe un DTE emitido y vigente.' : 'Opcional; se usará para análisis comercial.');
        if (submitText) submitText.textContent = outcome === 'invoiced' ? 'Validar y archivar' : 'Cerrar y archivar';
    };

    const closeOutcomeInputs = document.querySelectorAll('#closeOpportunityForm input[name="outcome"]');
    closeOutcomeInputs.forEach(function(input) {
        input.addEventListener('change', function() {
            window.updateCloseOutcomeFields(this.value);
        });
    });

    const closeOpportunityForm = document.getElementById('closeOpportunityForm');
    if (closeOpportunityForm && !closeOpportunityForm.dataset.submitAttached) {
        closeOpportunityForm.addEventListener('submit', function(event) {
            event.preventDefault();
            if (!this.reportValidity()) return;
            const button = document.getElementById('closeOpportunitySubmit');
            const originalHtml = button ? button.innerHTML : '';
            if (button) {
                button.disabled = true;
                button.innerHTML = '<i data-lucide="loader" class="spin-icon"></i><span>Cerrando...</span>';
                if (window.lucide) window.lucide.createIcons();
            }
            const formData = new FormData(this);
            const opportunityId = formData.get('id');
            fetch(this.action, { method: 'POST', body: formData })
                .then(function(response) { return response.json().then(function(data) { return { ok: response.ok, data: data }; }); })
                .then(function(result) {
                    if (!result.ok || !result.data.success) throw new Error(result.data.error || result.data.message || 'No fue posible cerrar la oportunidad.');
                    if (window.ICY_SPA_CLEAR_CACHE) window.ICY_SPA_CLEAR_CACHE();
                    var detailModal = document.getElementById('oppViewModalBackdrop');
                    if (detailModal) detailModal.remove();
                    var card = document.querySelector('.crm-opportunity-card[data-id="' + opportunityId + '"]');
                    if (card) {
                        card.style.transition = 'opacity .18s ease, transform .18s ease';
                        card.style.opacity = '0';
                        card.style.transform = 'scale(.96)';
                        setTimeout(function() { card.remove(); window.updateColumnCounts(); }, 190);
                    } else {
                        window.updateColumnCounts();
                    }
                    window.closeCloseOpportunityModal();
                    window.showKanbanToast('Oportunidad cerrada y archivada');
                })
                .catch(function(error) { alert(error.message); })
                .finally(function() {
                    if (button) {
                        button.disabled = false;
                        button.innerHTML = originalHtml;
                        if (window.lucide) window.lucide.createIcons();
                    }
                });
        });
        closeOpportunityForm.dataset.submitAttached = 'true';
    }

    // --- MANEJO DE ENVÍO MANUAL (CREAR OPORTUNIDAD) ---
    const createOppForm = document.getElementById('form-create-opportunity');
    if (createOppForm && !createOppForm.dataset.customSubmitAttached) {
        createOppForm.addEventListener('submit', function(e) {
            e.preventDefault();
            const btn = document.getElementById('saveOpportunityBtn');
            const originalHtml = btn.innerHTML;
            btn.disabled = true;
            btn.innerHTML = '<i data-lucide="loader" class="spin-icon"></i><span class="mobile-hidden">Guardando...</span>';
            if (window.lucide) window.lucide.createIcons();

            fetch(this.action, {
                method: 'POST',
                body: new FormData(this),
                redirect: 'follow'
            })
            .then(res => {
                const url = new URL(res.url);
                const oppId = url.searchParams.get('id');
                if (oppId) {
                    if (window.ICY_SPA_CLEAR_CACHE) window.ICY_SPA_CLEAR_CACHE();
                    (window.ICY_SPA_GO ? window.ICY_SPA_GO(window.location.pathname + '?open_modal=' + oppId, { replace: true, force: true }) : (window.location.href = window.location.pathname + '?open_modal=' + oppId));
                } else {
                    (window.ICY_SPA_RELOAD ? window.ICY_SPA_RELOAD({ force: true }) : window.location.reload());
                }
            })
            .catch(err => {
                console.error('Error al guardar:', err);
                btn.disabled = false;
                btn.innerHTML = originalHtml;
                if (window.lucide) window.lucide.createIcons();
            });
        });
        createOppForm.dataset.customSubmitAttached = 'true';
    }

    // --- AUTO-ABRIR MODAL SI VENIMOS DE CREAR ---
    <?php if ($openModalId > 0): ?>
        window.history.replaceState({}, document.title, window.location.pathname);
        setTimeout(() => {
            window.openOppViewModal(null, <?php echo $openModalId; ?>);
        }, 400);
    <?php endif; ?>

    // --- NAVEGACION FLUIDA DEL KANBAN: TOUCHPAD, MOUSE, TOUCH Y LONG PRESS ---
    const kanbanWrapper = document.getElementById('kanbanWrapper');
    if (kanbanWrapper && !kanbanWrapper.dataset.navigationAttached) {
        const mobileMedia = window.matchMedia ? window.matchMedia('(max-width: 760px)') : null;
        let gesture = null;
        let longPressTimer = null;
        let touchDrag = null;
        let dragAutoScrollFrame = null;
        let dragAutoScrollLastTime = null;
        let suppressNextClick = false;
        let wheelEndTimer = null;

        const interactiveSelector = 'button, a, input, select, textarea, label, .stage-dropdown-menu';

        const syncMobileColumnWidth = function() {
            if (!mobileMedia || !mobileMedia.matches) {
                kanbanWrapper.style.removeProperty('--kanban-mobile-column-width');
                return;
            }
            const width = Math.max(240, Math.floor(kanbanWrapper.clientWidth));
            kanbanWrapper.style.setProperty('--kanban-mobile-column-width', width + 'px');
        };

        const snapToNearestColumn = function() {
            if (!mobileMedia || !mobileMedia.matches) return;
            const columns = Array.from(kanbanWrapper.querySelectorAll('.crm-column'));
            if (!columns.length) return;
            let nearestIndex = 0;
            let nearestDistance = Math.abs(kanbanWrapper.scrollLeft - columns[0].offsetLeft);
            columns.forEach(function(column, index) {
                const distance = Math.abs(kanbanWrapper.scrollLeft - column.offsetLeft);
                if (distance < nearestDistance) {
                    nearestIndex = index;
                    nearestDistance = distance;
                }
            });
            kanbanWrapper.scrollTo({ left: columns[nearestIndex].offsetLeft, behavior: 'smooth' });
        };

        const snapAfterSwipe = function(completedGesture) {
            if (!mobileMedia || !mobileMedia.matches || !completedGesture) return;
            const columns = Array.from(kanbanWrapper.querySelectorAll('.crm-column'));
            if (!columns.length) return;

            let startIndex = 0;
            let startDistance = Math.abs(completedGesture.startScrollLeft - columns[0].offsetLeft);
            columns.forEach(function(column, index) {
                const distance = Math.abs(completedGesture.startScrollLeft - column.offsetLeft);
                if (distance < startDistance) {
                    startIndex = index;
                    startDistance = distance;
                }
            });

            const deltaX = completedGesture.lastX - completedGesture.startX;
            const threshold = Math.max(42, Math.min(76, kanbanWrapper.clientWidth * 0.16));
            if (Math.abs(deltaX) >= threshold) {
                const direction = deltaX < 0 ? 1 : -1;
                const targetIndex = Math.max(0, Math.min(columns.length - 1, startIndex + direction));
                kanbanWrapper.scrollTo({ left: columns[targetIndex].offsetLeft, behavior: 'smooth' });
                return;
            }

            snapToNearestColumn();
        };

        const clearLongPress = function() {
            if (longPressTimer !== null) {
                window.clearTimeout(longPressTimer);
                longPressTimer = null;
            }
        };

        const markGestureAsNavigation = function() {
            suppressNextClick = true;
            window.kanbanDidPan = true;
        };

        const getDropzoneAtPoint = function(x, y) {
            const element = document.elementFromPoint(x, y);
            if (!element) return null;
            const directZone = element.closest('.dropzone');
            if (directZone) return directZone;
            const column = element.closest('.crm-column');
            return column ? column.querySelector('.dropzone') : null;
        };

        const getDragAfterElement = function(container, y) {
            const draggableElements = Array.from(container.querySelectorAll('.crm-opportunity-card:not(.is-touch-drag-source):not(.is-hidden)'));
            return draggableElements.reduce(function(closest, child) {
                const box = child.getBoundingClientRect();
                const offset = y - box.top - box.height / 2;
                if (offset < 0 && offset > closest.offset) return { offset: offset, element: child };
                return closest;
            }, { offset: Number.NEGATIVE_INFINITY, element: null }).element;
        };

        const setTouchDragTarget = function(zone) {
            if (!touchDrag) return;
            if (touchDrag.targetZone === zone) return;
            if (touchDrag.targetZone) touchDrag.targetZone.classList.remove('drag-over');
            touchDrag.targetZone = zone;
            if (touchDrag.targetZone) touchDrag.targetZone.classList.add('drag-over');
        };

        const updateTouchDragPosition = function(x, y) {
            if (!touchDrag) return;
            touchDrag.x = x;
            touchDrag.y = y;
            touchDrag.ghost.style.left = x + 'px';
            touchDrag.ghost.style.top = y + 'px';
            setTouchDragTarget(getDropzoneAtPoint(x, y));

            const wrapperRect = kanbanWrapper.getBoundingClientRect();
            const horizontalEdge = Math.min(72, wrapperRect.width * 0.16);
            const leftDepth = Math.max(0, wrapperRect.left + horizontalEdge - x);
            const rightDepth = Math.max(0, x - (wrapperRect.right - horizontalEdge));
            const nextEdgeX = leftDepth > 0 ? -1 : (rightDepth > 0 ? 1 : 0);
            if (nextEdgeX !== touchDrag.edgeX) touchDrag.horizontalStepAt = 0;
            touchDrag.edgeX = nextEdgeX;

            const targetRect = touchDrag.targetZone ? touchDrag.targetZone.getBoundingClientRect() : null;
            const verticalEdge = targetRect ? Math.min(58, targetRect.height * 0.14) : 0;
            touchDrag.edgeY = targetRect && y < targetRect.top + verticalEdge ? -12 : (targetRect && y > targetRect.bottom - verticalEdge ? 12 : 0);
        };

        const runTouchDragAutoScroll = function(frameTime) {
            if (!touchDrag) {
                dragAutoScrollFrame = null;
                dragAutoScrollLastTime = null;
                return;
            }
            const elapsed = dragAutoScrollLastTime === null ? 16.67 : Math.min(33.34, Math.max(0, frameTime - dragAutoScrollLastTime));
            const frameScale = elapsed / 16.67;
            dragAutoScrollLastTime = frameTime;
            if (touchDrag.horizontalAnimation) {
                const animation = touchDrag.horizontalAnimation;
                const progress = Math.min(1, Math.max(0, (frameTime - animation.startedAt) / animation.duration));
                const easedProgress = 1 - Math.pow(1 - progress, 3);
                kanbanWrapper.scrollLeft = animation.from + (animation.to - animation.from) * easedProgress;
                if (progress >= 1) touchDrag.horizontalAnimation = null;
            }
            if (!touchDrag.horizontalAnimation && touchDrag.edgeX && (touchDrag.horizontalStepAt === 0 || frameTime - touchDrag.horizontalStepAt >= 850)) {
                const columns = Array.from(kanbanWrapper.querySelectorAll('.crm-column'));
                if (columns.length) {
                    const currentIndex = Math.max(0, Math.min(columns.length - 1, touchDrag.horizontalColumnIndex));
                    const targetIndex = Math.max(0, Math.min(columns.length - 1, currentIndex + touchDrag.edgeX));
                    if (targetIndex !== currentIndex) {
                        touchDrag.horizontalAnimation = {
                            from: kanbanWrapper.scrollLeft,
                            to: columns[targetIndex].offsetLeft,
                            startedAt: frameTime,
                            duration: 280
                        };
                        touchDrag.horizontalColumnIndex = targetIndex;
                    }
                }
                touchDrag.horizontalStepAt = frameTime;
            }
            if (touchDrag.edgeY && touchDrag.targetZone) touchDrag.targetZone.scrollTop += touchDrag.edgeY * frameScale;
            if (touchDrag.edgeX || touchDrag.edgeY) setTouchDragTarget(getDropzoneAtPoint(touchDrag.x, touchDrag.y));
            dragAutoScrollFrame = window.requestAnimationFrame(runTouchDragAutoScroll);
        };

        const beginTouchDrag = function() {
            if (!gesture || !gesture.card || gesture.moved || touchDrag) return;
            clearLongPress();

            const card = gesture.card;
            document.querySelectorAll('#embudo-main .stage-dropdown-menu.is-open').forEach(function(menu) {
                menu.classList.remove('is-open');
            });
            const columns = Array.from(kanbanWrapper.querySelectorAll('.crm-column'));
            const sourceColumnIndex = Math.max(0, columns.indexOf(card.closest('.crm-column')));
            const rect = card.getBoundingClientRect();
            const ghost = card.cloneNode(true);
            ghost.removeAttribute('id');
            ghost.removeAttribute('onclick');
            ghost.setAttribute('aria-hidden', 'true');
            ghost.classList.add('kanban-touch-drag-ghost');
            ghost.querySelectorAll('.stage-dropdown-menu').forEach(function(menu) { menu.remove(); });
            ghost.style.width = rect.width + 'px';
            ghost.style.left = gesture.lastX + 'px';
            ghost.style.top = gesture.lastY + 'px';
            (document.getElementById('embudo-main') || document.body).appendChild(ghost);

            touchDrag = {
                card: card,
                ghost: ghost,
                originalZone: card.closest('.dropzone'),
                targetZone: null,
                originalStage: card.dataset.stage,
                x: gesture.lastX,
                y: gesture.lastY,
                edgeX: 0,
                edgeY: 0,
                horizontalStepAt: 0,
                horizontalColumnIndex: sourceColumnIndex,
                horizontalAnimation: null
            };

            card.classList.add('is-touch-drag-source');
            kanbanWrapper.classList.add('is-touch-dragging');
            window.draggedCard = card;
            window.kanbanTouchDragActive = true;
            markGestureAsNavigation();
            setTouchDragTarget(touchDrag.originalZone);
            if (navigator.vibrate) navigator.vibrate(28);
            dragAutoScrollLastTime = null;
            dragAutoScrollFrame = window.requestAnimationFrame(runTouchDragAutoScroll);
        };

        const finishTouchDrag = function(cancelled) {
            if (!touchDrag) return;
            const state = touchDrag;
            const targetColumn = state.targetZone ? state.targetZone.closest('.crm-column') : null;
            touchDrag = null;

            if (dragAutoScrollFrame !== null) {
                window.cancelAnimationFrame(dragAutoScrollFrame);
                dragAutoScrollFrame = null;
            }
            dragAutoScrollLastTime = null;

            if (!cancelled && state.targetZone) {
                const beforeElement = getDragAfterElement(state.targetZone, state.y);
                if (beforeElement) state.targetZone.insertBefore(state.card, beforeElement);
                else state.targetZone.appendChild(state.card);

                const emptyMsg = state.targetZone.querySelector('.crm-empty');
                if (emptyMsg) emptyMsg.style.display = 'none';

                const newStage = state.targetZone.dataset.stage;
                if (newStage && newStage !== state.originalStage) {
                    state.card.dataset.stage = newStage;
                    window.executeStageUpdate(state.card.dataset.id, newStage);
                }
            }

            if (state.targetZone) state.targetZone.classList.remove('drag-over');
            state.card.classList.remove('is-touch-drag-source');
            if (state.ghost && state.ghost.parentNode) state.ghost.remove();
            kanbanWrapper.classList.remove('is-touch-dragging');
            window.draggedCard = null;
            window.kanbanTouchDragActive = false;
            window.updateColumnCounts();

            if (!cancelled && targetColumn && mobileMedia && mobileMedia.matches) {
                const columns = Array.from(kanbanWrapper.querySelectorAll('.crm-column'));
                const targetIndex = columns.indexOf(targetColumn);
                if (targetIndex >= 0) {
                    window.requestAnimationFrame(function() {
                        kanbanWrapper.scrollTo({ left: columns[targetIndex].offsetLeft, behavior: 'smooth' });
                    });
                }
            }
        };

        const releaseGesture = function(event, cancelled) {
            if (!gesture) return;
            if (event && event.pointerId !== undefined && event.pointerId !== gesture.pointerId) return;
            clearLongPress();

            const completedGesture = gesture;
            const completedMode = completedGesture.mode;
            const pointerId = gesture.pointerId;
            const createStage = gesture.createStage || '';
            const shouldCreate = !cancelled && completedMode === 'pending' && !touchDrag && createStage !== '';
            if (touchDrag) finishTouchDrag(Boolean(cancelled));

            gesture = null;
            kanbanWrapper.classList.remove('is-panning');
            try { kanbanWrapper.releasePointerCapture(pointerId); } catch (error) {}

            if (!cancelled && completedMode === 'horizontal') snapAfterSwipe(completedGesture);
            if (shouldCreate) {
                suppressNextClick = true;
                window.openOpportunityModal(createStage);
            }
            window.setTimeout(function() { window.kanbanDidPan = false; }, 220);
            window.setTimeout(function() { suppressNextClick = false; }, 700);
        };

        const embudoResizeHandler = function() { syncMobileColumnWidth(); };
        const embudoOrientationHandler = function() {
            window.setTimeout(function() {
                syncMobileColumnWidth();
                snapToNearestColumn();
            }, 120);
        };
        const embudoMediaHandler = function() {
            syncMobileColumnWidth();
            snapToNearestColumn();
        };

        syncMobileColumnWidth();
        window.addEventListener('resize', embudoResizeHandler, { passive: true });
        window.addEventListener('orientationchange', embudoOrientationHandler, { passive: true });
        if (mobileMedia && mobileMedia.addEventListener) mobileMedia.addEventListener('change', embudoMediaHandler);

        if (window.ICY_SPA_REGISTER_CLEANUP) {
            window.ICY_SPA_REGISTER_CLEANUP(function() {
                clearLongPress();
                if (wheelEndTimer !== null) window.clearTimeout(wheelEndTimer);
                if (dragAutoScrollFrame !== null) window.cancelAnimationFrame(dragAutoScrollFrame);
                if (touchDrag) finishTouchDrag(true);
                window.removeEventListener('resize', embudoResizeHandler);
                window.removeEventListener('orientationchange', embudoOrientationHandler);
                if (mobileMedia && mobileMedia.removeEventListener) mobileMedia.removeEventListener('change', embudoMediaHandler);
                document.querySelectorAll('.kanban-touch-drag-ghost, #kanbanToast, #oppViewModalBackdrop').forEach(function(node) { node.remove(); });
                window.kanbanTouchDragActive = false;
                window.draggedCard = null;
                window.kanbanDidPan = false;
                if (window.ICY_OPEN_CLOSE_OPPORTUNITY) window.openCloseOpportunityModal = window.ICY_OPEN_CLOSE_OPPORTUNITY;
                if (window.ICY_OPEN_OPPORTUNITY_MODAL) window.openOppViewModal = window.ICY_OPEN_OPPORTUNITY_MODAL;
            });
        }

        // Trackpad horizontal gestures are intercepted in capture phase so they
        // work over cards, headers, empty spaces and vertically scrollable columns.
        kanbanWrapper.addEventListener('wheel', function(event) {
            if (event.ctrlKey || kanbanWrapper.scrollWidth <= kanbanWrapper.clientWidth + 2) return;

            const factor = event.deltaMode === 1 ? 18 : (event.deltaMode === 2 ? kanbanWrapper.clientWidth : 1);
            const deltaX = event.deltaX * factor;
            const deltaY = event.deltaY * factor;
            const columnBody = event.target.closest('.crm-column-body');

            if (Math.abs(deltaX) > 0.5) {
                event.preventDefault();
                kanbanWrapper.scrollLeft += deltaX;
            } else if (event.shiftKey && Math.abs(deltaY) > 0.5) {
                event.preventDefault();
                kanbanWrapper.scrollLeft += deltaY;
            } else if (columnBody && columnBody.scrollHeight > columnBody.clientHeight + 2) {
                const canScrollDown = columnBody.scrollTop + columnBody.clientHeight < columnBody.scrollHeight - 2;
                const canScrollUp = columnBody.scrollTop > 1;
                if ((deltaY > 0 && canScrollDown) || (deltaY < 0 && canScrollUp)) return;
                if (Math.abs(deltaY) > 0.5) {
                    event.preventDefault();
                    kanbanWrapper.scrollLeft += deltaY;
                }
            } else if (Math.abs(deltaY) > 0.5) {
                event.preventDefault();
                kanbanWrapper.scrollLeft += deltaY;
            }

            window.clearTimeout(wheelEndTimer);
            wheelEndTimer = window.setTimeout(function() {
                if (mobileMedia && mobileMedia.matches) snapToNearestColumn();
            }, 140);
        }, { passive: false, capture: true });

        kanbanWrapper.addEventListener('pointerdown', function(event) {
            if (!event.isPrimary || gesture) return;
            if (event.pointerType === 'mouse' && event.button !== 0) return;

            const interactiveTarget = event.target.closest(interactiveSelector);
            if (interactiveTarget) return;
            const card = event.target.closest('.crm-opportunity-card');
            // Desktop mouse keeps native HTML5 card drag. Background mouse panning remains available.
            if (event.pointerType === 'mouse' && card) return;

            const columnBody = event.target.closest('.crm-column-body');
            const createStage = columnBody && columnBody.classList.contains('is-create-enabled') && !card
                ? (columnBody.dataset.createStage || columnBody.dataset.stage || '')
                : '';
            gesture = {
                pointerId: event.pointerId,
                pointerType: event.pointerType,
                startX: event.clientX,
                startY: event.clientY,
                lastX: event.clientX,
                lastY: event.clientY,
                startScrollLeft: kanbanWrapper.scrollLeft,
                startColumnScrollTop: columnBody ? columnBody.scrollTop : 0,
                columnBody: columnBody,
                card: card,
                createStage: createStage,
                mode: 'pending',
                moved: false
            };

            window.kanbanDidPan = false;
            try { kanbanWrapper.setPointerCapture(event.pointerId); } catch (error) {}

            if (event.pointerType !== 'mouse' && card) {
                longPressTimer = window.setTimeout(beginTouchDrag, 460);
            }
        }, { passive: true });

        kanbanWrapper.addEventListener('pointermove', function(event) {
            if (!gesture || event.pointerId !== gesture.pointerId) return;
            gesture.lastX = event.clientX;
            gesture.lastY = event.clientY;

            if (touchDrag) {
                event.preventDefault();
                updateTouchDragPosition(event.clientX, event.clientY);
                return;
            }

            const deltaX = event.clientX - gesture.startX;
            const deltaY = event.clientY - gesture.startY;
            const absX = Math.abs(deltaX);
            const absY = Math.abs(deltaY);

            if (gesture.mode === 'pending' && Math.max(absX, absY) >= 7) {
                gesture.moved = true;
                clearLongPress();
                gesture.mode = absX >= absY * 0.72 ? 'horizontal' : 'vertical';
                markGestureAsNavigation();
                if (gesture.mode === 'horizontal') kanbanWrapper.classList.add('is-panning');
            }

            if (gesture.mode === 'horizontal') {
                event.preventDefault();
                kanbanWrapper.scrollLeft = gesture.startScrollLeft - deltaX;
            } else if (gesture.mode === 'vertical' && gesture.columnBody) {
                event.preventDefault();
                gesture.columnBody.scrollTop = gesture.startColumnScrollTop - deltaY;
            }
        }, { passive: false });

        kanbanWrapper.addEventListener('pointerup', function(event) { releaseGesture(event, false); }, { passive: true });
        kanbanWrapper.addEventListener('pointercancel', function(event) { releaseGesture(event, true); }, { passive: true });
        kanbanWrapper.addEventListener('lostpointercapture', function(event) {
            if (gesture && event.pointerId === gesture.pointerId) releaseGesture(event, Boolean(touchDrag));
        }, { passive: true });

        // Prevent accidental actions after swipe/drag and provide a delegated
        // fallback for browsers that retarget a click after pointer capture.
        kanbanWrapper.addEventListener('click', function(event) {
            if (suppressNextClick) {
                event.preventDefault();
                event.stopPropagation();
                suppressNextClick = false;
                return;
            }

            const body = event.target.closest('.crm-column-body.is-create-enabled');
            if (!body) return;
            if (event.target.closest('.crm-opportunity-card, button, a, input, select, textarea, label, .stage-dropdown-menu')) return;
            event.preventDefault();
            event.stopPropagation();
            window.openOpportunityModal(body.dataset.createStage || body.dataset.stage || 'nuevo');
        }, true);

        kanbanWrapper.addEventListener('contextmenu', function(event) {
            if (window.kanbanTouchDragActive || event.target.closest('.crm-opportunity-card')) {
                event.preventDefault();
            }
        });

        kanbanWrapper.addEventListener('keydown', function(event) {
            if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;
            event.preventDefault();
            const columns = Array.from(kanbanWrapper.querySelectorAll('.crm-column'));
            const step = mobileMedia && mobileMedia.matches && columns.length
                ? columns[0].getBoundingClientRect().width + 10
                : 332;
            kanbanWrapper.scrollBy({ left: event.key === 'ArrowRight' ? step : -step, behavior: 'smooth' });
        });

        kanbanWrapper.dataset.navigationAttached = 'true';
    }

    <?php if ($closeModalOpportunity): ?>
        window.history.replaceState({}, document.title, window.location.pathname);
        setTimeout(function() {
            window.openCloseOpportunityModal(null, <?php echo (int)$closeModalOpportunity['id']; ?>, <?php echo htmlspecialchars(json_encode($closeModalOpportunity['title'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>);
        }, 220);
    <?php endif; ?>

    // --- DRAG AND DROP ---
    const cards = document.querySelectorAll('.crm-opportunity-card');
    const dropzones = document.querySelectorAll('.dropzone');
    const isCoarsePointer = window.matchMedia && window.matchMedia('(pointer: coarse)').matches;
    
    cards.forEach(card => {
        if (isCoarsePointer) {
            card.setAttribute('draggable', 'false');
            return;
        }
        card.addEventListener('dragstart', function(e) { 
            window.draggedCard = this; 
            setTimeout(() => this.classList.add('is-dragging'), 0); 
            e.dataTransfer.effectAllowed = 'move'; 
            e.dataTransfer.setData('text/plain', this.dataset.id); 
        });
        card.addEventListener('dragend', function() { 
            this.classList.remove('is-dragging'); 
            window.draggedCard = null; 
            dropzones.forEach(dz => dz.classList.remove('drag-over')); 
            window.updateColumnCounts(); 
        });
    });
    
    dropzones.forEach(dz => {
        dz.addEventListener('dragover', function(e) { 
            e.preventDefault(); 
            e.dataTransfer.dropEffect = 'move'; 
            if (!window.draggedCard) return;
            if (kanbanWrapper) {
                const rect = kanbanWrapper.getBoundingClientRect();
                const edge = 72;
                if (e.clientX < rect.left + edge) kanbanWrapper.scrollLeft -= 18;
                else if (e.clientX > rect.right - edge) kanbanWrapper.scrollLeft += 18;
            }
            
            const getDragAfterElement = function(container, y) {
                const draggableElements = [...container.querySelectorAll('.crm-opportunity-card:not(.is-dragging):not(.is-hidden)')];
                return draggableElements.reduce((closest, child) => { 
                    const box = child.getBoundingClientRect(); 
                    const offset = y - box.top - box.height / 2; 
                    if (offset < 0 && offset > closest.offset) { return { offset: offset, element: child }; } else { return closest; } 
                }, { offset: Number.NEGATIVE_INFINITY }).element;
            };

            const afterElement = getDragAfterElement(this, e.clientY); 
            if (afterElement == null) { this.appendChild(window.draggedCard); } else { this.insertBefore(window.draggedCard, afterElement); } 
        });
        dz.addEventListener('dragenter', function(e) { e.preventDefault(); this.classList.add('drag-over'); });
        dz.addEventListener('dragleave', function() { this.classList.remove('drag-over'); });
        dz.addEventListener('drop', function(e) { 
            e.preventDefault(); 
            this.classList.remove('drag-over'); 
            if (!window.draggedCard) return; 
            
            const newStage = this.dataset.stage; 
            const currentStage = window.draggedCard.dataset.stage; 
            const emptyMsg = this.querySelector('.crm-empty'); 
            if (emptyMsg) emptyMsg.style.display = 'none'; 
            
            if (newStage !== currentStage) { 
                window.draggedCard.dataset.stage = newStage; 
                const oppId = window.draggedCard.dataset.id; 
                window.executeStageUpdate(oppId, newStage); 
            } 
        });
    });

    // --- AUTOCOMPLETE MODAL CLIENTES ---
    var dbCustomers = <?php echo json_encode(array_map(function($c) { return [
        'id' => (int)$c['id'],
        'name' => !empty($c['commercial_name']) ? $c['commercial_name'] : $c['customer_name'],
        'commercial_name' => $c['commercial_name'] ?? '',
        'customer_name' => $c['customer_name'] ?? '',
        'legal_name' => $c['legal_name'] ?? '',
        'rut' => $c['customer_tax_id'] ?? '',
        'city' => $c['city'] ?? ''
    ]; }, $customers)); ?>;
    var modalSearch = document.getElementById('modalCustomerSearch');
    var modalHidden = document.getElementById('modalCustomerId');
    var modalResults = document.getElementById('modalCustomerResults');
    var newCustomerBlock = document.getElementById('modalNewCustomerBlock');
    var newCustomerBtn = document.getElementById('modalNewCustomerBtn');

    function normalize(text) { 
        if (window.ICY_NORMALIZE_SEARCH) return window.ICY_NORMALIZE_SEARCH(text);
        return (text || '').toString().toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").trim(); 
    }
    function normalizeRutSearch(text) {
        if (window.ICY_NORMALIZE_RUT_SEARCH) return window.ICY_NORMALIZE_RUT_SEARCH(text);
        return normalize(text).replace(/[^0-9k]/g, '');
    }

    function showNewCustomerBlock(show) {
        if (!newCustomerBlock) return;
        newCustomerBlock.style.display = show ? 'block' : 'none';
        newCustomerBlock.querySelectorAll('.is-required input:not([type="hidden"]), .is-required select, .is-required textarea').forEach(function(field) {
            field.required = !!show;
        });
        var opportunityForm = newCustomerBlock.closest('form');
        if (opportunityForm) opportunityForm.dispatchEvent(new Event('icy:opportunity-customer-mode'));
        if (show && window.ICY_CUSTOMER_LOCATION) {
            window.ICY_CUSTOMER_LOCATION.init(newCustomerBlock);
        }
    }
    
    function selectCustomer(c) {
        modalSearch.value = c.name; 
        modalHidden.value = c.id; 
        
        if (modalResults) {
            modalResults.style.display = 'none'; 
            modalResults.innerHTML = '';
        }
        showNewCustomerBlock(false);
        
        if(modalSearch) modalSearch.dispatchEvent(new Event('change', { bubbles: true }));
    }

    if(modalSearch) {
        if(modalResults) {
            modalResults.style.position = 'absolute';
            modalResults.style.width = '100%';
            modalResults.style.zIndex = '1060';
            modalResults.style.boxShadow = 'var(--shadow-lg)';
            modalResults.style.border = '1px solid var(--border-default)';
            modalResults.style.background = 'var(--surface-1)';
            modalResults.style.maxHeight = '220px';
            modalResults.style.overflowY = 'auto';
            modalResults.style.borderRadius = 'var(--radius-lg)';
            modalResults.style.top = '100%';
            modalResults.style.left = '0';
            modalResults.style.display = 'none';
        }

        modalSearch.addEventListener('input', function () {
            modalHidden.value = '';
            var rawQuery = modalSearch.value.trim();
            var query = normalize(rawQuery);
            var rutQuery = normalizeRutSearch(rawQuery);
            if(modalResults) modalResults.innerHTML = '';
            
            if (query.length < 2) {
                if(modalResults) modalResults.style.display = 'none';
                return;
            }
            
            var matches = dbCustomers.filter(function (c) {
                var rawHaystack = [c.name, c.commercial_name, c.customer_name, c.legal_name, c.rut, c.city].filter(Boolean).join(' ');
                var haystack = normalize(rawHaystack);
                var rutHaystack = normalizeRutSearch(rawHaystack);
                return haystack.indexOf(query) !== -1 || (rutQuery.length >= 2 && rutHaystack.indexOf(rutQuery) !== -1);
            }).slice(0, 8);

            if (!matches.length) {
                if(modalResults) {
                    modalResults.innerHTML = '<div style="padding: 12px; color: var(--text-muted); font-size: 0.85rem; text-align: center;">Sin coincidencias. Puedes crear un cliente nuevo.</div>';
                    modalResults.style.display = 'block';
                }
                return;
            }

            matches.forEach(function (c) {
                var button = document.createElement('button');
                button.type = 'button'; 
                button.style.cssText = 'width: 100%; text-align: left; padding: 10px 12px; background: var(--surface-1); border: none; border-bottom: 1px solid var(--border-subtle); cursor: pointer; display: flex; flex-direction: column; transition: background 0.2s;';
                button.innerHTML = '<strong style="color: var(--text-primary); font-size: 0.9rem;">' + (c.name || c.commercial_name || c.legal_name || c.customer_name) + '</strong><span style="color: var(--text-muted); font-size: 0.75rem; margin-top: 2px;">' + [c.legal_name, c.rut, c.city].filter(Boolean).join(' · ') + '</span>';
                
                button.addEventListener('mouseenter', function() { this.style.background = 'var(--surface-2)'; });
                button.addEventListener('mouseleave', function() { this.style.background = 'var(--surface-1)'; });

                button.addEventListener('click', function () { selectCustomer(c); });
                if(modalResults) modalResults.appendChild(button);
            });
            
            if(modalResults) modalResults.style.display = 'block';
        });

        document.addEventListener('click', function(e) {
            if (modalResults && modalSearch && !modalSearch.contains(e.target) && !modalResults.contains(e.target)) {
                modalResults.style.display = 'none';
            }
        });
    }

    if(newCustomerBtn) {
        newCustomerBtn.addEventListener('click', function () {
            var isVis = newCustomerBlock.style.display === 'block';
            if (isVis) { showNewCustomerBlock(false); } else {
                modalHidden.value = ''; modalSearch.value = ''; 
                if(modalResults) { modalResults.innerHTML = ''; modalResults.style.display = 'none'; }
                showNewCustomerBlock(true);
            }
        });
    }

    var rutInput = document.querySelector('input[name="new_customer_tax_id"]');
    if (rutInput) {
        rutInput.addEventListener('input', function (e) {
            if (window.ICY_CUSTOMER_LOCATION && window.ICY_CUSTOMER_LOCATION.countryCode(e.target.closest('form')) !== 'cl') return;
            var value = e.target.value.replace(/[^0-9kK]/g, '');
            if (!value) { e.target.value = ''; return; }
            if (value.length === 1) { e.target.value = value.toUpperCase(); return; }
            var body = value.slice(0, -1);
            var dv = value.slice(-1).toUpperCase();
            body = body.replace(/\B(?=(\d{3})+(?!\d))/g, ".");
            e.target.value = body + '-' + dv;
        });
    }

    var oPrefixSelect = document.getElementById('modal_opp_phone_prefix');
    var oNumberInput = document.getElementById('modal_opp_phone_number');
    var oRealPhone = document.getElementById('modal_opp_real_phone_input');
    if (oPrefixSelect && oNumberInput && oRealPhone) {
        function updateOppPhone() {
            var num = oNumberInput.value.replace(/[^0-9\s-]/g, ''); 
            oNumberInput.value = num;
            if (num.length > 0) oRealPhone.value = oPrefixSelect.value + ' ' + num;
            else oRealPhone.value = '';
        }
        oPrefixSelect.addEventListener('change', updateOppPhone);
        oNumberInput.addEventListener('input', updateOppPhone);
    }

})();
</script>

<?php require_once '../../layouts/footer.php'; ?>
