<?xml version="1.0" encoding="utf-8"?>
<odoo>

    <!-- ================================================================== -->
    <!-- TECHNICIAN DASHBOARD (Redesigned - Task-based Timeline)             -->
    <!-- ================================================================== -->
    <template id="portal_technician_dashboard" name="Technician Dashboard">
        <t t-call="portal.portal_layout">
            <t t-set="breadcrumbs_searchbar" t-value="False"/>
            <t t-set="no_breadcrumbs" t-value="True"/>

            <div class="container py-3 tech-portal">
                <!-- Breadcrumbs -->
                <nav aria-label="breadcrumb" class="mb-3">
                    <ol class="breadcrumb mb-0">
                        <li class="breadcrumb-item"><a href="/my/home">Home</a></li>
                        <li class="breadcrumb-item active">Technician Dashboard</li>
                    </ol>
                </nav>

                <!-- Clock In/Out -->
                <t t-if="clock_enabled">
                    <div class="tech-clock-card mb-3"
                         id="techClockCard"
                         t-att-data-checked-in="'true' if clock_checked_in else 'false'"
                         t-att-data-check-in-time="clock_check_in_time or ''"
                         t-att-data-today-hours="clock_today_hours or 0">
                        <div class="tech-clock-layout">
                            <div class="tech-clock-info">
                                <div class="tech-clock-status-line">
                                    <span t-attf-class="tech-clock-dot {{ 'tech-clock-dot--active' if clock_checked_in else '' }}"/>
                                    <span class="tech-clock-status" id="clockStatusText">
                                        <t t-if="clock_checked_in">Clocked In</t>
                                        <t t-else="">Not Clocked In</t>
                                    </span>
                                </div>
                                <div class="tech-clock-timer" id="clockTimer">00:00:00</div>
                                <div class="tech-clock-hours" id="clockTodayHours">
                                    Today: <t t-esc="'%.1fh' % (clock_today_hours or 0)"/>
                                </div>
                            </div>
                            <div class="tech-clock-action">
                                <div t-attf-class="tech-clock-orb-wrap {{ 'tech-clock-orb-wrap--active' if clock_checked_in else '' }}" id="clockOrbWrap">
                                    <span class="tech-clock-wave tech-clock-wave--1"/>
                                    <span class="tech-clock-wave tech-clock-wave--2"/>
                                    <span class="tech-clock-wave tech-clock-wave--3"/>
                                    <button t-attf-class="tech-clock-orb {{ 'tech-clock-orb--out' if clock_checked_in else '' }}"
                                            id="clockActionBtn" onclick="handleClockAction()">
                                        <svg class="tech-clock-orb-icon" id="clockIconPlay" width="22" height="22" viewBox="0 0 24 24" fill="white"
                                             t-attf-style="display:{{ 'none' if clock_checked_in else 'block' }}">
                                            <polygon points="6 3 20 12 6 21"/>
                                        </svg>
                                        <svg class="tech-clock-orb-icon" id="clockIconStop" width="18" height="18" viewBox="0 0 24 24" fill="white"
                                             t-attf-style="display:{{ 'block' if clock_checked_in else 'none' }}">
                                            <rect x="4" y="4" width="16" height="16" rx="2"/>
                                        </svg>
                                    </button>
                                </div>
                                <span class="tech-clock-label" id="clockBtnLabel">
                                    <t t-if="clock_checked_in">Clock Out</t>
                                    <t t-else="">Clock In</t>
                                </span>
                            </div>
                        </div>
                        <div class="tech-clock-error" id="clockError" style="display:none;">
                            <i class="fa fa-exclamation-triangle"/>
                            <span id="clockErrorText"/>
                        </div>
                    </div>

                    <!-- Missed Clock-Out Reason Modal -->
                    <div class="tech-reason-overlay" id="clockReasonModal" style="display:none;">
                        <div class="tech-reason-backdrop" onclick="document.getElementById('clockReasonModal').style.display='none'"/>
                        <div class="tech-reason-dialog">
                            <div class="tech-reason-header">
                                <i class="fa fa-exclamation-triangle text-warning" style="font-size:1.5rem;"/>
                                <h5>Missed Clock-Out</h5>
                                <p class="text-muted small mb-0">You didn't clock out on your last shift. Please provide details before clocking in.</p>
                            </div>
                            <div class="tech-reason-body">
                                <label class="form-label small fw-semibold" for="clockReasonText">
                                    Reason <span class="text-danger">*</span>
                                </label>
                                <textarea id="clockReasonText" class="form-control mb-2" rows="3"
                                          placeholder="Please explain why you didn't clock out..."/>
                                <label class="form-label small fw-semibold" for="clockReasonTime">
                                    Departure Time <span class="text-muted">(optional)</span>
                                </label>
                                <input type="datetime-local" id="clockReasonTime" class="form-control"/>
                            </div>
                            <div class="tech-reason-footer">
                                <button class="btn btn-sm btn-secondary" onclick="document.getElementById('clockReasonModal').style.display='none'">Cancel</button>
                                <button class="btn btn-sm btn-success" id="clockReasonSubmitBtn" onclick="submitClockReason()">
                                    <i class="fa fa-check"/> Submit
                                </button>
                            </div>
                        </div>
                    </div>
                </t>

                <!-- Quick Stats Bar -->
                <div class="tech-stats-bar mb-4">
                    <div class="tech-stat-card tech-stat-total">
                        <div class="stat-number"><t t-out="total_today"/></div>
                        <div class="stat-label">Today</div>
                    </div>
                    <div class="tech-stat-card tech-stat-remaining">
                        <div class="stat-number"><t t-out="remaining_today"/></div>
                        <div class="stat-label">Remaining</div>
                    </div>
                    <div class="tech-stat-card tech-stat-completed">
                        <div class="stat-number"><t t-out="completed_today"/></div>
                        <div class="stat-label">Done</div>
                    </div>
                </div>

                <!-- Current / Next Task Hero Card -->
                <t t-if="current_task">
                    <div class="tech-hero-card card">
                        <div class="card-header d-flex justify-content-between align-items-center">
                            <h5 class="mb-0"><i class="fa fa-wrench me-2"/>Current Task</h5>
                            <span class="tech-status-badge tech-status-in_progress">In Progress</span>
                        </div>
                        <div class="card-body">
                            <div class="d-flex justify-content-between align-items-start mb-2">
                                <div>
                                    <span t-attf-class="tech-badge tech-badge-#{current_task.task_type}">
                                        <t t-out="dict(current_task._fields['task_type'].selection).get(current_task.task_type, '')"/>
                                    </span>
                                    <span class="ms-2 fw-bold"><t t-out="current_task.name"/></span>
                                </div>
                                <span class="text-muted"><t t-out="current_task.time_start_display"/> - <t t-out="current_task.time_end_display"/></span>
                            </div>
                            <p class="mb-1"><i class="fa fa-user me-1 text-muted"/><t t-out="current_task.client_display_name or 'N/A'"/></p>
                            <p class="mb-2 text-muted"><i class="fa fa-map-marker me-1"/><t t-out="current_task.address_display or 'No address'"/></p>
                            <t t-if="current_task.description">
                                <p class="mb-2 small"><t t-out="current_task.description"/></p>
                            </t>
                            <div class="d-flex gap-2 flex-wrap mt-3">
                                <a t-if="current_task.get_google_maps_url()"
                                   href="#" class="tech-action-btn tech-btn-navigate"
                                   t-att-data-nav-url="current_task.get_google_maps_url()"
                                   t-att-data-nav-addr="current_task.address_display or ''"
                                   onclick="openGoogleMapsNav(this); return false;">
                                    <i class="fa fa-location-arrow"/>Navigate
                                </a>
                                <a t-attf-href="/my/technician/task/#{current_task.id}"
                                   class="tech-action-btn tech-btn-complete">
                                    <i class="fa fa-check"/>Complete
                                </a>
                                <a t-if="current_task.client_display_phone" t-attf-href="tel:#{current_task.client_display_phone}"
                                   class="tech-action-btn tech-btn-call">
                                    <i class="fa fa-phone"/>Call
                                </a>
                            </div>
                        </div>
                    </div>
                </t>
                <t t-elif="next_task">
                    <div class="tech-hero-card card">
                        <div class="card-header d-flex justify-content-between align-items-center">
                            <h5 class="mb-0"><i class="fa fa-arrow-right me-2"/>Next Task</h5>
                            <span class="tech-status-badge tech-status-scheduled">
                                <t t-out="next_task.time_start_display"/>
                            </span>
                        </div>
                        <div class="card-body">
                            <div class="d-flex justify-content-between align-items-start mb-2">
                                <div>
                                    <span t-attf-class="tech-badge tech-badge-#{next_task.task_type}">
                                        <t t-out="dict(next_task._fields['task_type'].selection).get(next_task.task_type, '')"/>
                                    </span>
                                    <span class="ms-2 fw-bold"><t t-out="next_task.name"/></span>
                                </div>
                            </div>
                            <p class="mb-1"><i class="fa fa-user me-1 text-muted"/><t t-out="next_task.client_display_name or 'N/A'"/></p>
                            <p class="mb-1 text-muted"><i class="fa fa-map-marker me-1"/><t t-out="next_task.address_display or 'No address'"/></p>
                            <t t-if="next_task.travel_time_minutes">
                                <p class="mb-2 small text-purple"><i class="fa fa-car me-1"/><t t-out="next_task.travel_time_minutes"/> min drive
                                    <t t-if="next_task.travel_distance_km"> (<t t-out="next_task.travel_distance_km"/> km)</t>
                                </p>
                            </t>
                            <div class="d-flex gap-2 flex-wrap mt-3">
                                <a t-if="next_task.get_google_maps_url()"
                                   href="#" class="tech-action-btn tech-btn-navigate"
                                   t-att-data-nav-url="next_task.get_google_maps_url()"
                                   t-att-data-nav-addr="next_task.address_display or ''"
                                   onclick="openGoogleMapsNav(this); return false;">
                                    <i class="fa fa-location-arrow"/>Navigate
                                </a>
                                <button class="tech-action-btn tech-btn-enroute"
                                        onclick="techTaskAction(this, 'en_route')"
                                        t-att-data-task-id="next_task.id">
                                    <i class="fa fa-road"/>En Route
                                </button>
                                <a t-attf-href="/my/technician/task/#{next_task.id}"
                                   class="tech-action-btn" style="background: #6c757d; color: #fff;">
                                    <i class="fa fa-eye"/>Details
                                </a>
                            </div>
                        </div>
                    </div>
                </t>
                <t t-elif="total_today == 0">
                    <div class="text-center py-5">
                        <i class="fa fa-calendar-check-o fa-3x text-success mb-3" style="display:block;"/>
                        <h4>No tasks scheduled for today</h4>
                        <p class="text-muted">Check tomorrow's schedule or view all your tasks.</p>
                    </div>
                </t>

                <!-- Today's Timeline -->
                <t t-if="today_tasks">
                    <h5 class="mb-3"><i class="fa fa-clock-o me-2"/>Today's Schedule</h5>
                    <div class="tech-timeline mb-4">
                        <t t-foreach="today_tasks" t-as="task">
                            <!-- Travel indicator -->
                            <t t-if="task.travel_time_minutes and not task_first">
                                <div class="tech-travel-indicator">
                                    <i class="fa fa-car me-1"/><t t-out="task.travel_time_minutes"/> min
                                    <t t-if="task.travel_distance_km"> / <t t-out="task.travel_distance_km"/> km</t>
                                </div>
                            </t>
                            <div class="tech-timeline-item">
                                <div t-attf-class="tech-timeline-dot status-#{task.status}"/>
                                <a t-attf-href="/my/technician/task/#{task.id}"
                                   t-attf-class="tech-timeline-card #{'active' if task.status == 'in_progress' else ''}">
                                    <div class="d-flex justify-content-between align-items-start">
                                        <span class="tech-timeline-time">
                                            <t t-out="task.time_start_display"/> - <t t-out="task.time_end_display"/>
                                        </span>
                                        <span t-attf-class="tech-status-badge tech-status-#{task.status}" style="font-size:0.7rem;">
                                            <t t-out="dict(task._fields['status'].selection).get(task.status, '')"/>
                                        </span>
                                    </div>
                                    <div class="tech-timeline-title">
                                        <span t-attf-class="tech-badge tech-badge-#{task.task_type} me-1">
                                            <t t-out="dict(task._fields['task_type'].selection).get(task.task_type, '')"/>
                                        </span>
                                        <t t-out="task.client_display_name or task.name"/>
                                    </div>
                                    <div class="tech-timeline-meta">
                                        <i class="fa fa-map-marker me-1"/><t t-out="task.address_city or 'No address'"/>
                                        <t t-if="task.sale_order_id">
                                            <span class="ms-2"><i class="fa fa-file-text-o me-1"/><t t-out="task.sale_order_id.name"/></span>
                                        </t>
                                    </div>
                                </a>
                            </div>
                        </t>
                    </div>
                </t>

                <!-- Quick Links -->
                <div class="tech-quick-links mb-4">
                    <a href="/my/technician/tasks" class="tech-quick-link tech-quick-link-primary">
                        <i class="fa fa-list"/>
                        <span>All Tasks</span>
                    </a>
                    <a href="/my/technician/tomorrow" class="tech-quick-link tech-quick-link-secondary">
                        <i class="fa fa-calendar"/>
                        <span>Tomorrow</span>
                        <t t-if="tomorrow_count">
                            <span class="tech-quick-link-badge"><t t-out="tomorrow_count"/></span>
                        </t>
                    </a>
                    <a href="/repair-form" class="tech-quick-link tech-quick-link-warning">
                        <i class="fa fa-wrench"/>
                        <span>Repair Form</span>
                    </a>
                </div>

                <!-- My Start Location -->
                <div class="tech-card mb-4">
                    <div class="d-flex align-items-center mb-2">
                        <div class="tech-card-icon bg-primary-subtle text-primary" style="width:36px;height:36px;border-radius:10px;display:flex;align-items:center;justify-content:center;margin-right:0.75rem;">
                            <i class="fa fa-home"/>
                        </div>
                        <div>
                            <div class="fw-semibold" style="font-size:0.9rem;">My Start Location</div>
                            <div class="text-muted small">Where your day starts (for travel time calculations)</div>
                        </div>
                    </div>
                    <div class="input-group">
                        <input type="text" class="form-control" id="startLocationInput"
                               t-att-value="start_address or ''"
                               placeholder="e.g. 123 Main St, Brampton, ON"
                               style="border-radius:10px 0 0 10px;"/>
                        <button class="btn btn-primary" onclick="saveStartLocation()" id="saveStartBtn"
                                style="border-radius:0 10px 10px 0;">
                            <i class="fa fa-save"/>
                        </button>
                    </div>
                    <t t-if="not start_address">
                        <div class="text-muted small mt-1">
                            <i class="fa fa-info-circle me-1"/>Using company default location. Set yours above.
                        </div>
                    </t>
                    <span id="startLocStatus" class="small text-muted"></span>
                </div>
            </div>

            <!-- Clock In/Out JS -->
            <script type="text/javascript">
                (function() {
                    var card = document.getElementById('techClockCard');
                    if (!card) return;

                    var isCheckedIn = card.dataset.checkedIn === 'true';
                    var checkInTime = card.dataset.checkInTime ? new Date(card.dataset.checkInTime + 'Z') : null;
                    var timerInterval = null;

                    function updateTimer() {
                        if (!checkInTime) return;
                        var diff = Math.max(0, Math.floor((new Date() - checkInTime) / 1000));
                        var h = Math.floor(diff / 3600);
                        var m = Math.floor((diff % 3600) / 60);
                        var s = diff % 60;
                        var pad = function(n) { return n &lt; 10 ? '0' + n : '' + n; };
                        document.getElementById('clockTimer').textContent = pad(h) + ':' + pad(m) + ':' + pad(s);
                    }

                    function startTimer() {
                        stopTimer();
                        updateTimer();
                        timerInterval = setInterval(updateTimer, 1000);
                    }

                    function stopTimer() {
                        if (timerInterval) { clearInterval(timerInterval); timerInterval = null; }
                    }

                    function applyState() {
                        var dot = card.querySelector('.tech-clock-dot');
                        var statusEl = document.getElementById('clockStatusText');
                        var btn = document.getElementById('clockActionBtn');
                        var timerEl = document.getElementById('clockTimer');
                        var labelEl = document.getElementById('clockBtnLabel');
                        var orbWrap = document.getElementById('clockOrbWrap');
                        var playIcon = document.getElementById('clockIconPlay');
                        var stopIcon = document.getElementById('clockIconStop');

                        if (dot) dot.className = 'tech-clock-dot' + (isCheckedIn ? ' tech-clock-dot--active' : '');
                        if (statusEl) statusEl.textContent = isCheckedIn ? 'Clocked In' : 'Not Clocked In';
                        if (btn) {
                            btn.className = 'tech-clock-orb' + (isCheckedIn ? ' tech-clock-orb--out' : '');
                        }
                        if (orbWrap) {
                            orbWrap.className = 'tech-clock-orb-wrap' + (isCheckedIn ? ' tech-clock-orb-wrap--active' : '');
                        }
                        if (playIcon) playIcon.style.display = isCheckedIn ? 'none' : 'block';
                        if (stopIcon) stopIcon.style.display = isCheckedIn ? 'block' : 'none';
                        if (labelEl) labelEl.textContent = isCheckedIn ? 'Clock Out' : 'Clock In';
                        if (!isCheckedIn &amp;&amp; timerEl) timerEl.textContent = '00:00:00';
                    }

                    if (isCheckedIn &amp;&amp; checkInTime) startTimer();

                    function showClockError(msg) {
                        var errEl = document.getElementById('clockError');
                        var errText = document.getElementById('clockErrorText');
                        var btn = document.getElementById('clockActionBtn');
                        if (errText) errText.textContent = msg;
                        if (errEl) errEl.style.display = 'flex';
                        if (btn) btn.disabled = false;
                    }

                    function doClockAction(lat, lng, accuracy) {
                        var btn = document.getElementById('clockActionBtn');
                        var errEl = document.getElementById('clockError');

                        fetch('/fusion_clock/clock_action', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({jsonrpc: '2.0', id: 1, method: 'call', params: {
                                latitude: lat,
                                longitude: lng,
                                accuracy: accuracy,
                                source: 'portal'
                            }})
                        })
                        .then(function(r) {
                            if (!r.ok) {
                                throw new Error('HTTP ' + r.status);
                            }
                            return r.json();
                        })
                        .then(function(data) {
                            if (data.error) {
                                var msg = (data.error.data &amp;&amp; data.error.data.message) || data.error.message || 'Server error';
                                showClockError(msg);
                                return;
                            }
                            var result = data.result;
                            if (!result) {
                                showClockError('No response from server. Please try again.');
                                return;
                            }
                            if (result.error) {
                                showClockError(result.error);
                                return;
                            }
                            if (result.requires_reason) {
                                var modal = document.getElementById('clockReasonModal');
                                if (modal) modal.style.display = 'flex';
                                btn.disabled = false;
                                return;
                            }
                            if (result.action === 'clock_in') {
                                isCheckedIn = true;
                                checkInTime = new Date(result.check_in + 'Z');
                                startTimer();
                            } else if (result.action === 'clock_out') {
                                isCheckedIn = false;
                                checkInTime = null;
                                stopTimer();
                            } else {
                                showClockError(result.message || 'Unexpected response. Please try again.');
                                return;
                            }
                            applyState();
                            btn.disabled = false;
                        })
                        .catch(function(e) {
                            showClockError('Network error. Please try again.');
                        });
                    }

                    window.submitClockReason = function() {
                        var reasonEl = document.getElementById('clockReasonText');
                        var timeEl = document.getElementById('clockReasonTime');
                        var submitBtn = document.getElementById('clockReasonSubmitBtn');
                        var reason = reasonEl ? reasonEl.value.trim() : '';

                        if (!reason) {
                            showClockError('Please provide a reason.');
                            return;
                        }

                        submitBtn.disabled = true;
                        submitBtn.innerHTML = '&lt;i class="fa fa-spinner fa-spin">&lt;/i> Submitting...';

                        var rawTime = timeEl ? timeEl.value.trim() : '';
                        var depTime = rawTime ? new Date(rawTime).toISOString() : '';
                        fetch('/fusion_clock/submit_reason', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({jsonrpc: '2.0', id: 1, method: 'call', params: {
                                reason: reason,
                                departure_time: depTime
                            }})
                        })
                        .then(function(r) { return r.json(); })
                        .then(function(data) {
                            submitBtn.disabled = false;
                            submitBtn.innerHTML = '&lt;i class="fa fa-check">&lt;/i> Submit';

                            if (data.error) {
                                showClockError((data.error.data &amp;&amp; data.error.data.message) || data.error.message || 'Server error');
                                return;
                            }
                            var result = data.result || {};
                            if (result.success) {
                                var modal = document.getElementById('clockReasonModal');
                                if (modal) modal.style.display = 'none';
                                if (reasonEl) reasonEl.value = '';
                                if (timeEl) timeEl.value = '';
                                var errEl = document.getElementById('clockError');
                                if (errEl) errEl.style.display = 'none';
                                handleClockAction();
                            } else {
                                showClockError(result.error || 'Failed to submit reason.');
                            }
                        })
                        .catch(function() {
                            submitBtn.disabled = false;
                            submitBtn.innerHTML = '&lt;i class="fa fa-check">&lt;/i> Submit';
                            showClockError('Network error. Please try again.');
                        });
                    };

                    window.handleClockAction = function() {
                        var btn = document.getElementById('clockActionBtn');
                        var errEl = document.getElementById('clockError');
                        var errText = document.getElementById('clockErrorText');
                        btn.disabled = true;
                        errEl.style.display = 'none';

                        if (!navigator.geolocation) {
                            doClockAction(0, 0, 0);
                            return;
                        }

                        navigator.geolocation.getCurrentPosition(
                            function(pos) {
                                doClockAction(pos.coords.latitude, pos.coords.longitude, pos.coords.accuracy);
                            },
                            function() {
                                fetch('https://ipapi.co/json/')
                                    .then(function(r) { return r.json(); })
                                    .then(function(ipData) {
                                        var lat = (ipData.latitude &amp;&amp; ipData.longitude) ? ipData.latitude : 0;
                                        var lng = (ipData.latitude &amp;&amp; ipData.longitude) ? ipData.longitude : 0;
                                        doClockAction(lat, lng, lat ? 5000 : 0);
                                    })
                                    .catch(function() {
                                        doClockAction(0, 0, 0);
                                    });
                            },
                            { enableHighAccuracy: true, timeout: 15000, maximumAge: 0 }
                        );
                    };
                })();
            </script>

            <!-- Inline JS for task actions -->
            <script type="text/javascript">
                function techTaskAction(btn, action) {
                    var taskId = btn.dataset.taskId;
                    var origHtml = btn.innerHTML;
                    btn.disabled = true;
                    btn.innerHTML = '<i class="fa fa-spinner fa-spin"></i> Getting location...';
                    window.fusionGetLocation().then(function(coords) {
                        btn.innerHTML = '<i class="fa fa-spinner fa-spin"></i> ...';
                        fetch('/my/technician/task/' + taskId + '/action', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({jsonrpc: '2.0', method: 'call', params: {
                                action: action,
                                latitude: coords.latitude,
                                longitude: coords.longitude,
                                accuracy: coords.accuracy
                            }})
                        })
                        .then(function(r) { return r.json(); })
                        .then(function(data) {
                            if (data.result &amp;&amp; data.result.success) {
                                window.location.reload();
                            } else {
                                alert(data.result ? data.result.error : 'Error');
                                btn.disabled = false;
                                btn.innerHTML = origHtml;
                            }
                        })
                        .catch(function() {
                            alert('Network error. Please try again.');
                            btn.disabled = false;
                            btn.innerHTML = origHtml;
                        });
                    }).catch(function() {
                        alert('Location access is required. Please enable GPS and try again.');
                        btn.disabled = false;
                        btn.innerHTML = origHtml;
                    });
                }

                function saveStartLocation() {
                    var input = document.getElementById('startLocationInput');
                    var btn = document.getElementById('saveStartBtn');
                    var status = document.getElementById('startLocStatus');
                    var address = input.value.trim();
                    btn.disabled = true;
                    btn.innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
                    status.textContent = '';
                    fetch('/my/technician/settings/start-location', {
                        method: 'POST',
                        headers: {'Content-Type': 'application/json'},
                        body: JSON.stringify({jsonrpc: '2.0', method: 'call', params: {address: address}})
                    })
                    .then(function(r) { return r.json(); })
                    .then(function(data) {
                        btn.disabled = false;
                        btn.innerHTML = '<i class="fa fa-save"></i>';
                        if (data.result &amp;&amp; data.result.success) {
                            status.textContent = 'Saved!';
                            status.className = 'small text-success';
                            setTimeout(function() { status.textContent = ''; }, 3000);
                        } else {
                            status.textContent = data.result ? data.result.error : 'Error saving';
                            status.className = 'small text-danger';
                        }
                    })
                    .catch(function() {
                        btn.disabled = false;
                        btn.innerHTML = '<i class="fa fa-save"></i>';
                        status.textContent = 'Network error';
                        status.className = 'small text-danger';
                    });
                }

                /* Google Places Autocomplete for Start Location */
                function initStartLocationAutocomplete() {
                    var input = document.getElementById('startLocationInput');
                    if (!input || !window.google || !google.maps || !google.maps.places) return;
                    var autocomplete = new google.maps.places.Autocomplete(input, {
                        types: ['address'],
                        componentRestrictions: {country: 'ca'},
                        fields: ['formatted_address']
                    });
                    autocomplete.addListener('place_changed', function() {
                        var place = autocomplete.getPlace();
                        if (place &amp;&amp; place.formatted_address) {
                            input.value = place.formatted_address;
                        }
                    });
                }
            </script>
            <!-- Load Google Maps Places API for autocomplete -->
            <t t-if="google_maps_api_key">
                <script t-attf-src="https://maps.googleapis.com/maps/api/js?key=#{google_maps_api_key}&amp;libraries=places&amp;callback=initStartLocationAutocomplete"
                        async="" defer=""/>
            </t>
        </t>
    </template>

    <!-- ================================================================== -->
    <!-- TECHNICIAN TASKS LIST                                               -->
    <!-- ================================================================== -->
    <template id="portal_technician_tasks" name="Technician Tasks List">
        <t t-call="portal.portal_layout">
            <t t-set="breadcrumbs_searchbar" t-value="False"/>
            <t t-set="no_breadcrumbs" t-value="True"/>

            <div class="container py-3 tech-portal">
                <nav aria-label="breadcrumb" class="mb-3">
                    <ol class="breadcrumb mb-0">
                        <li class="breadcrumb-item"><a href="/my/home">Home</a></li>
                        <li class="breadcrumb-item"><a href="/my/technician">Dashboard</a></li>
                        <li class="breadcrumb-item active">All Tasks</li>
                    </ol>
                </nav>

                <h3 class="mb-3"><i class="fa fa-tasks me-2"/>My Tasks</h3>

                <!-- Filters -->
                <div class="row mb-3 g-2">
                    <div class="col-md-6">
                        <form method="GET" action="/my/technician/tasks">
                            <div class="input-group">
                                <input type="text" name="search" class="form-control"
                                       placeholder="Search client, task #, city..."
                                       t-att-value="search"/>
                                <button type="submit" class="btn btn-primary"><i class="fa fa-search"/></button>
                            </div>
                            <input type="hidden" name="filter_status" t-att-value="filter_status"/>
                        </form>
                    </div>
                    <div class="col-md-6">
                        <div class="d-flex gap-1 flex-wrap justify-content-md-end">
                            <a t-attf-href="/my/technician/tasks?filter_status=all"
                               t-attf-class="btn btn-sm btn-outline-secondary #{'active' if filter_status == 'all' else ''}">All</a>
                            <a t-attf-href="/my/technician/tasks?filter_status=active"
                               t-attf-class="btn btn-sm btn-outline-primary #{'active' if filter_status == 'active' else ''}">Active</a>
                            <a t-attf-href="/my/technician/tasks?filter_status=scheduled"
                               t-attf-class="btn btn-sm btn-outline-info #{'active' if filter_status == 'scheduled' else ''}">Scheduled</a>
                            <a t-attf-href="/my/technician/tasks?filter_status=in_progress"
                               t-attf-class="btn btn-sm btn-outline-warning #{'active' if filter_status == 'in_progress' else ''}">In Progress</a>
                            <a t-attf-href="/my/technician/tasks?filter_status=completed"
                               t-attf-class="btn btn-sm btn-outline-success #{'active' if filter_status == 'completed' else ''}">Completed</a>
                        </div>
                    </div>
                </div>

                <!-- Tasks Cards (mobile-friendly) -->
                <t t-foreach="tasks" t-as="task">
                    <a t-attf-href="/my/technician/task/#{task.id}" class="tech-timeline-card mb-2">
                        <div class="d-flex justify-content-between align-items-start">
                            <div>
                                <span t-attf-class="tech-badge tech-badge-#{task.task_type}">
                                    <t t-out="dict(task._fields['task_type'].selection).get(task.task_type, '')"/>
                                </span>
                                <strong class="ms-1"><t t-out="task.name"/></strong>
                            </div>
                            <span t-attf-class="tech-status-badge tech-status-#{task.status}">
                                <t t-out="dict(task._fields['status'].selection).get(task.status, '')"/>
                            </span>
                        </div>
                        <div class="mt-1">
                            <span class="text-muted me-3">
                                <i class="fa fa-calendar me-1"/><t t-out="task.scheduled_date" t-options="{'widget': 'date'}"/>
                                <span class="ms-1"><t t-out="task.time_start_display"/></span>
                            </span>
                            <span>
                                <i class="fa fa-user me-1"/><t t-out="task.client_display_name or '-'"/>
                            </span>
                        </div>
                        <div class="text-muted small mt-1">
                            <i class="fa fa-map-marker me-1"/><t t-out="task.address_city or 'No location'"/>
                            <t t-if="task.sale_order_id">
                                <span class="ms-2"><i class="fa fa-file-text-o me-1"/><t t-out="task.sale_order_id.name"/></span>
                            </t>
                        </div>
                    </a>
                </t>
                <t t-if="not tasks">
                    <div class="text-center py-5 text-muted">
                        <i class="fa fa-inbox fa-3x mb-2" style="display:block;"/>
                        <p>No tasks found</p>
                    </div>
                </t>

                <!-- Pager -->
                <t t-if="pager">
                    <div class="d-flex justify-content-center mt-3">
                        <t t-call="portal.pager"/>
                    </div>
                </t>
            </div>
        </t>
    </template>

    <!-- ================================================================== -->
    <!-- TECHNICIAN TASK DETAIL                                              -->
    <!-- ================================================================== -->
    <template id="portal_technician_task_detail" name="Technician Task Detail">
        <t t-call="portal.portal_layout">
            <t t-set="breadcrumbs_searchbar" t-value="False"/>
            <t t-set="no_breadcrumbs" t-value="True"/>

            <!-- Sequential enforcement: must complete earlier tasks first -->
            <t t-if="earlier_incomplete">
                <div class="container py-3">
                    <div class="alert alert-warning text-center" style="border-radius:12px;">
                        <h5><i class="fa fa-exclamation-triangle"/> Complete Previous Task First</h5>
                        <p class="mb-2">You need to complete
                            <strong><t t-out="earlier_incomplete.name"/></strong>
                            (<t t-out="earlier_incomplete.time_start_display"/>) before starting this task.
                        </p>
                        <a t-attf-href="/my/technician/task/#{earlier_incomplete.id}"
                           class="btn btn-warning">
                            <i class="fa fa-arrow-left"/> Go to <t t-out="earlier_incomplete.name"/>
                        </a>
                    </div>
                </div>
            </t>

            <div class="container py-3 tech-portal has-bottom-bar">

                <!-- ===== HERO HEADER ===== -->
                <div class="tech-task-hero mb-3">
                    <div class="d-flex align-items-center mb-2">
                        <a href="/my/technician" class="tech-back-btn me-2"><i class="fa fa-chevron-left"/></a>
                        <span class="text-muted small"><t t-out="task.name"/></span>
                    </div>
                    <div class="d-flex align-items-center justify-content-between">
                        <div>
                            <span t-attf-class="tech-badge tech-badge-#{task.task_type} me-1">
                                <t t-out="dict(task._fields['task_type'].selection).get(task.task_type, '')"/>
                            </span>
                            <span t-attf-class="tech-status-badge tech-status-#{task.status}">
                                <t t-out="dict(task._fields['status'].selection).get(task.status, '')"/>
                            </span>
                        </div>
                        <div class="text-end">
                            <div class="fw-bold"><t t-out="task.time_start_display"/> - <t t-out="task.time_end_display"/></div>
                            <div class="text-muted small"><t t-out="task.scheduled_date" t-options="{'widget': 'date'}"/></div>
                        </div>
                    </div>
                    <t t-if="task.travel_time_minutes">
                        <div class="mt-1">
                            <span class="badge text-bg-secondary"><i class="fa fa-car me-1"/><t t-out="task.travel_time_minutes"/> min drive
                                <t t-if="task.travel_distance_km"> - <t t-out="task.travel_distance_km"/> km</t>
                            </span>
                        </div>
                    </t>
                </div>

                <!-- ===== QUICK ACTIONS ROW ===== -->
                <div class="tech-quick-actions mb-3">
                    <t t-if="task.get_google_maps_url()">
                        <a href="#" class="tech-quick-btn"
                           t-att-data-nav-url="task.get_google_maps_url()"
                           t-att-data-nav-addr="task.address_display or ''"
                           onclick="openGoogleMapsNav(this); return false;">
                            <i class="fa fa-location-arrow"/>
                            <span>Navigate</span>
                        </a>
                    </t>
                    <t t-if="task.client_display_phone">
                        <a t-attf-href="tel:#{task.client_display_phone}" class="tech-quick-btn">
                            <i class="fa fa-phone"/>
                            <span>Call</span>
                        </a>
                    </t>
                    <t t-if="task.client_display_phone">
                        <a t-attf-href="sms:#{task.client_display_phone}" class="tech-quick-btn">
                            <i class="fa fa-comment"/>
                            <span>Text</span>
                        </a>
                    </t>
                    <t t-if="task.sale_order_id">
                        <a t-attf-href="/my/orders/#{task.sale_order_id.id}" class="tech-quick-btn">
                            <i class="fa fa-file-text-o"/>
                            <span>Case</span>
                        </a>
                    </t>
                </div>

                <!-- ===== LOCATION CARD ===== -->
                <div class="tech-card mb-3">
                    <div class="d-flex align-items-start">
                        <div class="tech-card-icon bg-primary-subtle text-primary">
                            <i class="fa fa-map-marker"/>
                        </div>
                        <div class="flex-grow-1">
                            <div class="fw-semibold"><t t-out="task.address_street or 'No address'"/></div>
                            <t t-if="task.address_street2">
                                <div class="text-muted small">Unit/Suite: <t t-out="task.address_street2"/></div>
                            </t>
                            <t t-if="task.address_buzz_code">
                                <span class="badge text-bg-warning mt-1"><i class="fa fa-key me-1"/>Buzz: <t t-out="task.address_buzz_code"/></span>
                            </t>
                        </div>
                    </div>
                </div>

                <!-- ===== CLIENT CARD ===== -->
                <div class="tech-card mb-3">
                    <div class="d-flex align-items-center">
                        <div class="tech-card-icon bg-success-subtle text-success">
                            <i class="fa fa-user"/>
                        </div>
                        <div class="flex-grow-1">
                            <div class="fw-semibold"><t t-out="task.client_display_name or 'No client'"/></div>
                            <t t-if="task.client_display_phone">
                                <a t-attf-href="tel:#{task.client_display_phone}" class="text-muted small text-decoration-none">
                                    <i class="fa fa-phone me-1"/><t t-out="task.client_display_phone"/>
                                </a>
                            </t>
                        </div>
                    </div>
                </div>

                <!-- ===== INSTRUCTIONS ===== -->
                <t t-if="task.description">
                    <div class="tech-card mb-3">
                        <div class="text-muted small text-uppercase fw-semibold mb-1">
                            <i class="fa fa-file-text-o me-1"/>Instructions
                        </div>
                        <div style="white-space:pre-wrap;font-size:0.9rem;"><t t-out="task.description"/></div>
                    </div>
                </t>

                <!-- ===== ORDER DETAILS (Sale Order or Purchase Order) ===== -->
                <t t-if="linked_order">
                    <div class="tech-card tech-order-card mb-3">
                        <div class="d-flex align-items-center justify-content-between mb-2">
                            <div class="d-flex align-items-center">
                                <div t-attf-class="tech-card-icon #{linked_order_type == 'sale' and 'bg-info-subtle text-info' or 'bg-purple-subtle text-purple'}">
                                    <i t-attf-class="fa #{linked_order_type == 'sale' and 'fa-shopping-cart' or 'fa-truck'}"/>
                                </div>
                                <div>
                                    <div class="text-muted small text-uppercase fw-semibold" style="font-size:0.68rem;letter-spacing:0.05em;">
                                        <t t-if="linked_order_type == 'sale'">Sale Order</t>
                                        <t t-else="">Purchase Order</t>
                                    </div>
                                    <div class="fw-bold" style="font-size:0.95rem;"><t t-out="linked_order.name"/></div>
                                </div>
                            </div>
                            <t t-if="linked_order_type == 'sale'">
                                <a t-attf-href="/my/orders/#{linked_order.id}" class="btn btn-sm btn-outline-secondary rounded-pill"
                                   style="font-size:0.75rem;">
                                    <i class="fa fa-external-link me-1"/>View
                                </a>
                            </t>
                        </div>

                        <!-- Order Lines: Products & Services -->
                        <t t-if="order_lines">
                            <div class="tech-order-lines">
                                <div class="text-muted small text-uppercase fw-semibold mb-2" style="font-size:0.68rem;letter-spacing:0.05em;">
                                    <i class="fa fa-cube me-1"/>Items (<t t-out="len(order_lines)"/>)
                                </div>
                                <t t-foreach="order_lines" t-as="line">
                                    <div t-attf-class="tech-order-line-item #{not line_last and 'tech-order-line-border' or ''}">
                                        <div class="d-flex justify-content-between align-items-start">
                                            <div class="flex-grow-1 me-2">
                                                <div class="fw-semibold" style="font-size:0.88rem;">
                                                    <t t-out="line.product_id.name"/>
                                                </div>
                                                <!-- Product description (differs from product name) -->
                                                <t t-if="linked_order_type == 'sale'">
                                                    <t t-set="line_desc" t-value="line.name or ''"/>
                                                </t>
                                                <t t-else="">
                                                    <t t-set="line_desc" t-value="line.name or ''"/>
                                                </t>
                                                <t t-if="line_desc and line_desc != line.product_id.name">
                                                    <div class="text-muted" style="font-size:0.8rem;white-space:pre-wrap;line-height:1.35;">
                                                        <t t-out="line_desc"/>
                                                    </div>
                                                </t>
                                                <!-- Serial number if available -->
                                                <t t-if="linked_order_type == 'sale' and line.sudo()._fields.get('x_fc_serial_number') and line.x_fc_serial_number">
                                                    <div class="mt-1">
                                                        <span class="badge text-bg-light border" style="font-size:0.72rem;">
                                                            <i class="fa fa-barcode me-1"/>S/N: <t t-out="line.x_fc_serial_number"/>
                                                        </span>
                                                    </div>
                                                </t>
                                            </div>
                                            <div class="text-end flex-shrink-0">
                                                <span class="tech-qty-badge">
                                                    <t t-if="linked_order_type == 'sale'">
                                                        <t t-out="int(line.product_uom_qty)"/>
                                                    </t>
                                                    <t t-else="">
                                                        <t t-out="int(line.product_qty)"/>
                                                    </t>
                                                </span>
                                                <div class="text-muted" style="font-size:0.68rem;">qty</div>
                                            </div>
                                        </div>
                                    </div>
                                </t>
                            </div>
                        </t>
                        <t t-if="not order_lines">
                            <div class="text-muted small text-center py-2">
                                <i class="fa fa-info-circle me-1"/>No line items on this order
                            </div>
                        </t>
                    </div>
                </t>

                <!-- ===== EQUIPMENT NEEDED ===== -->
                <t t-if="task.equipment_needed">
                    <div class="tech-card mb-3">
                        <div class="tech-equipment-tag">
                            <div class="text-muted small text-uppercase fw-semibold mb-1">
                                <i class="fa fa-wrench me-1"/>Equipment Needed
                            </div>
                            <div style="white-space:pre-wrap;font-size:0.9rem;"><t t-out="task.equipment_needed"/></div>
                        </div>
                    </div>
                </t>

                <!-- ===== POD (if required) ===== -->
                <t t-if="task.pod_required">
                    <div class="tech-card mb-3">
                        <div class="d-flex align-items-center">
                            <div class="tech-card-icon bg-warning-subtle text-warning">
                                <i class="fa fa-pencil-square-o"/>
                            </div>
                            <div class="flex-grow-1">
                                <div class="fw-semibold">Proof of Delivery</div>
                                <t t-set="has_task_pod" t-value="bool(task.pod_signature)"/>
                                <t t-set="has_order_pod" t-value="bool(task.sale_order_id and task.sale_order_id.x_fc_pod_signature)"/>
                                <t t-if="has_task_pod or has_order_pod">
                                    <span class="text-success small d-block"><i class="fa fa-check me-1"/>Signature collected</span>
                                    <a t-attf-href="/my/technician/task/#{task.id}/pod" class="btn btn-sm btn-outline-warning mt-1">
                                        <i class="fa fa-refresh me-1"/>Re-collect Signature
                                    </a>
                                </t>
                                <t t-else="">
                                    <a t-attf-href="/my/technician/task/#{task.id}/pod" class="btn btn-sm btn-warning mt-1">
                                        <i class="fa fa-pencil me-1"/>Collect Signature
                                    </a>
                                </t>
                            </div>
                        </div>
                    </div>
                </t>

                <!-- ===== COMPLETION REPORT (completed tasks) ===== -->
                <t t-if="task.status == 'completed'">
                    <div class="tech-card tech-card-success mb-3">
                        <div class="text-muted small text-uppercase fw-semibold mb-2">
                            <i class="fa fa-check-circle me-1"/>Completion Report
                        </div>
                        <t t-if="task.completion_notes">
                            <div id="existingNotes"><t t-out="task.completion_notes"/></div>
                        </t>
                        <t t-else="">
                            <p class="text-muted mb-0" id="existingNotes">No notes added yet.</p>
                        </t>
                    </div>

                    <!-- Add Notes Section -->
                    <div class="tech-card mb-3" id="addNotesSection">
                        <div class="text-muted small text-uppercase fw-semibold mb-2">
                            <i class="fa fa-plus-circle me-1"/>Add Notes
                        </div>
                        <!-- Voice toggle -->
                        <div class="d-none text-center py-3 mb-2" id="completedVoicePanel"
                             style="border:2px dashed var(--o-main-border-color, #dee2e6);border-radius:12px;">
                            <button class="btn btn-lg rounded-circle" id="completedRecordBtn"
                                    onclick="toggleCompletedRecording()"
                                    style="width:64px;height:64px;font-size:24px;border:2px solid #dc3545;color:#dc3545;">
                                <i class="fa fa-microphone"/>
                            </button>
                            <div class="d-none mt-2 fw-bold" id="completedRecordTimer" style="color:#dc3545;">0:00</div>
                            <p class="small text-muted mt-1 mb-0">Tap to record. Speak in any language.</p>
                        </div>
                        <span id="completedRecordStatus" class="small text-muted d-block mb-1"></span>
                        <textarea class="form-control mb-2" id="additionalNotes" rows="3"
                                  placeholder="Type or use voice to add notes..." style="border-radius:10px;"></textarea>

                        <!-- Photo Attachments -->
                        <div class="mb-2">
                            <input type="file" id="notePhotoInput" accept="image/*" multiple="multiple"
                                   class="d-none" onchange="handleNotePhotos(this)"/>
                            <div id="notePhotoPreview" class="d-flex flex-wrap gap-2 mb-2"></div>
                        </div>

                        <div class="d-flex gap-2 flex-wrap">
                            <button class="btn btn-outline-secondary btn-sm rounded-pill" id="completedVoiceBtn"
                                    onclick="toggleCompletedVoice()">
                                <i class="fa fa-microphone me-1"/>Voice
                            </button>
                            <button class="btn btn-outline-secondary btn-sm rounded-pill"
                                    onclick="document.getElementById('notePhotoInput').click()">
                                <i class="fa fa-camera me-1"/>Photo
                            </button>
                            <button class="btn btn-outline-primary btn-sm rounded-pill" id="aiFormatBtn" onclick="aiFormatNotes()">
                                <i class="fa fa-magic me-1"/>AI Format
                            </button>
                            <button class="btn btn-success btn-sm rounded-pill ms-auto" onclick="saveCompletedTaskNotes()">
                                <i class="fa fa-save me-1"/>Save
                            </button>
                            <span id="notesSaveStatus" class="small text-muted align-self-center"></span>
                        </div>
                    </div>
                </t>

                <!-- ===== VOICE SECTION (active tasks) ===== -->
                <t t-if="task.status in ('in_progress', 'en_route', 'scheduled')">
                    <div class="tech-card mb-3" id="voiceSection">
                        <div class="text-muted small text-uppercase fw-semibold mb-2">
                            <i class="fa fa-microphone me-1"/>Voice Note
                        </div>
                        <div class="tech-voice-recorder" id="voiceRecorder">
                            <p class="text-muted mb-3 small">Record what you did. Speak in any language.</p>
                            <button class="tech-record-btn" id="recordBtn" onclick="toggleRecording()">
                                <i class="fa fa-microphone"/>
                            </button>
                            <div class="tech-record-timer d-none" id="recordTimer">0:00</div>
                            <p class="small text-muted mt-2" id="recordStatus">Tap to start recording</p>
                        </div>
                        <div class="d-none mt-3" id="reviewPanel">
                            <label class="form-label fw-bold small">Review Transcription:</label>
                            <textarea class="form-control mb-2" id="transcriptionText" rows="4" style="border-radius:10px;"></textarea>
                            <div class="d-flex gap-2">
                                <button class="tech-action-btn tech-btn-complete flex-grow-1" onclick="submitVoiceCompletion()">
                                    <i class="fa fa-check"/>Submit &amp; Complete
                                </button>
                                <button class="btn btn-outline-secondary" onclick="resetRecording()" style="border-radius:12px;">
                                    <i class="fa fa-refresh"/>
                                </button>
                            </div>
                        </div>
                    </div>
                </t>

                <!-- ===== BOTTOM ACTION BAR ===== -->
                <div class="tech-bottom-bar" t-if="task.status not in ('completed', 'cancelled')">
                    <t t-if="task.status == 'scheduled'">
                        <button class="tech-action-btn tech-btn-enroute"
                                onclick="techTaskAction(this, 'en_route')"
                                t-att-data-task-id="task.id">
                            <i class="fa fa-road"/>En Route
                        </button>
                        <button class="tech-action-btn tech-btn-start"
                                onclick="techTaskAction(this, 'start')"
                                t-att-data-task-id="task.id">
                            <i class="fa fa-play"/>Start
                        </button>
                        <button class="tech-action-btn tech-btn-complete"
                                onclick="techCompleteTask(this)"
                                t-att-data-task-id="task.id">
                            <i class="fa fa-check-circle"/>Complete
                        </button>
                    </t>
                    <t t-if="task.status == 'en_route'">
                        <a t-if="task.get_google_maps_url()"
                           href="#" class="tech-action-btn tech-btn-navigate"
                           t-att-data-nav-url="task.get_google_maps_url()"
                           t-att-data-nav-addr="task.address_display or ''"
                           onclick="openGoogleMapsNav(this); return false;">
                            <i class="fa fa-location-arrow"/>Navigate
                        </a>
                        <button class="tech-action-btn tech-btn-start"
                                onclick="techTaskAction(this, 'start')"
                                t-att-data-task-id="task.id">
                            <i class="fa fa-play"/>Start
                        </button>
                        <button class="tech-action-btn tech-btn-complete"
                                onclick="techCompleteTask(this)"
                                t-att-data-task-id="task.id">
                            <i class="fa fa-check-circle"/>Complete
                        </button>
                    </t>
                    <t t-if="task.status == 'in_progress'">
                        <button class="tech-action-btn tech-btn-complete"
                                onclick="techCompleteTask(this)"
                                t-att-data-task-id="task.id"
                                style="flex:1;">
                            <i class="fa fa-check-circle"/>Complete
                        </button>
                        <a href="#voiceSection" class="tech-action-btn tech-btn-navigate" style="flex:0 0 auto;">
                            <i class="fa fa-microphone"/>
                        </a>
                    </t>
                </div>

                <!-- ===== COMPLETION OVERLAY ===== -->
                <div id="completionOverlay" class="tech-overlay">
                    <div class="tech-overlay-card">
                        <div class="tech-overlay-icon text-success">
                            <i class="fa fa-check-circle"/>
                        </div>
                        <h3 id="completionTitle" class="text-success mb-2">Task Completed!</h3>
                        <p id="completionMessage" class="text-muted mb-4"></p>
                        <div id="completionActions">
                            <a id="nextTaskBtn" href="#" class="btn btn-lg btn-primary w-100 mb-2 rounded-pill" style="display:none;">
                                <i class="fa fa-arrow-right me-1"/> Next Task
                            </a>
                            <p id="autoRedirectMsg" class="text-muted small" style="display:none;">
                                Auto-redirecting in <span id="countdownSec">5</span>s...
                            </p>
                            <a href="/my/technician" class="btn btn-outline-secondary w-100 rounded-pill">
                                <i class="fa fa-home me-1"/> Dashboard
                            </a>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Voice Recording JS -->
            <script type="text/javascript">
                var taskId = <t t-out="task.id"/>;
                var mediaRecorder = null;
                var audioChunks = [];
                var recordingTimer = null;
                var recordingSeconds = 0;

                function techTaskAction(btn, action) {
                    var origHtml = btn.innerHTML;
                    btn.disabled = true;
                    btn.innerHTML = '&lt;i class="fa fa-spinner fa-spin">&lt;/i> Getting location...';
                    window.fusionGetLocation().then(function(coords) {
                        btn.innerHTML = '&lt;i class="fa fa-spinner fa-spin">&lt;/i>';
                        fetch('/my/technician/task/' + taskId + '/action', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({jsonrpc: '2.0', method: 'call', params: {
                                action: action,
                                latitude: coords.latitude,
                                longitude: coords.longitude,
                                accuracy: coords.accuracy
                            }})
                        })
                        .then(function(r) { return r.json(); })
                        .then(function(data) {
                            if (data.result &amp;&amp; data.result.success) {
                                window.location.reload();
                            } else {
                                alert(data.result ? data.result.error : 'Error');
                                btn.disabled = false;
                                btn.innerHTML = origHtml;
                            }
                        })
                        .catch(function() {
                            alert('Network error. Please try again.');
                            btn.disabled = false;
                            btn.innerHTML = origHtml;
                        });
                    }).catch(function() {
                        alert('Location access is required. Please enable GPS and try again.');
                        btn.disabled = false;
                        btn.innerHTML = origHtml;
                    });
                }

                function techCompleteTask(btn) {
                    var origHtml = btn.innerHTML;
                    btn.disabled = true;
                    btn.innerHTML = '&lt;i class="fa fa-spinner fa-spin">&lt;/i> Getting location...';
                    window.fusionGetLocation().then(function(coords) {
                        btn.innerHTML = '&lt;i class="fa fa-spinner fa-spin">&lt;/i> Completing...';
                        fetch('/my/technician/task/' + taskId + '/action', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({jsonrpc: '2.0', method: 'call', params: {
                                action: 'complete',
                                latitude: coords.latitude,
                                longitude: coords.longitude,
                                accuracy: coords.accuracy
                            }})
                        })
                        .then(function(r) { return r.json(); })
                        .then(function(data) {
                            if (data.result &amp;&amp; data.result.success) {
                                showCompletionOverlay(data.result);
                            } else {
                                alert(data.result ? data.result.error : 'Error completing task');
                                btn.disabled = false;
                                btn.innerHTML = origHtml;
                            }
                        })
                        .catch(function(err) {
                            alert('Network error. Please try again.');
                            btn.disabled = false;
                            btn.innerHTML = origHtml;
                        });
                    }).catch(function() {
                        alert('Location access is required. Please enable GPS and try again.');
                        btn.disabled = false;
                        btn.innerHTML = origHtml;
                    });
                }

                function showCompletionOverlay(result) {
                    var overlay = document.getElementById('completionOverlay');
                    var msg = document.getElementById('completionMessage');
                    var nextBtn = document.getElementById('nextTaskBtn');
                    var autoMsg = document.getElementById('autoRedirectMsg');
                    var countdown = document.getElementById('countdownSec');

                    overlay.style.display = 'flex';

                    if (result.next_task_id) {
                        msg.textContent = 'Next: ' + result.next_task_name + ' at ' + result.next_task_time;
                        nextBtn.href = result.next_task_url;
                        nextBtn.style.display = 'block';
                        autoMsg.style.display = 'block';

                        // Auto-redirect countdown
                        var sec = 5;
                        countdown.textContent = sec;
                        var timer = setInterval(function() {
                            sec--;
                            countdown.textContent = sec;
                            if (sec &lt;= 0) {
                                clearInterval(timer);
                                window.location.href = result.next_task_url;
                            }
                        }, 1000);

                        // Cancel auto-redirect if user clicks anything
                        overlay.addEventListener('click', function(e) {
                            if (e.target !== overlay) {
                                clearInterval(timer);
                                autoMsg.style.display = 'none';
                            }
                        });
                    } else {
                        msg.textContent = 'All tasks complete for today! Great work.';
                        nextBtn.style.display = 'none';
                        autoMsg.style.display = 'none';
                    }
                }

                // --- Image compression helper ---
                function compressImage(file, maxDim, quality) {
                    maxDim = maxDim || 1920;
                    quality = quality || 0.80;
                    return new Promise(function(resolve) {
                        var img = new Image();
                        img.onload = function() {
                            var w = img.width, h = img.height;
                            if (w > maxDim || h > maxDim) {
                                var ratio = Math.min(maxDim / w, maxDim / h);
                                w = Math.round(w * ratio);
                                h = Math.round(h * ratio);
                            }
                            var canvas = document.createElement('canvas');
                            canvas.width = w;
                            canvas.height = h;
                            canvas.getContext('2d').drawImage(img, 0, 0, w, h);
                            var dataUrl = canvas.toDataURL('image/jpeg', quality);
                            URL.revokeObjectURL(img.src);
                            resolve(dataUrl);
                        };
                        img.src = URL.createObjectURL(file);
                    });
                }

                // --- Photo attachments for notes ---
                var notePhotosBase64 = [];

                function handleNotePhotos(input) {
                    var files = input.files;
                    if (!files || !files.length) return;
                    var preview = document.getElementById('notePhotoPreview');

                    for (var i = 0; i &lt; files.length; i++) {
                        (function(file) {
                            if (!file.type.startsWith('image/')) return;
                            // Limit to 10 MB per raw file
                            if (file.size > 10 * 1024 * 1024) {
                                alert('Photo too large (max 10 MB): ' + file.name);
                                return;
                            }
                            // Compress via Canvas then store
                            compressImage(file).then(function(dataUrl) {
                                var idx = notePhotosBase64.length;
                                notePhotosBase64.push({
                                    data: dataUrl,
                                    name: file.name,
                                    type: 'image/jpeg'
                                });
                                // Build thumbnail
                                var wrapper = document.createElement('div');
                                wrapper.className = 'position-relative';
                                wrapper.style.cssText = 'width:72px;height:72px;';
                                wrapper.setAttribute('data-photo-idx', idx);

                                var img = document.createElement('img');
                                img.src = dataUrl;
                                img.style.cssText = 'width:72px;height:72px;object-fit:cover;border-radius:8px;border:1px solid var(--o-main-border-color, #dee2e6);';

                                var removeBtn = document.createElement('button');
                                removeBtn.type = 'button';
                                removeBtn.className = 'btn btn-sm position-absolute';
                                removeBtn.style.cssText = 'top:-6px;right:-6px;width:22px;height:22px;padding:0;line-height:22px;text-align:center;border-radius:50%;background:#dc3545;color:#fff;font-size:12px;border:none;';
                                removeBtn.innerHTML = '&amp;times;';
                                removeBtn.onclick = function() {
                                    notePhotosBase64[idx] = null;  // mark as removed
                                    wrapper.remove();
                                };

                                wrapper.appendChild(img);
                                wrapper.appendChild(removeBtn);
                                preview.appendChild(wrapper);
                            });
                        })(files[i]);
                    }
                    // Reset input so same file can be re-selected
                    input.value = '';
                }

                // --- Voice recording for completed tasks ---
                var completedRecorder = null;
                var completedChunks = [];
                var completedTimer = null;
                var completedSeconds = 0;

                function toggleCompletedVoice() {
                    var panel = document.getElementById('completedVoicePanel');
                    panel.classList.toggle('d-none');
                }

                function toggleCompletedRecording() {
                    if (completedRecorder &amp;&amp; completedRecorder.state === 'recording') {
                        stopCompletedRecording();
                    } else {
                        startCompletedRecording();
                    }
                }

                async function startCompletedRecording() {
                    try {
                        var stream = await navigator.mediaDevices.getUserMedia({
                            audio: {echoCancellation: true, noiseSuppression: true}
                        });
                        completedChunks = [];
                        completedRecorder = new MediaRecorder(stream, {mimeType: 'audio/webm'});
                        completedRecorder.ondataavailable = function(e) {
                            if (e.data.size > 0) completedChunks.push(e.data);
                        };
                        completedRecorder.onstop = function() {
                            stream.getTracks().forEach(function(t) { t.stop(); });
                            transcribeCompletedVoice();
                        };
                        completedRecorder.start();
                        completedSeconds = 0;
                        var timerEl = document.getElementById('completedRecordTimer');
                        timerEl.classList.remove('d-none');
                        completedTimer = setInterval(function() {
                            completedSeconds++;
                            var m = Math.floor(completedSeconds / 60);
                            var s = completedSeconds % 60;
                            timerEl.textContent = m + ':' + (s &lt; 10 ? '0' : '') + s;
                        }, 1000);
                        var btn = document.getElementById('completedRecordBtn');
                        btn.style.background = '#dc3545';
                        btn.style.color = 'white';
                        btn.innerHTML = '&lt;i class="fa fa-stop">&lt;/i>';
                        document.getElementById('completedRecordStatus').textContent = 'Recording...';
                    } catch(err) {
                        alert('Microphone access needed for voice notes.');
                    }
                }

                function stopCompletedRecording() {
                    if (completedRecorder &amp;&amp; completedRecorder.state === 'recording') {
                        completedRecorder.stop();
                    }
                    clearInterval(completedTimer);
                    var btn = document.getElementById('completedRecordBtn');
                    btn.style.background = '';
                    btn.style.color = '#dc3545';
                    btn.innerHTML = '&lt;i class="fa fa-microphone">&lt;/i>';
                    document.getElementById('completedRecordStatus').textContent = 'Transcribing...';
                }

                async function transcribeCompletedVoice() {
                    var blob = new Blob(completedChunks, {type: 'audio/webm'});
                    var reader = new FileReader();
                    reader.onloadend = function() {
                        var base64 = reader.result.split(',')[1];
                        fetch('/my/technician/task/' + taskId + '/voice-transcribe', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({
                                jsonrpc: '2.0', method: 'call',
                                params: {audio_data: base64, mime_type: 'audio/webm'}
                            })
                        })
                        .then(function(r) { return r.json(); })
                        .then(function(data) {
                            if (data.result &amp;&amp; data.result.success) {
                                var textarea = document.getElementById('additionalNotes');
                                var existing = textarea.value.trim();
                                textarea.value = existing ? existing + '\n' + data.result.transcription : data.result.transcription;
                                document.getElementById('completedRecordStatus').textContent = 'Transcribed! Edit if needed, then Save.';
                            } else {
                                document.getElementById('completedRecordStatus').textContent = 'Transcription failed: ' + (data.result ? data.result.error : 'Error');
                            }
                            document.getElementById('completedRecordTimer').classList.add('d-none');
                        })
                        .catch(function() {
                            document.getElementById('completedRecordStatus').textContent = 'Network error';
                            document.getElementById('completedRecordTimer').classList.add('d-none');
                        });
                    };
                    reader.readAsDataURL(blob);
                }

                function aiFormatNotes() {
                    var textarea = document.getElementById('additionalNotes');
                    var text = textarea.value.trim();
                    if (!text) {
                        document.getElementById('notesSaveStatus').textContent = 'Type or record something first.';
                        return;
                    }
                    var btn = document.getElementById('aiFormatBtn');
                    btn.disabled = true;
                    btn.innerHTML = '&lt;i class="fa fa-spinner fa-spin me-1">&lt;/i>Formatting...';
                    document.getElementById('notesSaveStatus').textContent = '';

                    fetch('/my/technician/task/' + taskId + '/ai-format', {
                        method: 'POST',
                        headers: {'Content-Type': 'application/json'},
                        body: JSON.stringify({jsonrpc: '2.0', method: 'call', params: {text: text}})
                    })
                    .then(function(r) { return r.json(); })
                    .then(function(data) {
                        btn.disabled = false;
                        btn.innerHTML = '&lt;i class="fa fa-magic me-1">&lt;/i>AI Format';
                        if (data.result &amp;&amp; data.result.success) {
                            textarea.value = data.result.formatted_text;
                            document.getElementById('notesSaveStatus').textContent = 'Formatted! Review and Save.';
                            document.getElementById('notesSaveStatus').style.color = '#28a745';
                        } else {
                            document.getElementById('notesSaveStatus').textContent = data.result ? data.result.error : 'Formatting failed';
                            document.getElementById('notesSaveStatus').style.color = '#dc3545';
                        }
                    })
                    .catch(function() {
                        btn.disabled = false;
                        btn.innerHTML = '&lt;i class="fa fa-magic me-1">&lt;/i>AI Format';
                        document.getElementById('notesSaveStatus').textContent = 'Network error';
                    });
                }

                function saveCompletedTaskNotes() {
                    var notes = document.getElementById('additionalNotes').value.trim();
                    // Collect non-null photos
                    var photos = notePhotosBase64.filter(function(p) { return p !== null; });
                    if (!notes &amp;&amp; !photos.length) return;
                    var statusEl = document.getElementById('notesSaveStatus');
                    statusEl.textContent = 'Saving...';
                    statusEl.style.color = '#666';
                    fetch('/my/technician/task/' + taskId + '/add-notes', {
                        method: 'POST',
                        headers: {'Content-Type': 'application/json'},
                        body: JSON.stringify({jsonrpc: '2.0', method: 'call', params: {
                            notes: notes,
                            photos: photos.map(function(p) { return {data: p.data, name: p.name}; })
                        }})
                    })
                    .then(function(r) { return r.json(); })
                    .then(function(data) {
                        if (data.result &amp;&amp; data.result.success) {
                            statusEl.textContent = 'Saved!';
                            statusEl.style.color = '#28a745';
                            document.getElementById('additionalNotes').value = '';
                            // Clear photo previews
                            notePhotosBase64 = [];
                            document.getElementById('notePhotoPreview').innerHTML = '';
                            // Refresh to show updated notes
                            setTimeout(function() { window.location.reload(); }, 1000);
                        } else {
                            statusEl.textContent = data.result ? data.result.error : 'Error saving';
                            statusEl.style.color = '#dc3545';
                        }
                    })
                    .catch(function() {
                        statusEl.textContent = 'Network error';
                        statusEl.style.color = '#dc3545';
                    });
                }

                function toggleRecording() {
                    if (mediaRecorder &amp;&amp; mediaRecorder.state === 'recording') {
                        stopRecording();
                    } else {
                        startRecording();
                    }
                }

                async function startRecording() {
                    try {
                        var stream = await navigator.mediaDevices.getUserMedia({
                            audio: {echoCancellation: true, noiseSuppression: true}
                        });
                        var mimeType = MediaRecorder.isTypeSupported('audio/webm') ? 'audio/webm' :
                                       MediaRecorder.isTypeSupported('audio/ogg') ? 'audio/ogg' : 'audio/mp4';
                        mediaRecorder = new MediaRecorder(stream, {mimeType: mimeType});
                        audioChunks = [];
                        mediaRecorder.ondataavailable = function(e) { if (e.data.size > 0) audioChunks.push(e.data); };
                        mediaRecorder.onstop = function() { stream.getTracks().forEach(function(t){t.stop();}); processRecording(); };
                        mediaRecorder.start();

                        document.getElementById('recordBtn').classList.add('recording');
                        document.getElementById('recordBtn').innerHTML = '<i class="fa fa-stop"></i>';
                        document.getElementById('recordTimer').classList.remove('d-none');
                        document.getElementById('recordStatus').textContent = 'Recording... Tap to stop';
                        document.getElementById('voiceRecorder').classList.add('recording');

                        recordingSeconds = 0;
                        recordingTimer = setInterval(function() {
                            recordingSeconds++;
                            var m = Math.floor(recordingSeconds / 60);
                            var s = recordingSeconds % 60;
                            document.getElementById('recordTimer').textContent = m + ':' + (s &lt; 10 ? '0' : '') + s;
                        }, 1000);
                    } catch (err) {
                        alert('Microphone access denied. Please allow microphone access.');
                    }
                }

                function stopRecording() {
                    if (mediaRecorder &amp;&amp; mediaRecorder.state === 'recording') {
                        mediaRecorder.stop();
                        clearInterval(recordingTimer);
                    }
                }

                async function processRecording() {
                    document.getElementById('recordBtn').classList.remove('recording');
                    document.getElementById('recordBtn').innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
                    document.getElementById('recordStatus').textContent = 'Transcribing...';
                    document.getElementById('voiceRecorder').classList.remove('recording');

                    var blob = new Blob(audioChunks, {type: mediaRecorder.mimeType});
                    var reader = new FileReader();
                    reader.onload = async function() {
                        var base64 = reader.result.split(',')[1];
                        try {
                            var resp = await fetch('/my/technician/task/' + taskId + '/voice-transcribe', {
                                method: 'POST',
                                headers: {'Content-Type': 'application/json'},
                                body: JSON.stringify({
                                    jsonrpc: '2.0', method: 'call',
                                    params: {audio_data: base64, mime_type: mediaRecorder.mimeType}
                                })
                            });
                            var data = await resp.json();
                            if (data.result &amp;&amp; data.result.success) {
                                document.getElementById('transcriptionText').value = data.result.transcription;
                                document.getElementById('reviewPanel').classList.remove('d-none');
                                document.getElementById('voiceRecorder').classList.add('d-none');
                            } else {
                                alert('Transcription failed: ' + (data.result ? data.result.error : 'Unknown error'));
                                resetRecording();
                            }
                        } catch (err) {
                            alert('Error: ' + err.message);
                            resetRecording();
                        }
                    };
                    reader.readAsDataURL(blob);
                }

                function resetRecording() {
                    document.getElementById('voiceRecorder').classList.remove('d-none', 'recording');
                    document.getElementById('reviewPanel').classList.add('d-none');
                    document.getElementById('recordBtn').classList.remove('recording');
                    document.getElementById('recordBtn').innerHTML = '<i class="fa fa-microphone"></i>';
                    document.getElementById('recordTimer').classList.add('d-none');
                    document.getElementById('recordStatus').textContent = 'Tap to start recording';
                }

                async function submitVoiceCompletion() {
                    var text = document.getElementById('transcriptionText').value;
                    if (!text.trim()) { alert('Please record or type completion notes.'); return; }
                    var btns = document.querySelectorAll('#reviewPanel button');
                    btns.forEach(function(b){b.disabled = true;});

                    try {
                        var coords = await window.fusionGetLocation();
                        var resp = await fetch('/my/technician/task/' + taskId + '/voice-complete', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({jsonrpc: '2.0', method: 'call', params: {
                                transcription: text,
                                latitude: coords.latitude,
                                longitude: coords.longitude,
                                accuracy: coords.accuracy
                            }})
                        });
                        var data = await resp.json();
                        if (data.result &amp;&amp; data.result.success) {
                            window.location.reload();
                        } else {
                            alert('Error: ' + (data.result ? data.result.error : 'Unknown'));
                            btns.forEach(function(b){b.disabled = false;});
                        }
                    } catch (err) {
                        if (err instanceof GeolocationPositionError || err.code) {
                            alert('Location access is required. Please enable GPS and try again.');
                        } else {
                            alert('Error: ' + err.message);
                        }
                        btns.forEach(function(b){b.disabled = false;});
                    }
                }
            </script>
        </t>
    </template>

    <!-- ================================================================== -->
    <!-- TOMORROW / NEXT DAY PREPARATION                                     -->
    <!-- ================================================================== -->
    <template id="portal_technician_tomorrow" name="Next Day Preparation">
        <t t-call="portal.portal_layout">
            <t t-set="breadcrumbs_searchbar" t-value="False"/>
            <t t-set="no_breadcrumbs" t-value="True"/>

            <div class="container py-3 tech-portal">
                <nav aria-label="breadcrumb" class="mb-3">
                    <ol class="breadcrumb mb-0">
                        <li class="breadcrumb-item"><a href="/my/home">Home</a></li>
                        <li class="breadcrumb-item"><a href="/my/technician">Dashboard</a></li>
                        <li class="breadcrumb-item active">Tomorrow</li>
                    </ol>
                </nav>

                <h3 class="mb-1"><i class="fa fa-calendar me-2"/>Tomorrow's Schedule</h3>
                <p class="text-muted mb-4">
                    <t t-out="tomorrow_date" t-options="{'widget': 'date', 'format': 'EEEE, MMMM d, yyyy'}"/>
                </p>

                <!-- Summary Stats -->
                <div class="tech-stats-bar mb-4">
                    <div class="tech-stat-card tech-stat-total">
                        <div class="stat-number"><t t-out="len(tomorrow_tasks)"/></div>
                        <div class="stat-label">Tasks</div>
                    </div>
                    <div class="tech-stat-card tech-stat-travel">
                        <div class="stat-number"><t t-out="total_travel"/></div>
                        <div class="stat-label">Travel min</div>
                    </div>
                    <div class="tech-stat-card" style="background: linear-gradient(135deg, #e67e22, #d35400);">
                        <div class="stat-number"><t t-out="'%.0f' % total_distance"/></div>
                        <div class="stat-label">km total</div>
                    </div>
                </div>

                <!-- Equipment Preparation -->
                <t t-if="all_equipment">
                    <div class="tech-prep-equipment mb-4">
                        <h6 class="mb-2"><i class="fa fa-wrench me-1"/>Equipment to Prepare</h6>
                        <ul class="mb-0">
                            <t t-foreach="all_equipment" t-as="equip">
                                <li><t t-out="equip"/></li>
                            </t>
                        </ul>
                    </div>
                </t>

                <!-- Task List for Tomorrow -->
                <t t-if="tomorrow_tasks">
                    <t t-foreach="tomorrow_tasks" t-as="task">
                        <div class="tech-prep-card">
                            <div class="d-flex justify-content-between align-items-start">
                                <div>
                                    <span class="prep-time"><t t-out="task.time_start_display"/> - <t t-out="task.time_end_display"/></span>
                                    <span t-attf-class="tech-badge tech-badge-#{task.task_type} prep-type">
                                        <t t-out="dict(task._fields['task_type'].selection).get(task.task_type, '')"/>
                                    </span>
                                </div>
                                <t t-if="task.travel_time_minutes">
                                    <span class="text-muted small"><i class="fa fa-car me-1"/><t t-out="task.travel_time_minutes"/> min</span>
                                </t>
                            </div>
                            <div class="mt-2">
                                <strong><t t-out="task.client_display_name or task.name"/></strong>
                            </div>
                            <div class="text-muted small">
                                <i class="fa fa-map-marker me-1"/><t t-out="task.address_display or 'No address'"/>
                            </div>
                            <t t-if="task.client_display_phone">
                                <div class="small mt-1">
                                    <a t-attf-href="tel:#{task.client_display_phone}" class="text-decoration-none">
                                        <i class="fa fa-phone me-1"/><t t-out="task.client_display_phone"/>
                                    </a>
                                </div>
                            </t>
                            <t t-if="task.description">
                                <div class="small mt-1 text-muted"><t t-out="task.description"/></div>
                            </t>
                            <t t-if="task.equipment_needed">
                                <div class="small mt-1 text-warning"><i class="fa fa-wrench me-1"/><t t-out="task.equipment_needed"/></div>
                            </t>
                        </div>
                    </t>
                </t>
                <t t-else="">
                    <div class="text-center py-5 text-muted">
                        <i class="fa fa-umbrella fa-3x mb-2" style="display:block;"/>
                        <h5>No tasks scheduled for tomorrow</h5>
                        <p>Enjoy your day off, or check back later for schedule updates.</p>
                    </div>
                </t>
            </div>
        </t>
    </template>

    <!-- ================================================================== -->
    <!-- SCHEDULE FOR SPECIFIC DATE                                          -->
    <!-- ================================================================== -->
    <template id="portal_technician_schedule_date" name="Technician Schedule Date">
        <t t-call="portal.portal_layout">
            <t t-set="breadcrumbs_searchbar" t-value="False"/>
            <t t-set="no_breadcrumbs" t-value="True"/>

            <div class="container py-3 tech-portal">
                <nav aria-label="breadcrumb" class="mb-3">
                    <ol class="breadcrumb mb-0">
                        <li class="breadcrumb-item"><a href="/my/home">Home</a></li>
                        <li class="breadcrumb-item"><a href="/my/technician">Dashboard</a></li>
                        <li class="breadcrumb-item active">
                            <t t-out="schedule_date" t-options="{'widget': 'date'}"/>
                        </li>
                    </ol>
                </nav>

                <h3 class="mb-3">
                    <i class="fa fa-calendar me-2"/>
                    <t t-out="schedule_date" t-options="{'widget': 'date', 'format': 'EEEE, MMMM d'}"/>
                </h3>

                <t t-if="total_travel">
                    <p class="text-muted"><i class="fa fa-car me-1"/>Total travel: <t t-out="total_travel"/> minutes</p>
                </t>

                <div class="tech-timeline">
                    <t t-foreach="tasks" t-as="task">
                        <t t-if="task.travel_time_minutes and not task_first">
                            <div class="tech-travel-indicator">
                                <i class="fa fa-car me-1"/><t t-out="task.travel_time_minutes"/> min
                            </div>
                        </t>
                        <div class="tech-timeline-item">
                            <div t-attf-class="tech-timeline-dot status-#{task.status}"/>
                            <a t-attf-href="/my/technician/task/#{task.id}" class="tech-timeline-card">
                                <div class="d-flex justify-content-between">
                                    <span class="tech-timeline-time">
                                        <t t-out="task.time_start_display"/> - <t t-out="task.time_end_display"/>
                                    </span>
                                    <span t-attf-class="tech-status-badge tech-status-#{task.status}" style="font-size:0.7rem;">
                                        <t t-out="dict(task._fields['status'].selection).get(task.status, '')"/>
                                    </span>
                                </div>
                                <div class="tech-timeline-title">
                                    <span t-attf-class="tech-badge tech-badge-#{task.task_type} me-1">
                                        <t t-out="dict(task._fields['task_type'].selection).get(task.task_type, '')"/>
                                    </span>
                                    <t t-out="task.client_display_name or task.name"/>
                                </div>
                                <div class="tech-timeline-meta">
                                    <i class="fa fa-map-marker me-1"/><t t-out="task.address_city or 'No address'"/>
                                </div>
                            </a>
                        </div>
                    </t>
                </div>

                <t t-if="not tasks">
                    <div class="text-center py-5 text-muted">
                        <i class="fa fa-calendar-times-o fa-3x mb-2" style="display:block;"/>
                        <p>No tasks scheduled for this date.</p>
                    </div>
                </t>
            </div>
        </t>
    </template>

    <!-- ================================================================== -->
    <!-- TECHNICIAN LOCATION MAP (Admin View)                               -->
    <!-- ================================================================== -->
    <template id="portal_technician_map" name="Technician Location Map">
        <t t-call="portal.portal_layout">
            <t t-set="breadcrumbs_searchbar" t-value="False"/>
            <t t-set="no_breadcrumbs" t-value="True"/>

            <div class="container-fluid py-3">
                <div class="d-flex justify-content-between align-items-center mb-3">
                    <h3><i class="fa fa-map-marker"/> Technician Locations</h3>
                    <a href="/web#action=fusion_tasks.action_technician_locations" class="btn btn-secondary btn-sm">
                        <i class="fa fa-list"/> View History
                    </a>
                </div>

                <div id="techMap" style="width:100%;height:70vh;border-radius:12px;border:1px solid #ddd;"></div>

                <!-- Legend -->
                <div class="mt-3">
                    <strong>Last updated locations (past 24 hours):</strong>
                    <ul class="list-inline mt-2">
                        <t t-foreach="locations" t-as="loc">
                            <li class="list-inline-item badge bg-primary me-2 mb-1">
                                <i class="fa fa-user"/> <t t-out="loc['name']"/>
                                <small class="ms-1">(<t t-out="loc['logged_at'][:16]"/>)</small>
                            </li>
                        </t>
                    </ul>
                    <t t-if="not locations">
                        <p class="text-muted">No location data in the past 24 hours.</p>
                    </t>
                </div>
            </div>

            <script t-if="google_maps_api_key">
                var techLocations = <t t-out="json.dumps(locations)" t-options="{'widget': 'text'}"/>;

                function initMap() {
                    var center = {lat: 43.7, lng: -79.4}; // Default: GTA
                    if (techLocations.length > 0) {
                        center = {lat: techLocations[0].latitude, lng: techLocations[0].longitude};
                    }
                    var map = new google.maps.Map(document.getElementById('techMap'), {
                        zoom: 11,
                        center: center,
                        mapTypeId: 'roadmap',
                    });
                    var bounds = new google.maps.LatLngBounds();
                    techLocations.forEach(function(loc) {
                        var pos = {lat: loc.latitude, lng: loc.longitude};
                        var marker = new google.maps.Marker({
                            position: pos,
                            map: map,
                            title: loc.name,
                            label: {text: loc.name.charAt(0), color: 'white'},
                        });
                        var infoWindow = new google.maps.InfoWindow({
                            content: '<div><strong>' + loc.name + '</strong><br/>' +
                                     '<small>Last seen: ' + loc.logged_at + '</small><br/>' +
                                     '<small>Accuracy: ' + (loc.accuracy || 'N/A') + 'm</small></div>'
                        });
                        marker.addListener('click', function() {
                            infoWindow.open(map, marker);
                        });
                        bounds.extend(pos);
                    });
                    if (techLocations.length > 1) {
                        map.fitBounds(bounds);
                    }
                }
            </script>
            <script t-if="google_maps_api_key"
                    t-attf-src="https://maps.googleapis.com/maps/api/js?key=#{google_maps_api_key}&amp;callback=initMap"
                    async="" defer=""/>
            <t t-if="not google_maps_api_key">
                <div class="alert alert-warning mt-3">
                    <i class="fa fa-exclamation-triangle"/> Google Maps API key not configured.
                    Please set it in Settings > Fusion Claims > Google Maps API Key.
                </div>
            </t>
        </t>
    </template>

</odoo>
