{"id":200,"date":"2026-03-31T11:22:19","date_gmt":"2026-03-31T11:22:19","guid":{"rendered":"https:\/\/ph-taskportal.zyneventures.com\/?page_id=200"},"modified":"2026-07-09T09:12:23","modified_gmt":"2026-07-09T09:12:23","slug":"qc-adhoc-assignment","status":"publish","type":"page","link":"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/qc-adhoc-assignment\/","title":{"rendered":"QC Adhoc Assignment"},"content":{"rendered":"<style>.kadence-column200_04667f-4e > .kt-inside-inner-col,.kadence-column200_04667f-4e > .kt-inside-inner-col:before{border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;border-bottom-left-radius:0px;}.kadence-column200_04667f-4e > .kt-inside-inner-col{column-gap:var(--global-kb-gap-sm, 1rem);}.kadence-column200_04667f-4e > .kt-inside-inner-col{flex-direction:column;}.kadence-column200_04667f-4e > .kt-inside-inner-col > .aligncenter{width:100%;}.kadence-column200_04667f-4e > .kt-inside-inner-col:before{opacity:0.3;}.kadence-column200_04667f-4e{position:relative;}@media all and (max-width: 1024px){.kadence-column200_04667f-4e > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 767px){.kadence-column200_04667f-4e > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}<\/style>\n<div class=\"wp-block-kadence-column kadence-column200_04667f-4e\"><div class=\"kt-inside-inner-col\"><style>.kb-row-layout-id200_5b7a92-30 > .kt-row-column-wrap{align-content:start;}:where(.kb-row-layout-id200_5b7a92-30 > .kt-row-column-wrap) > .wp-block-kadence-column{justify-content:start;}.kb-row-layout-id200_5b7a92-30 > .kt-row-column-wrap{column-gap:var(--global-kb-gap-md, 2rem);row-gap:var(--global-kb-gap-md, 2rem);padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;grid-template-columns:minmax(0, 1fr);}.kb-row-layout-id200_5b7a92-30 > .kt-row-layout-overlay{opacity:0.30;}@media all and (max-width: 1024px){.kb-row-layout-id200_5b7a92-30 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}@media all and (max-width: 767px){.kb-row-layout-id200_5b7a92-30 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}<\/style><div class=\"kb-row-layout-wrap kb-row-layout-id200_5b7a92-30 alignnone wp-block-kadence-rowlayout\"><div class=\"kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top\">\n<style>.kadence-column200_4e941e-a3 > .kt-inside-inner-col,.kadence-column200_4e941e-a3 > .kt-inside-inner-col:before{border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;border-bottom-left-radius:0px;}.kadence-column200_4e941e-a3 > .kt-inside-inner-col{column-gap:var(--global-kb-gap-sm, 1rem);}.kadence-column200_4e941e-a3 > .kt-inside-inner-col{flex-direction:column;}.kadence-column200_4e941e-a3 > .kt-inside-inner-col > .aligncenter{width:100%;}.kadence-column200_4e941e-a3 > .kt-inside-inner-col:before{opacity:0.3;}.kadence-column200_4e941e-a3{position:relative;}@media all and (max-width: 1024px){.kadence-column200_4e941e-a3 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 767px){.kadence-column200_4e941e-a3 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}<\/style>\n<div class=\"wp-block-kadence-column kadence-column200_4e941e-a3\"><div class=\"kt-inside-inner-col\">\n<style data-wp-block-html=\"css\">\n:root {\n    --primary-blue: #0180FF;\n    --hover-blue: #3499FF;\n    --text-dark: #212529;\n    --text-muted: #8D8C9C;\n    --border-color: #EFEFEF;\n    --success-green: #1E8E3E;\n    --bg-light: #F7F8FA;\n    --white: #ffffff;\n}\n\n*, *::before, *::after {\n    box-sizing: border-box;\n}\n\nhtml, body {\n    overflow-x: hidden;\n    max-width: 100%;\n}\n    \nbody {\n    font-family: 'Sora', sans-serif;\n    background-color: var(--white);\n    color: var(--text-dark);\n}\n\n.ph-title,\n.filter-grid,\n.action-row,\n.tabs-nav,\n.table-container,\n.pagination-container {\n    max-width: 100%;\n}\n    \n.ph-title {\n    font-size: 21px;\n    font-weight: 500;\n    text-transform: uppercase;\n    margin-bottom: 21px;\n    letter-spacing: 0.5px;\n}\n    \n\/* Form Grid *\/\n.filter-grid {\n    display: grid;\n    grid-template-columns: repeat(4, minmax(0, 1fr));\n    gap: 15px;\n    margin-bottom: 20px;\n    max-width: 100%;\n}\n    \n.form-group {\n    display: flex;\n    flex-direction: column;\n}\n    \n.form-group label {\n    font-size: 12px;\n    margin-bottom: 6px;\n    color: var(--text-dark);\n}\n    \n.form-control {\n    height: 38px;\n    padding: 0 12px;\n    border: 1px solid #ced4da;\n    border-radius: 6px;\n    font-family: 'Sora';\n    font-size: 12px;\n    outline: none;\n    box-sizing: border-box;\n    width: 100%;\n    transition: all 0.2s;\n}\n    \n.form-control:focus {\n    background-color: #fff;\n    border-color: var(--primary-blue);\n    box-shadow: 0 0 0 3px rgba(1, 128, 255, 0.1);\n}\n\nselect.form-control {\n    appearance: auto;\n    -webkit-appearance: menulist;\n    -moz-appearance: menulist;\n    padding-right: 28px;\n    cursor: pointer;\n    background-color: #fff;\n}\n\nselect.form-control option {\n    color: var(--text-dark);\n    font-weight: 400;\n}\n    \n\/* Integrated search input inside the trigger *\/\n.cs-search-input {\n    flex: 1;\n    min-width: 60px;\n    border: 0 !important;\n    outline: 0 !important;\n    box-shadow: none !important;\n    background: transparent !important;\n    font-family: 'Sora', sans-serif;\n    font-size: 12px;\n    color: var(--text-dark);\n    padding: 0;\n    height: 26px;\n    -webkit-appearance: none;\n    -moz-appearance: none;\n    appearance: none;\n}\n    \n.cs-search-input:focus,\n.cs-search-input:active,\n.cs-search-input:hover,\n.cs-search-input:focus-visible {\n    border: 0 !important;\n    outline: 0 !important;\n    box-shadow: none !important;\n    background: transparent !important;\n}\n    \n.cs-search-input::placeholder {\n    color: #70757a;\n}\n    \n.custom-select-trigger:has(.cs-search-input) {\n    cursor: text;\n}\n    \n\/* Custom Select *\/\n.custom-select-wrapper {\n    position: relative;\n    width: 100%;\n}\n    \n.custom-select-trigger {\n    height: 38px;\n    padding: 0 36px 0 12px;\n    border: 1px solid #ced4da;\n    background-color: #fff;\n    border-radius: 6px;\n    font-family: 'Sora', sans-serif;\n    font-size: 12px;\n    color: var(--text-dark);\n    cursor: pointer;\n    display: flex;\n    align-items: center;\n    box-sizing: border-box;\n    width: 100%;\n    user-select: none;\n    position: relative;\n    transition: all 0.2s;\n    overflow: hidden;\n    white-space: nowrap;\n}\n    \n.custom-select-trigger:hover {\n    border-color: var(--primary-blue);\n}\n    \n.custom-select-wrapper.open .custom-select-trigger {\n    border-color: var(--primary-blue);\n    border-radius: 6px 6px 0 0;\n    box-shadow: 0 0 0 3px rgba(1, 128, 255, 0.1);\n}\n    \n.custom-select-trigger.placeholder-shown {\n    color: #70757a;\n}\n    \n.custom-select-trigger .cs-arrow {\n    position: absolute;\n    right: 10px;\n    top: 50%;\n    transform: translateY(-50%);\n    pointer-events: none;\n    color: #8D8C9C;\n    transition: transform 0.2s;\n    flex-shrink: 0;\n}\n    \n.custom-select-wrapper.open .custom-select-trigger .cs-arrow {\n    transform: translateY(-50%) rotate(180deg);\n}\n    \n.custom-select-dropdown {\n    display: none;\n    position: absolute;\n    top: 100%;\n    left: 0;\n    right: 0;\n    background: #fff;\n    border: 1px solid var(--primary-blue);\n    border-top: none;\n    border-radius: 0 0 6px 6px;\n    z-index: 9999;\n    overflow-y: auto;\n    max-height: 250px;\n    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.10);\n}\n    \n.cs-label {\n    display: flex;\n    flex-wrap: nowrap;\n    align-items: center;\n    gap: 6px;\n    overflow-x: auto;\n    overflow-y: hidden;\n    white-space: nowrap;\n    width: 100%;\n    min-width: 0;\n    scrollbar-width: thin;\n    -ms-overflow-style: auto;\n}\n    \n.cs-label::-webkit-scrollbar {\n    display: block;\n    height: 4px;\n}\n    \n.cs-label::-webkit-scrollbar-thumb {\n    background: #ccc;\n    border-radius: 4px;\n}\n    \n.custom-select-wrapper.open .custom-select-dropdown {\n    display: block;\n}\n    \n\/* Chips\/Badges styling *\/\n.cs-chips {\n    display: flex;\n    align-items: center;\n    gap: 4px;\n}\n    \n.cs-chip {\n    display: inline-flex;\n    align-items: center;\n    background-color: #e8f0fe;\n    border: 1px solid #d2e3fc;\n    border-radius: 4px;\n    padding: 0 8px;\n    font-size: 12px;\n    color: #1967d2;\n    gap: 4px;\n    white-space: nowrap;\n    flex-shrink: 0;\n    height: 26px;\n    margin: 0;\n}\n    \n.cs-chip-remove {\n    cursor: pointer;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 14px;\n    height: 14px;\n    border-radius: 50%;\n    color: #5f6368;\n    font-weight: bold;\n    transition: background 0.2s;\n}\n    \n.cs-chip-remove:hover {\n    background: #dadce0;\n    color: #202124;\n}\n    \n.custom-select-option {\n    padding: 8px 12px;\n    font-size: 12px;\n    font-family: 'Sora', sans-serif;\n    color: var(--text-dark);\n    cursor: pointer;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    line-height: 1.4;\n    display: flex;\n    align-items: center;\n    gap: 10px;\n}\n    \n.custom-select-option:hover {\n    background: #f0f6ff;\n    color: var(--primary-blue);\n}\n    \n.custom-select-option.selected {\n    background: #e8f1ff;\n    color: var(--primary-blue);\n    font-weight: 500;\n}\n    \n.custom-select-option.highlighted {\n    background: #f0f6ff;\n    color: var(--primary-blue);\n}\n    \n.custom-select-option .cs-checkbox {\n    width: 16px;\n    height: 16px;\n    border: 1px solid #ced4da;\n    border-radius: 3px;\n    background: #fff;\n    position: relative;\n    flex-shrink: 0;\n    display: none;\n}\n    \n.custom-select-wrapper.multi .custom-select-option .cs-checkbox {\n    display: block;\n}\n    \n.custom-select-option.selected .cs-checkbox {\n    background: var(--primary-blue);\n    border-color: var(--primary-blue);\n}\n    \n.custom-select-option.selected .cs-checkbox::after {\n    content: '';\n    position: absolute;\n    left: 5px;\n    top: 2px;\n    width: 4px;\n    height: 8px;\n    border: solid white;\n    border-width: 0 2px 2px 0;\n    transform: rotate(45deg);\n}\n    \n.custom-select-option.placeholder-option {\n    color: #999;\n}\n    \n\/* Search input in dropdown *\/\n.custom-select-search {\n    padding: 8px;\n    border-bottom: 1px solid #EFEFEF;\n    position: sticky;\n    top: 0;\n    background: #fff;\n    z-index: 10;\n}\n    \n.custom-select-search input {\n    width: 100%;\n    height: 30px;\n    padding: 0 10px;\n    border: 1px solid #ced4da;\n    border-radius: 4px;\n    font-family: 'Sora', sans-serif;\n    font-size: 11px;\n    outline: none;\n    box-sizing: border-box;\n}\n    \n.custom-select-search input:focus {\n    border-color: var(--primary-blue);\n}\n    \n\/* Buttons Row \u00e2\u20ac\u201d fills full width with equal flex *\/\n.action-row {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 10px;\n    margin-bottom: 25px;\n    width: 100%;\n}\n    \n.action-row .btn {\n    flex: 1 1 0;\n    min-width: 90px;\n}\n    \n.btn {\n    height: 38px;\n    padding: 0 12px;\n    border-radius: 6px;\n    font-size: 12px;\n    cursor: pointer;\n    border: none;\n    transition: 0.2s;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    white-space: nowrap;\n    box-sizing: border-box;\n}\n    \n.btn-clear {\n    background: #D0D7F3;\n    color: #555;\n}\n    \n.btn-filter {\n    background: var(--primary-blue);\n    color: white;\n}\n    \n.btn-blue {\n    background: var(--primary-blue);\n    color: white;\n}\n    \n.btn:hover {\n    opacity: 0.88;\n}\n    \n\/* Tabs *\/\n.tabs-nav {\n    border-bottom: 1px solid var(--border-color);\n    margin-bottom: 20px;\n    display: flex;\n    flex-wrap: wrap;\n    gap: 20px;\n    max-width: 100%;\n}\n    \n.tab-link {\n    padding: 12px 5px;\n    font-size: 15px;\n    color: var(--text-muted);\n    cursor: pointer;\n    position: relative;\n    white-space: normal;\n}\n    \n.tab-link.active {\n    color: var(--text-dark);\n    font-weight: 500;\n}\n    \n.tab-link.active::after {\n    content: '';\n    position: absolute;\n    bottom: -1px;\n    left: 0;\n    width: 100%;\n    height: 3px;\n    background: var(--primary-blue);\n}\n    \n\/* Table *\/\n.table-container {\n    overflow-x: hidden;\n    max-width: 100%;\n    border: 1px solid var(--border-color);\n    border-radius: 6px;\n}\n    \ntable {\n    width: 100%;\n    max-width: 100%;\n    border-collapse: collapse;\n    font-size: 11px;\n    table-layout: fixed;\n    white-space: normal;\n}\n    \nth {\n    background: var(--bg-light);\n    font-size: 11px;\n    font-weight: 500;\n    padding: 10px 8px;\n    text-align: left;\n    color: var(--text-dark);\n    border-bottom: 1px solid var(--border-color);\n    text-transform: uppercase;\n    white-space: normal;\n    word-break: break-word;\n    line-height: 1.3;\n}\n    \ntd {\n    font-size: 11px;\n    font-weight: 400;\n    padding: 10px 8px;\n    border-bottom: 1px solid #f2f2f2;\n    color: #8D8C9C;\n    white-space: normal;\n    word-break: break-word;\n    overflow-wrap: anywhere;\n    line-height: 1.35;\n    vertical-align: middle;\n}\n    \n\/* Pencil Edit icon button *\/\n.edit-icon-btn {\n    background: none;\n    border: none;\n    cursor: pointer;\n    padding: 5px 8px;\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    gap: 5px;\n    color: var(--text-muted);\n    border-radius: 4px;\n    transition: background 0.15s, color 0.15s;\n    line-height: 1;\n    font-family: 'Sora', sans-serif;\n    font-size: 12px;\n    font-weight: 400;\n}\n    \n.edit-icon-btn:hover {\n    background: #eef3ff;\n    color: var(--primary-blue);\n}\n    \n.edit-icon-btn svg {\n    width: 15px;\n    height: 15px;\n    stroke: currentColor;\n    fill: none;\n    stroke-width: 1.8;\n    stroke-linecap: round;\n    stroke-linejoin: round;\n    display: block;\n}\n    \n.edit-icon-btn .edit-label {\n    font-size: 12px;\n    line-height: 1;\n}\n    \n.action-stack {\n    display: flex;\n    flex-direction: column;\n    gap: 8px;\n    align-items: flex-start;\n}\n    \n.status-pill {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    border-radius: 999px;\n    padding: 4px 12px;\n    font-size: 12px;\n    line-height: 1;\n}\n    \n.status-pill.approved {\n    background: #D3EFE8;\n    color: #268A76;\n}\n    \n.status-pill.not-approved {\n    background: #FDE4E4;\n    color: #B91C1C;\n}\n    \n.status-pill.pending {\n    background: transparent;\n    color: var(--text-muted);\n    padding: 0;\n    border-radius: 0;\n}\n    \n\/* Table entity\/client colored badge *\/\n.entity-badge {\n    display: inline-block;\n    padding: 4px 10px;\n    font-size: 11px;\n    font-weight: 500;\n    line-height: 1.2;\n    white-space: normal;\n    word-break: break-word;\n    border-radius: 20px;\n    background: #D0FDF5;\n    color: #0E7F6E;\n}\n    \n\/* Pagination *\/\n.pagination-container {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    margin-top: 30px;\n    padding-bottom: 40px;\n    gap: 20px;\n    flex-wrap: wrap;\n}\n    \n.pagination-controls {\n    display: flex;\n    align-items: center;\n    gap: 5px;\n    flex-wrap: wrap;\n}\n    \n.page-item {\n    min-width: 32px;\n    height: 32px;\n    padding: 0 6px;\n    box-sizing: border-box;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    cursor: pointer;\n    border-radius: 16px;\n    font-size: 12px;\n    color: var(--text-muted);\n    transition: background 0.2s;\n}\n    \n.page-item.active {\n    background-color: var(--primary-blue);\n    color: white;\n}\n    \n.nav-link {\n    cursor: pointer;\n    color: var(--text-dark);\n    font-size: 12px;\n    padding: 5px 8px;\n    user-select: none;\n}\n    \n.nav-link.disabled {\n    color: #ccc;\n    pointer-events: none;\n}\n    \n\/* Modal Overlays *\/\n.modal-overlay {\n    position: fixed;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    background: rgba(0, 0, 0, 0.5);\n    display: none;\n    justify-content: center;\n    align-items: flex-start;\n    z-index: 1000;\n    padding: 40px 20px;\n    overflow-y: auto;\n    box-sizing: border-box;\n}\n    \n.modal-content {\n    background: white;\n    width: 100%;\n    max-width: 900px;\n    border-radius: 6px;\n    padding: 25px;\n    position: relative;\n    margin-bottom: 20px;\n}\n    \n.modal-header {\n    font-size: 21px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: #333;\n}\n    \n.modal-grid {\n    display: grid;\n    grid-template-columns: repeat(4, 1fr);\n    gap: 15px;\n}\n    \n.modal-footer {\n    margin-top: 25px;\n    display: flex;\n    justify-content: flex-end;\n    gap: 15px;\n}\n    \n.required::after {\n    content: \" *\";\n    color: red;\n}\n    \n\/* Hidden CSV file input *\/\n#csvImportInput {\n    display: none;\n}\n    \n\/* Custom Date Picker *\/\n.date-wrapper {\n    position: relative;\n}\n    \n.date-wrapper input[type=\"text\"] {\n    width: 100%;\n    padding: 10px 36px 10px 14px;\n    border: 1px solid #E0E0E0;\n    border-radius: 6px;\n    font-family: 'Sora', sans-serif;\n    font-size: 12px;\n    color: var(--text-dark);\n    outline: none;\n    cursor: pointer;\n    background: #fff;\n    transition: border-color 0.2s;\n    user-select: none;\n    height: 38px;\n    box-sizing: border-box;\n}\n    \n.date-wrapper input[type=\"text\"]:focus {\n    border-color: var(--primary-blue);\n}\n    \n.date-wrapper input[type=\"text\"]::placeholder {\n    color: #aaa;\n}\n    \n.date-wrapper .cal-icon {\n    position: absolute;\n    right: 12px;\n    top: 50%;\n    transform: translateY(-50%);\n    pointer-events: none;\n    color: #8D8C9C;\n}\n    \n.dp-dropdown {\n    display: none;\n    position: absolute;\n    top: 100%;\n    left: 0;\n    background: #fff;\n    border: 1px solid #EFEFEF;\n    border-radius: 12px;\n    z-index: 9999;\n    margin-top: 8px;\n    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);\n    overflow: hidden;\n    min-width: 0;\n    max-width: min(600px, calc(100vw - 32px));\n    width: min(600px, calc(100vw - 32px));\n}\n    \n.dp-dropdown.open {\n    display: flex;\n}\n    \n.dp-dropdown.align-right {\n    left: auto;\n    right: 0;\n}\n    \n.dp-backdrop {\n    display: none;\n    position: fixed;\n    inset: 0;\n    z-index: 1999;\n}\n    \n.dp-backdrop.show {\n    display: block;\n}\n    \n.dp-presets {\n    width: 140px;\n    border-right: 1px solid #EFEFEF;\n    display: flex;\n    flex-direction: column;\n    background: #fff;\n    padding: 8px 0;\n}\n    \n.dp-preset-item {\n    padding: 10px 16px;\n    font-size: 13px;\n    color: #3c4043;\n    cursor: pointer;\n    transition: all 0.2s;\n    white-space: nowrap;\n}\n    \n.dp-preset-item:hover {\n    background: #F1F3F4;\n}\n    \n.dp-preset-item.active {\n    background: var(--primary-blue);\n    color: #fff;\n    font-weight: 500;\n}\n    \n\/* Two-month panel container *\/\n.dp-calendars-wrap {\n    flex: 1;\n    display: flex;\n    flex-direction: column;\n    padding: 8px 10px 8px;\n    min-width: 0;\n}\n    \n.dp-months-row {\n    display: flex;\n    gap: 0;\n    flex: 1;\n}\n    \n.dp-calendar {\n    flex: 1;\n    padding: 0 6px;\n    min-width: 0;\n}\n    \n.dp-calendar+.dp-calendar {\n    border-left: 1px solid #EFEFEF;\n}\n    \n.dp-cal-header {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    margin-bottom: 6px;\n}\n    \n.dp-cal-title {\n    font-size: 14px;\n    font-weight: 600;\n    color: #3c4043;\n    margin: 0;\n    text-align: center;\n    flex: 1;\n}\n    \n.dp-nav-btn {\n    background: none;\n    border: none;\n    cursor: pointer;\n    padding: 6px;\n    color: #5f6368;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    border-radius: 50%;\n    transition: background 0.2s;\n}\n    \n.dp-nav-btn:hover {\n    background: #F1F3F4;\n}\n    \n.dp-nav-btn.dp-nav-hidden {\n    visibility: hidden;\n    pointer-events: none;\n}\n    \n.dp-weekdays {\n    display: grid;\n    grid-template-columns: repeat(7, 1fr);\n    margin-bottom: 2px;\n}\n    \n.dp-weekday {\n    text-align: center;\n    font-size: 11px;\n    font-weight: 500;\n    color: #8D8C9C;\n    padding: 2px 0;\n}\n    \n.dp-days {\n    display: grid;\n    grid-template-columns: repeat(7, 1fr);\n    gap: 1px;\n}\n    \n.dp-day {\n    text-align: center;\n    padding: 2px 0;\n    font-size: 11px;\n    border-radius: 50%;\n    cursor: pointer;\n    color: var(--text-dark);\n    transition: background 0.15s, color 0.15s;\n    aspect-ratio: 1;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n    \n.dp-day:hover {\n    background: #e8f1ff;\n    color: var(--primary-blue);\n}\n    \n.dp-day.today {\n    background: #F1F3F4;\n    border-radius: 50% !important;\n    font-weight: 600;\n}\n    \n.dp-day.selected {\n    background: var(--primary-blue) !important;\n    color: #fff !important;\n    font-weight: 600;\n    border-radius: 4px !important;\n    z-index: 2;\n}\n    \n.dp-day.in-range,\n.dp-day.hover-range {\n    background: #E8F0FE !important;\n    color: #3c4043;\n    border-radius: 0;\n}\n    \n.dp-day.selected-start,\n.dp-day.row-start,\n.dp-day.hover-start {\n    border-top-left-radius: 4px !important;\n    border-bottom-left-radius: 4px !important;\n}\n    \n.dp-day.selected-end,\n.dp-day.row-end,\n.dp-day.hover-end {\n    border-top-right-radius: 4px !important;\n    border-bottom-right-radius: 4px !important;\n}\n    \n.dp-day.selected-start.selected-end {\n    border-radius: 4px !important;\n}\n    \n.dp-weekday {\n    text-align: center;\n    font-size: 11px;\n    font-weight: 600;\n    color: #333;\n    padding: 4px 0;\n}\n    \n.dp-day.other-month {\n    color: #ccc;\n}\n    \n.dp-day.other-month:hover {\n    background: #f5f5f5;\n    color: #aaa;\n}\n    \n.dp-footer {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    gap: 12px;\n    margin-top: 10px;\n    padding: 12px 16px;\n    border-top: 1px solid #EFEFEF;\n}\n    \n.dp-range-display {\n    font-size: 12px;\n    color: #333;\n    font-weight: 500;\n}\n    \n.dp-btn-clear {\n    padding: 8px 16px;\n    border-radius: 8px;\n    font-size: 12px;\n    font-family: 'Sora', sans-serif;\n    background: #F1F3F4;\n    color: #3c4043;\n    border: none;\n    cursor: pointer;\n    font-weight: 500;\n    transition: background 0.2s;\n}\n    \n.dp-btn-clear:hover {\n    background: #E8EAED;\n}\n    \n.dp-btn-apply {\n    padding: 8px 24px;\n    border-radius: 8px;\n    font-size: 12px;\n    font-family: 'Sora', sans-serif;\n    background: var(--primary-blue);\n    color: #fff;\n    border: none;\n    cursor: pointer;\n    font-weight: 500;\n    transition: background 0.2s;\n}\n    \n.dp-btn-apply:hover {\n    background: var(--hover-blue);\n}\n    \n@media (max-width: 750px) {\n    .dp-dropdown {\n        flex-direction: column;\n        min-width: 0;\n        width: calc(100vw - 32px);\n        left: 50%;\n        transform: translateX(-50%);\n        max-height: 85vh;\n        overflow-y: auto;\n    }\n    \n    .dp-presets {\n        width: 100%;\n        border-right: none;\n        border-bottom: 1px solid #EFEFEF;\n        padding: 4px 0;\n        display: flex;\n        flex-wrap: wrap;\n    }\n    \n    .dp-preset-item {\n        padding: 6px 10px;\n        font-size: 11px;\n        flex: 1 1 auto;\n        text-align: center;\n        min-width: 80px;\n    }\n    \n    .dp-months-row {\n        flex-direction: column;\n        gap: 10px;\n    }\n    \n    .dp-calendar+.dp-calendar {\n        border-left: none;\n        border-top: 1px solid #EFEFEF;\n        padding-top: 8px;\n    }\n    \n    .dp-calendars-wrap {\n        padding: 6px 8px 8px;\n    }\n    \n    .dp-cal-header {\n        margin-bottom: 6px;\n    }\n    \n    .dp-day {\n        padding: 5px 0;\n        font-size: 11px;\n    }\n    \n    .dp-footer {\n        margin-top: 8px;\n        padding-top: 8px;\n    }\n}\n    \n@media (max-width: 480px) {\n    .dp-dropdown {\n        position: fixed;\n        top: 50%;\n        left: 50% !important;\n        transform: translate(-50%, -50%) !important;\n        width: calc(100vw - 24px);\n        max-width: 400px;\n        max-height: 92vh;\n        overflow-y: auto;\n        z-index: 3000;\n    }\n    \n    .dp-calendars-wrap {\n        padding: 6px 6px 6px;\n    }\n    \n    .dp-day {\n        font-size: 11px;\n        padding: 4px 0;\n    }\n    \n    .dp-cal-title {\n        font-size: 12px;\n    }\n    \n    .dp-footer {\n        margin-top: 6px;\n        padding-top: 6px;\n    }\n    \n    .dp-btn-clear,\n    .dp-btn-apply {\n        padding: 5px 10px;\n        font-size: 11px;\n    }\n}\n    \n\/* Responsive *\/\n@media (max-width: 1200px) {\n    .filter-grid {\n        grid-template-columns: repeat(3, minmax(0, 1fr));\n    }\n\n    .modal-grid {\n        grid-template-columns: repeat(3, 1fr);\n    }\n}\n\n@media (max-width: 1024px) {\n    .modal-grid {\n        grid-template-columns: repeat(3, 1fr);\n    }\n}\n    \n@media (max-width: 768px) {\n    body {\n        padding: 12px;\n    }\n    \n    .modal-grid {\n        grid-template-columns: repeat(2, 1fr);\n    }\n    \n    .filter-grid {\n        grid-template-columns: repeat(2, 1fr);\n    }\n    \n    .pagination-container {\n        justify-content: center;\n    }\n    \n    .action-row {\n        gap: 8px;\n    }\n    \n    .btn {\n        font-size: 11px;\n    }\n    \n    .tabs-nav {\n        gap: 16px;\n    }\n}\n    \n@media (max-width: 480px) {\n    .modal-grid {\n        grid-template-columns: 1fr 1fr;\n    }\n    \n    .filter-grid {\n        grid-template-columns: 1fr;\n    }\n    \n    .tabs-nav {\n        gap: 12px;\n    }\n    \n    .action-row .btn {\n        flex: 1 1 calc(50% - 5px);\n    }\n    \n    \/* Pagination Optimization for Mobile *\/\n    .pagination-controls {\n        flex-direction: column;\n        gap: 12px;\n        width: 100%;\n    }\n    \n    #prevBtn {\n        order: 1;\n        width: 100%;\n        text-align: center;\n        border: 1px solid var(--border-color);\n        border-radius: 6px;\n        padding: 8px 12px;\n        box-sizing: border-box;\n    }\n    \n    #pageNumbers {\n        order: 2;\n        justify-content: center;\n    }\n    \n    #nextBtn {\n        order: 3;\n        width: 100%;\n        text-align: center;\n        border: 1px solid var(--border-color);\n        border-radius: 6px;\n        padding: 8px 12px;\n        box-sizing: border-box;\n    }\n    \n    #entryInfo {\n        width: 100% !important;\n        text-align: center;\n    }\n}\n\n.adhoc-modal-content {\n    background: white;\n    width: 100%;\n    max-width: 460px;\n    border-radius: 12px;\n    padding: 32px 28px 28px;\n    position: relative;\n    margin-bottom: 20px;\n}\n.adhoc-modal-title {\n    font-size: 18px;\n    font-weight: 600;\n    margin-bottom: 22px;\n    color: #212529;\n}\n.adhoc-form-group {\n    display: flex;\n    flex-direction: column;\n    margin-bottom: 16px;\n}\n.adhoc-form-group label {\n    font-size: 13px;\n    font-weight: 500;\n    margin-bottom: 6px;\n    color: #212529;\n}\n.adhoc-form-group label .req {\n    color: red;\n    margin-left: 2px;\n}\n.adhoc-form-control {\n    height: 42px;\n    padding: 0 12px;\n    border: 1px solid #ced4da;\n    border-radius: 8px;\n    font-family: 'Sora', sans-serif;\n    font-size: 13px;\n    outline: none;\n    box-sizing: border-box;\n    width: 100%;\n    color: #212529;\n    background: #fff;\n}\n.adhoc-form-control:focus {\n    border-color: var(--primary-blue);\n    box-shadow: 0 0 0 3px rgba(1,128,255,0.1);\n}\n.adhoc-form-control:disabled {\n    background: #f5f5f5;\n    color: #aaa;\n    cursor: not-allowed;\n}\n.adhoc-form-control.select-control {\n    appearance: none;\n    -webkit-appearance: none;\n    background-image: url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='14' height='14' fill='none' stroke='%238D8C9C' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpolyline points='6 9 12 15 18 9'\/%3E%3C\/svg%3E\");\n    background-repeat: no-repeat;\n    background-position: right 12px center;\n    padding-right: 36px;\n}\n.adhoc-modal-footer {\n    display: flex;\n    justify-content: flex-end;\n    gap: 12px;\n    margin-top: 24px;\n}\n.adhoc-btn-close {\n    height: 40px;\n    padding: 0 24px;\n    border-radius: 8px;\n    font-size: 13px;\n    cursor: pointer;\n    border: none;\n    background: transparent;\n    color: #555;\n    font-family: 'Sora', sans-serif;\n    font-weight: 500;\n}\n.adhoc-btn-close:hover { background: #f0f0f0; }\n.adhoc-btn-submit {\n    height: 40px;\n    padding: 0 32px;\n    border-radius: 8px;\n    font-size: 13px;\n    cursor: pointer;\n    border: none;\n    background: var(--primary-blue);\n    color: white;\n    font-family: 'Sora', sans-serif;\n    font-weight: 500;\n}\n.adhoc-btn-submit:hover { opacity: 0.88; }\n\n\/* Ad hoc bulk approve \u2014 PHP list.blade.php checkbox column *\/\n.adhoc-select-col {\n    width: 44px;\n    text-align: center;\n    vertical-align: middle;\n}\n\n.adhoc-bulk-checkbox {\n    width: 16px;\n    height: 16px;\n    cursor: pointer;\n    accent-color: var(--primary-blue);\n}\n<\/style>\n\n<script data-wp-block-html=\"js\">\n\/\/ Helpers to avoid logical-and escaping issues in WordPress\nfunction both(a, b) {\n    if (a) return b;\n    return a;\n  }\n  \n  function every() {\n    const args = Array.prototype.slice.call(arguments);\n    for (let i = 0; i < args.length; i++) {\n      if (!args[i]) return args[i];\n    }\n    return args[args.length - 1];\n  }\n  \n  function formatTableHours(hours) {\n    if (!every(hours !== null, hours !== undefined, hours !== \"\", !isNaN(parseFloat(hours)))) {\n      return \"-\";\n    }\n    return parseFloat(hours).toFixed(2);\n  }\n  \n  function isWpEditorPreview() {\n    try {\n      if (both(document.body, document.body.classList.contains(\"block-editor-iframe__body\"))) {\n        return true;\n      }\n      if (document.querySelector(\".editor-styles-wrapper\")) {\n        return true;\n      }\n      if (both(window.frameElement, window.frameElement.classList.contains(\"wp-block-iframe-sandbox\"))) {\n        return true;\n      }\n      if (window.parent !== window) {\n        try {\n          if (window.parent.document.querySelector(\".block-editor-page\")) {\n            return true;\n          }\n        } catch (e) {\n          return true;\n        }\n      }\n    } catch (e) {}\n    return false;\n  }\n  \n  function safeGetStorage(key) {\n    try {\n      return localStorage.getItem(key);\n    } catch (e) {\n      return null;\n    }\n  }\n  \n  function safeRemoveStorage(key) {\n    try {\n      localStorage.removeItem(key);\n    } catch (e) {}\n  }\n  \n  function getAuthToken() {\n    const fromStorage = safeGetStorage(\"TOKEN\");\n    if (fromStorage) return fromStorage;\n    const match = document.cookie.match(\/(?:^|;\\s*)TOKEN=([^;]+)\/);\n    return match ? decodeURIComponent(match[1].trim()) : \"\";\n  }\n    \n    \/** ENDPOINTS CONFIGURATION **\/\n    const BASE_URL = \"https:\/\/api-ph-portal.zyneventures.com\/api\/v1\";\n    const LOGIN_URL = \"https:\/\/portal.precisionhub.com\/index.php\/login\/\";\n    const ENDPOINTS = {\n      UNSUBMITTED: `${BASE_URL}\/work_assignment\/un-submitted`,\n      ADHOC_ALL: `${BASE_URL}\/ad_hoc_assignment\/all`,\n      USERS: `${BASE_URL}\/user\/table\/list`,\n      USERS_ALL: `${BASE_URL}\/user\/all`,\n      CLIENTS: `${BASE_URL}\/client\/all`,\n      ENTITIES: `${BASE_URL}\/entity\/all`,\n      CATEGORIES: `${BASE_URL}\/category\/table\/list`,\n      PROJECTS: `${BASE_URL}\/project\/all`,\n      ACCOUNTS: `${BASE_URL}\/accountandbenchmark\/tableList`,\n      UPDATE_ASSIGNMENT: `${BASE_URL}\/work_assignment\/update`,\n      UPDATE_ADHOC: `${BASE_URL}\/ad_hoc_assignment\/update`,\n      GET_ASSIGNMENT: `${BASE_URL}\/work_assignment\/detail`,\n      GET_ADHOC: `${BASE_URL}\/ad_hoc_assignment\/detail`,\n      INSURANCES: `${BASE_URL}\/insurance\/all`,\n      PROJECT_TYPES: `${BASE_URL}\/projecttype\/all`,\n      ACCOUNT_DETAIL: `${BASE_URL}\/accountandbenchmark\/detail`,\n      SUBMIT_LOG: `${BASE_URL}\/work_assignment_log\/add`,\n      TEAM_MEMBERS: `${BASE_URL}\/user\/team-members`,\n      ADHOC_ADD: `${BASE_URL}\/ad_hoc_assignment\/add`,\n      ADHOC_APPROVE_BULK: `${BASE_URL}\/ad_hoc_assignment\/approve_bulk`,\n      ADHOC_RESET_BULK: `${BASE_URL}\/ad_hoc_assignment\/reset_bulk`,\n      ASSIGNED_EXPORT: `${BASE_URL}\/work_assignment\/export`,\n      ADHOC_EXPORT: `${BASE_URL}\/ad_hoc_assignment\/export`,\n    };\n    \n    \/\/ \u00e2\u201d\u20ac\u00e2\u201d\u20ac TOKEN VALIDATION (top-of-page gate) \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\n    (function enforceAuth() {\n      if (isWpEditorPreview()) return;\n      if (!getAuthToken()) {\n        window.location.href = LOGIN_URL;\n      }\n    })();\n    \n    let activeView = \"adhoc\";\n    let currentPage = 1;\n    let totalPages = 1;\n    let currentTotalRecords = 0;\n    let currentPerPage = 25;\n    let lastFetchedRows = [];\n    let lastFetchedHeaders = [];\n    \n    let dropDownData = {\n      users: [],\n      teamMembers: [],\n      entities: [],\n      clients: [],\n      accounts: [],\n      categories: [],\n      projects: [],\n      insurances: [],\n      projectTypes: [],\n    };\n    \n    \/\/ \u00e2\u201d\u20ac\u00e2\u201d\u20ac ROLE-BASED ACCESS CONTROL \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\n    \/\/ Source: login.html \u00e2\u20ac\u201c PERMISSION_TIER &#038; USER_DATA set on login.\n    \/\/ These values are UI hints ONLY. Backend re-validates every request\n    \/\/ against the authenticated user derived from the Bearer token.\n    const PERMISSION_TIER = (\n      safeGetStorage(\"PERMISSION_TIER\") || \"none\"\n    ).toLowerCase();\n    const CURRENT_USER_DATA = (() => {\n      try {\n        return JSON.parse(safeGetStorage(\"USER_DATA\") || \"{}\");\n      } catch (e) {\n        return {};\n      }\n    })();\n    const CURRENT_USER_ID =\n      safeGetStorage(\"USER_ID\") ||\n      (CURRENT_USER_DATA.id ? String(CURRENT_USER_DATA.id) : null);\n    const USER_ROLE = (\n      safeGetStorage(\"USER_ROLE\") ||\n      CURRENT_USER_DATA.role ||\n      CURRENT_USER_DATA.role_name ||\n      \"\"\n    )\n      .trim()\n      .toLowerCase();\n    \n    \/\/ PHP Helpers.php teamLeadAndAbove(): manage | director | team lead in role name\n    function teamLeadAndAbovePhp(role = USER_ROLE) {\n      const r = String(role || \"\").toLowerCase();\n      if (!r) return false;\n      return (\n        r.includes(\"manage\") || r.includes(\"director\") || r.includes(\"team lead\")\n      );\n    }\n    \/\/   associate \u00e2\u2020\u2019 read-only (personal), no add\/edit\/approve\/revert\n    \/\/   teamlead  \u00e2\u2020\u2019 read team + edit, no approve\/revert\n    \/\/   manager   \u00e2\u2020\u2019 add\/edit\/approve\/revert on team data\n    \/\/   admin     \u00e2\u2020\u2019 everything\n    const IS_ASSOCIATE = PERMISSION_TIER === \"associate\";\n    const IS_TEAMLEAD = PERMISSION_TIER === \"teamlead\";\n    const IS_MANAGER = PERMISSION_TIER === \"manager\";\n    const IS_ADMIN = PERMISSION_TIER === \"admin\";\n    const USER_PERMISSIONS = (() => {\n      try {\n        const raw = safeGetStorage(\"USER_PERMISSIONS\");\n        if (!raw) return [];\n        const parsed = JSON.parse(raw);\n        return Array.isArray(parsed) ? parsed : [];\n      } catch (e) {\n        return [];\n      }\n    })();\n    function hasUserRight(name) {\n      return USER_PERMISSIONS.some((p) => {\n        if (typeof p === \"string\") return p === name;\n        return p?.right === name || p?.name === name;\n      });\n    }\n    \/\/ PHP list1.blade.php: administrator OR assignment-editing right\n    const HAS_ASSIGNMENT_EDITING = hasUserRight(\"assignment-editing\");\n    const CAN_ADD = IS_MANAGER || IS_ADMIN;\n    const CAN_EDIT =\n      IS_TEAMLEAD || IS_MANAGER || IS_ADMIN || HAS_ASSIGNMENT_EDITING;\n    const CAN_APPROVE =\n      IS_MANAGER || IS_ADMIN || IS_TEAMLEAD || teamLeadAndAbovePhp();\n    const CAN_REVERT = IS_MANAGER || IS_ADMIN;\n    \/\/ PHP list.blade.php teamLeadAndAbove(): bulk approve\/reset + row checkboxes (incl. Deputy Manager)\n    const CAN_BULK_ADHOC = IS_TEAMLEAD || IS_MANAGER || teamLeadAndAbovePhp();\n    \n    function getAdhocTableColspan() {\n      return CAN_BULK_ADHOC ? 13 : 12;\n    }\n    \n    function getSelectedAdhocIds() {\n      return Array.from(document.querySelectorAll(\".adhoc-id-checkbox:checked\"))\n        .map((cb) => parseInt(cb.value, 10))\n        .filter((id) => id > 0);\n    }\n    \n    function toggleSelectAllAdhoc(master) {\n      document.querySelectorAll(\".adhoc-id-checkbox\").forEach((cb) => {\n        cb.checked = !!master.checked;\n      });\n      if (master) master.indeterminate = false;\n    }\n    \n    function syncAdhocSelectAll() {\n      const all = document.querySelectorAll(\".adhoc-id-checkbox\");\n      const master = document.getElementById(\"adhocSelectAll\");\n      if (!master || all.length === 0) return;\n      const checked = document.querySelectorAll(\n        \".adhoc-id-checkbox:checked\",\n      ).length;\n      master.checked = both(checked > 0, checked === all.length);\n      master.indeterminate = both(checked > 0, checked < all.length);\n    }\n    \n    \/\/ \u00e2\u201d\u20ac\u00e2\u201d\u20ac AD HOC PER-ROW RIGHTS (PHP parity) \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\n    \/\/ Mirrors workassignmentteam\/list.blade.php action column:\n    \/\/   is_approved == 2 (Not Approved) \u00e2\u2020\u2019 edit only for administrator\n    \/\/   is_approved != 1 (Pending)      \u00e2\u2020\u2019 edit for administrator OR the record creator\n    \/\/                                      (so a user always edits their OWN pending ad hoc)\n    \/\/   is_approved == 1 (Approved)     \u00e2\u2020\u2019 edit only for administrator\n    \/\/   Approve button (pending only)   \u00e2\u2020\u2019 administrator OR someone who has reports (lead+)\n    function getAdhocApprovalState(row) {\n      const rawStatus = String(row?.status_text || row?.status || \"\")\n        .trim()\n        .toLowerCase();\n      const isApproved =\n        rawStatus === \"approved\" ||\n        rawStatus === \"approve\" ||\n        Number(row?.is_approved) === 1;\n      const isNotApproved =\n        rawStatus === \"not approved\" ||\n        rawStatus === \"not approve\" ||\n        Number(row?.is_approved) === 2;\n      return {\n        isApproved,\n        isNotApproved,\n        isPending: both(!isApproved, !isNotApproved),\n      };\n    }\n    function isOwnAdhocRow(row) {\n      const createdBy = String(row?.created_by ?? row?.created_by_id ?? \"\");\n      return every(\n        !!createdBy,\n        !!CURRENT_USER_ID,\n        createdBy === String(CURRENT_USER_ID),\n      );\n    }\n    function canEditAdhocRow(row) {\n      const { isPending } = getAdhocApprovalState(row);\n      if (isPending) return IS_ADMIN || isOwnAdhocRow(row);\n      return IS_ADMIN;\n    }\n    function canApproveAdhocRow(row) {\n      const { isPending } = getAdhocApprovalState(row);\n      return both(isPending, IS_ADMIN || CAN_APPROVE);\n    }\n    \n    \/\/ Data scope for reads\n    function getScope() {\n      if (IS_ADMIN) return \"all\";\n      if (IS_MANAGER || IS_TEAMLEAD || teamLeadAndAbovePhp()) return \"team\";\n      return \"personal\";\n    }\n    function withScope(url) {\n      if (IS_ADMIN) return url;\n      const sep = (typeof url === \"string\" ? url : url.toString()).includes(\"?\")\n        ? \"&#038;\"\n        : \"?\";\n      return `${url}${sep}scope=${encodeURIComponent(getScope())}`;\n    }\n    \/\/ \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\n    \n    const getHeaders = () => ({\n      \"Content-Type\": \"application\/json\",\n      Authorization: `Bearer ${getAuthToken()}`,\n    });\n    \n    \/\/ Token expiry: only explicit 401 logs the user out (403 = stay logged in).\n    function handleAuthError(res, { logoutOnUnauthorized = true } = {}) {\n      const unauthorized = both(res, res.status === 401);\n      if (!unauthorized) return false;\n      if (!logoutOnUnauthorized) return true;\n      safeRemoveStorage(\"TOKEN\");\n      safeRemoveStorage(\"USER_NAME\");\n      safeRemoveStorage(\"USER_DATA\");\n      safeRemoveStorage(\"USER_ID\");\n      safeRemoveStorage(\"USER_ROLE\");\n      safeRemoveStorage(\"PERMISSION_TIER\");\n      safeRemoveStorage(\"USER_PERMISSIONS\");\n      document.cookie = \"TOKEN=; path=\/; expires=Thu, 01 Jan 1970 00:00:00 GMT;\";\n      window.location.href = LOGIN_URL;\n      return true;\n    }\n    \n    async function fetchWorkAssignmentDetail(id) {\n      return fetch(ENDPOINTS.GET_ASSIGNMENT, {\n        method: \"POST\",\n        headers: getHeaders(),\n        body: JSON.stringify({ id, work_assignment_id: id }),\n      });\n    }\n    \n    async function fetchAdHocDetail(id) {\n      return fetch(ENDPOINTS.GET_ADHOC, {\n        method: \"POST\",\n        headers: getHeaders(),\n        body: JSON.stringify({ id }),\n      });\n    }\n    \n    const extractListData = (payload) => {\n      if (Array.isArray(payload?.data)) return payload.data;\n      if (Array.isArray(payload?.data?.data)) return payload.data.data;\n      if (Array.isArray(payload?.data?.data?.data)) return payload.data.data.data;\n      return [];\n    };\n    \n    const extractPaginationInfo = (payload, fallbackLimit) => {\n      const directPages = Number(\n        payload?.pagination?.pages ||\n          payload?.data?.pagination?.pages ||\n          payload?.last_page ||\n          payload?.data?.last_page ||\n          0,\n      );\n    \n      const limit = Number(\n        payload?.pagination?.limit ||\n          payload?.data?.pagination?.limit ||\n          payload?.per_page ||\n          payload?.data?.per_page ||\n          payload?.data?.perPage ||\n          fallbackLimit,\n      );\n    \n      if (both(Number.isFinite(directPages), directPages > 0)) {\n        return {\n          pages: directPages,\n          limit: both(Number.isFinite(limit), limit > 0) ? limit : fallbackLimit,\n        };\n      }\n    \n      const total = Number(\n        payload?.pagination?.total ||\n          payload?.data?.pagination?.total ||\n          payload?.total ||\n          payload?.data?.total ||\n          0,\n      );\n    \n      const safeLimit = both(Number.isFinite(limit), limit > 0) ? limit : fallbackLimit;\n      const derivedPages = total > 0 ? Math.ceil(total \/ safeLimit) : 1;\n    \n      return { pages: Math.max(1, derivedPages), limit: safeLimit };\n    };\n    \n    async function fetchAllPages(endpoint) {\n      const defaultLimit = 500;\n      const buildUrl = (page, limit = defaultLimit) => {\n        \/\/ RBAC: attach scope so backend filters lookup data by user's access\n        const url = new URL(withScope(endpoint));\n        url.searchParams.set(\"page\", String(page));\n        url.searchParams.set(\"limit\", String(limit));\n        return url.toString();\n      };\n    \n      const firstRes = await fetch(buildUrl(1, defaultLimit), {\n        headers: getHeaders(),\n      });\n      const firstJson = await firstRes.json();\n    \n      let allItems = extractListData(firstJson);\n      const { pages, limit } = extractPaginationInfo(firstJson, defaultLimit);\n    \n      if (pages > 1) {\n        const pageRequests = [];\n        for (let page = 2; page <= pages; page++) {\n          pageRequests.push(\n            fetch(buildUrl(page, limit), { headers: getHeaders() })\n              .then((r) => r.json())\n              .catch(() => null),\n          );\n        }\n    \n        const otherPages = await Promise.all(pageRequests);\n        otherPages.forEach((pageData) => {\n          if (pageData) allItems = allItems.concat(extractListData(pageData));\n        });\n      }\n    \n      return allItems;\n    }\n    \n    function isActiveItem(item) {\n      return item?.is_active === true || item?.is_active === 1;\n    }\n    \n    \/\/ Initialize App\n    async function init() {\n      \/\/ Guard: if this script is loaded on a page without the expected markup,\n      \/\/ skip initialization instead of throwing null element errors.\n      if (!document.getElementById(\"filterForm\")) return;\n      await fetchDropdownData();\n      renderUI();\n      fetchTableData();\n    }\n    \n    async function fetchDropdownData() {\n      try {\n        const [u, uAll, e, c, a, cat, p, ins, pt, tm] = await Promise.all([\n          fetchAllPages(ENDPOINTS.USERS),\n          fetchAllPages(ENDPOINTS.USERS_ALL).catch(() => []),\n          fetchAllPages(ENDPOINTS.ENTITIES),\n          fetchAllPages(ENDPOINTS.CLIENTS),\n          fetch(withScope(ENDPOINTS.ACCOUNTS), { headers: getHeaders() }).then(\n            (r) => r.json(),\n          ),\n          fetchAllPages(ENDPOINTS.CATEGORIES),\n          fetchAllPages(ENDPOINTS.PROJECTS),\n          fetch(ENDPOINTS.INSURANCES, { headers: getHeaders() }).then((r) =>\n            r.json(),\n          ),\n          fetchAllPages(ENDPOINTS.PROJECT_TYPES),\n          fetch(ENDPOINTS.TEAM_MEMBERS, { headers: getHeaders() })\n            .then((r) => r.json())\n            .catch(() => ({})),\n        ]);\n        dropDownData.users = buildUserDirectory([\n          Array.isArray(u) ? u : [],\n          Array.isArray(uAll) ? uAll : [],\n        ]);\n        dropDownData.teamMembers = enrichTeamMembersWithHierarchy(\n          Array.isArray(tm?.data)\n            ? tm.data\n            : Array.isArray(tm?.data?.data)\n              ? tm.data.data\n              : dropDownData.users,\n          dropDownData.users,\n        );\n        dropDownData.entities = Array.isArray(e) ? e : [];\n        dropDownData.clients = Array.isArray(c) ? c : [];\n        dropDownData.accounts = Array.isArray(a) ? a : extractListData(a);\n        dropDownData.categories = Array.isArray(cat) ? cat : [];\n        dropDownData.projects = Array.isArray(p) ? p : [];\n        dropDownData.insurances = Array.isArray(ins?.data?.data)\n          ? ins.data.data\n          : Array.isArray(ins?.data)\n            ? ins.data\n            : [];\n        dropDownData.projectTypes = Array.isArray(pt)\n          ? pt.filter(isActiveItem)\n          : [];\n      } catch (err) {\n        console.error(\"Dropdown fetch error\", err);\n      }\n    }\n    \n    \/* Pencil SVG \u00e2\u20ac\u201d inline so it inherits stroke color *\/\n    const editIconSVG = `<svg viewBox=\"0 0 24 24\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\"\/><path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\"\/><\/svg>`;\n    \n    function renderUI() {\n      const isAssigned = activeView === \"assigned\";\n      const headingEl = document.getElementById(\"pageHeading\");\n      if (headingEl)\n        headingEl.innerText = isAssigned\n          ? \"Assigned Assignment\"\n          : \"Ad Hoc Assignments\";\n    \n      \/\/ Render Filters\n      const form = document.getElementById(\"filterForm\");\n      if (!form) return;\n      \/\/ Always reset inline style so CSS grid class controls layout\n      form.style.gridTemplateColumns = \"\";\n      if (isAssigned) {\n        form.innerHTML = `\n                    ${renderSelect(\"Assigned to\", \"filterAssignedTo\", dropDownData.teamMembers, \"pesudo_name\", \"id\", true)}\n                    ${renderSelect(\"Entity\", \"filterEntity\", dropDownData.entities, \"entity\", \"id\", true)}\n                    ${renderSelect(\"Client\", \"filterClient\", dropDownData.clients, \"name\", \"id\", true)}\n                    ${renderSelect(\"Account\", \"filterAccount\", dropDownData.accounts, \"name\", \"id\", true)}\n                    ${renderSelect(\"Category\", \"filterCategory\", dropDownData.categories, \"category\", \"id\", true)}\n                    ${renderSelect(\"Project\", \"filterProject\", dropDownData.projects, \"name\", \"id\", true)}\n                    <div class=\"form-group\"><label>Select Date<\/label>\n                        <div class=\"date-wrapper\" id=\"dpWrapperAssigned\">\n                            <input type=\"text\" id=\"filterDate\" placeholder=\"Select Date range\" readonly onclick=\"toggleDatePicker(event,'assigned')\">\n                            <svg class=\"cal-icon\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" viewBox=\"0 0 24 24\">\n                                <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"\/>\n                                <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"\/>\n                                <line x1=\"8\"  y1=\"2\" x2=\"8\"  y2=\"6\"\/>\n                                <line x1=\"3\"  y1=\"10\" x2=\"21\" y2=\"10\"\/>\n                            <\/svg>\n                            <div class=\"dp-backdrop\" id=\"dpBackdropAssigned\" onclick=\"closeDatePicker('assigned')\"><\/div>\n                            <div class=\"dp-dropdown\" id=\"dpDropdownAssigned\">\n                                <div class=\"dp-presets\">\n                                    <div class=\"dp-preset-item active\" data-preset=\"today\"     onclick=\"selectPreset(event,'today','assigned')\">Today<\/div>\n                                    <div class=\"dp-preset-item\"       data-preset=\"yesterday\"  onclick=\"selectPreset(event,'yesterday','assigned')\">Yesterday<\/div>\n                                    <div class=\"dp-preset-item\"       data-preset=\"last7\"      onclick=\"selectPreset(event,'last7','assigned')\">Last 7 Days<\/div>\n                                    <div class=\"dp-preset-item\"       data-preset=\"last30\"     onclick=\"selectPreset(event,'last30','assigned')\">Last 30 Days<\/div>\n                                    <div class=\"dp-preset-item\"       data-preset=\"thisMonth\"  onclick=\"selectPreset(event,'thisMonth','assigned')\">This Month<\/div>\n                                    <div class=\"dp-preset-item\"       data-preset=\"lastMonth\"  onclick=\"selectPreset(event,'lastMonth','assigned')\">Last Month<\/div>\n                                <\/div>\n                                <div class=\"dp-calendars-wrap\">\n                                    <div class=\"dp-months-row\">\n                                        <div class=\"dp-calendar\">\n                                            <div class=\"dp-cal-header\">\n                                                <button class=\"dp-nav-btn\" onclick=\"dpChangeMonth(event,-1,'assigned')\">&#8249;<\/button>\n                                                <span class=\"dp-cal-title\" id=\"dpCalTitleAssigned\"><\/span>\n                                                <button class=\"dp-nav-btn dp-nav-hidden\">&#8250;<\/button>\n                                            <\/div>\n                                            <div class=\"dp-weekdays\">\n                                                <div class=\"dp-weekday\">Su<\/div><div class=\"dp-weekday\">Mo<\/div>\n                                                <div class=\"dp-weekday\">Tu<\/div><div class=\"dp-weekday\">We<\/div>\n                                                <div class=\"dp-weekday\">Th<\/div><div class=\"dp-weekday\">Fr<\/div>\n                                                <div class=\"dp-weekday\">Sa<\/div>\n                                            <\/div>\n                                            <div class=\"dp-days\" id=\"dpDaysAssigned\"><\/div>\n                                        <\/div>\n                                        <div class=\"dp-calendar\">\n                                            <div class=\"dp-cal-header\">\n                                                <button class=\"dp-nav-btn dp-nav-hidden\">&#8249;<\/button>\n                                                <span class=\"dp-cal-title\" id=\"dpCalTitleAssigned2\"><\/span>\n                                                <button class=\"dp-nav-btn\" onclick=\"dpChangeMonth(event,1,'assigned')\">&#8250;<\/button>\n                                            <\/div>\n                                            <div class=\"dp-weekdays\">\n                                                <div class=\"dp-weekday\">Su<\/div><div class=\"dp-weekday\">Mo<\/div>\n                                                <div class=\"dp-weekday\">Tu<\/div><div class=\"dp-weekday\">We<\/div>\n                                                <div class=\"dp-weekday\">Th<\/div><div class=\"dp-weekday\">Fr<\/div>\n                                                <div class=\"dp-weekday\">Sa<\/div>\n                                            <\/div>\n                                            <div class=\"dp-days\" id=\"dpDaysAssigned2\"><\/div>\n                                        <\/div>\n                                    <\/div>\n                                    <div class=\"dp-footer\">\n                                        <div class=\"dp-range-display\" id=\"dpRangeDisplayAssigned\">Select Date Range<\/div>\n                                        <div class=\"dp-footer-btns\">\n                                            <button class=\"dp-btn-clear\" onclick=\"dpClear(event,'assigned')\">Cancel<\/button>\n                                            <button class=\"dp-btn-apply\" onclick=\"dpApply(event,'assigned')\">Apply<\/button>\n                                        <\/div>\n                                    <\/div>\n                                <\/div>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                    <div class=\"form-group\"><label>Per Page<\/label><select id=\"filterPerPage\" class=\"form-control\" onchange=\"fetchTableData(1)\"><option value=\"\" disabled selected>Per Page<\/option><option value=\"10\">10<\/option><option value=\"15\">15<\/option><option value=\"25\" >25<\/option><option value=\"50\">50<\/option><option value=\"100\">100<\/option><\/select><\/div>\n                `;\n      } else {\n        form.style.display = \"grid\";\n        form.style.gridTemplateColumns = \"\";\n        form.innerHTML = `\n                    ${renderSelect(\"Assigned to\", \"filterAssignedToAdhoc\", dropDownData.teamMembers, \"pesudo_name\", \"id\", true)}\n                    <div class=\"form-group\">\n                        <label>Status<\/label>\n                        <select id=\"filterStatusAdhoc\" class=\"form-control\" onchange=\"fetchAdhocTableData(1)\">\n                            <option value=\"all\">All<\/option>\n                            <option value=\"pending\">Pending<\/option>\n                            <option value=\"approve\">Approve<\/option>\n                            <option value=\"not approve\">Not Approve<\/option>\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label>Select Date<\/label>\n                        <div class=\"date-wrapper\" id=\"dpWrapperAdhoc\">\n                            <input type=\"text\" id=\"filterAdhocDate\" placeholder=\"Select Date range\" readonly onclick=\"toggleDatePicker(event,'adhoc')\">\n                            <svg class=\"cal-icon\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" viewBox=\"0 0 24 24\">\n                                <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"\/>\n                                <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"\/>\n                                <line x1=\"8\"  y1=\"2\" x2=\"8\"  y2=\"6\"\/>\n                                <line x1=\"3\"  y1=\"10\" x2=\"21\" y2=\"10\"\/>\n                            <\/svg>\n                            <div class=\"dp-backdrop\" id=\"dpBackdropAdhoc\" onclick=\"closeDatePicker('adhoc')\"><\/div>\n                            <div class=\"dp-dropdown\" id=\"dpDropdownAdhoc\">\n                                <div class=\"dp-presets\">\n                                    <div class=\"dp-preset-item active\" data-preset=\"today\"     onclick=\"selectPreset(event,'today','adhoc')\">Today<\/div>\n                                    <div class=\"dp-preset-item\"       data-preset=\"yesterday\"  onclick=\"selectPreset(event,'yesterday','adhoc')\">Yesterday<\/div>\n                                    <div class=\"dp-preset-item\"       data-preset=\"last7\"      onclick=\"selectPreset(event,'last7','adhoc')\">Last 7 Days<\/div>\n                                    <div class=\"dp-preset-item\"       data-preset=\"last30\"     onclick=\"selectPreset(event,'last30','adhoc')\">Last 30 Days<\/div>\n                                    <div class=\"dp-preset-item\"       data-preset=\"thisMonth\"  onclick=\"selectPreset(event,'thisMonth','adhoc')\">This Month<\/div>\n                                    <div class=\"dp-preset-item\"       data-preset=\"lastMonth\"  onclick=\"selectPreset(event,'lastMonth','adhoc')\">Last Month<\/div>\n                                <\/div>\n                                <div class=\"dp-calendars-wrap\">\n                                    <div class=\"dp-months-row\">\n                                        <div class=\"dp-calendar\">\n                                            <div class=\"dp-cal-header\">\n                                                <button class=\"dp-nav-btn\" onclick=\"dpChangeMonth(event,-1,'adhoc')\">&#8249;<\/button>\n                                                <span class=\"dp-cal-title\" id=\"dpCalTitleAdhoc\"><\/span>\n                                                <button class=\"dp-nav-btn\" dp-nav-hidden=\"\">&#8250;<\/button>\n                                            <\/div>\n                                            <div class=\"dp-weekdays\">\n                                                <div class=\"dp-weekday\">Su<\/div><div class=\"dp-weekday\">Mo<\/div>\n                                                <div class=\"dp-weekday\">Tu<\/div><div class=\"dp-weekday\">We<\/div>\n                                                <div class=\"dp-weekday\">Th<\/div><div class=\"dp-weekday\">Fr<\/div>\n                                                <div class=\"dp-weekday\">Sa<\/div>\n                                            <\/div>\n                                            <div class=\"dp-days\" id=\"dpDaysAdhoc\"><\/div>\n                                        <\/div>\n                                        <div class=\"dp-calendar\">\n                                            <div class=\"dp-cal-header\">\n                                                <button class=\"dp-nav-btn dp-nav-hidden\">&#8249;<\/button>\n                                                <span class=\"dp-cal-title\" id=\"dpCalTitleAdhoc2\"><\/span>\n                                                <button class=\"dp-nav-btn\" onclick=\"dpChangeMonth(event,1,'adhoc')\">&#8250;<\/button>\n                                            <\/div>\n                                            <div class=\"dp-weekdays\">\n                                                <div class=\"dp-weekday\">Su<\/div><div class=\"dp-weekday\">Mo<\/div>\n                                                <div class=\"dp-weekday\">Tu<\/div><div class=\"dp-weekday\">We<\/div>\n                                                <div class=\"dp-weekday\">Th<\/div><div class=\"dp-weekday\">Fr<\/div>\n                                                <div class=\"dp-weekday\">Sa<\/div>\n                                            <\/div>\n                                            <div class=\"dp-days\" id=\"dpDaysAdhoc2\"><\/div>\n                                        <\/div>\n                                    <\/div>\n                                    <div class=\"dp-footer\">\n                                        <div class=\"dp-range-display\" id=\"dpRangeDisplayAdhoc\">Select Date Range<\/div>\n                                        <div class=\"dp-footer-btns\">\n                                            <button class=\"dp-btn-clear\" onclick=\"dpClear(event,'adhoc')\">Cancel<\/button>\n                                            <button class=\"dp-btn-apply\" onclick=\"dpApply(event,'adhoc')\">Apply<\/button>\n                                        <\/div>\n                                    <\/div>\n                                <\/div>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                    <div class=\"form-group\"><label>Per Page<\/label><select id=\"filterPerPageAdhoc\" class=\"form-control\" onchange=\"fetchAdhocTableData(1)\"><option value=\"\" disabled selected>Per Page<\/option><option value=\"10\">10<\/option><option value=\"15\">15<\/option><option value=\"25\" selected>25<\/option><option value=\"50\">50<\/option><option value=\"100\">100<\/option><\/select><\/div>\n                `;\n      }\n    \n      \/\/ Render Buttons \u00e2\u20ac\u201d flex:1 on each fills full row width\n      let btns = [];\n      if (isAssigned) {\n        \/\/ Assign Assignment Tab\n        if (IS_ADMIN) {\n          btns = [\n            \"Close\",\n            \"Filter\",\n            \"+ Add New Assignment\",\n            \"+ CSV Import\",\n            \"+ CSV Download\",\n          ];\n        } else if (IS_MANAGER) {\n          btns = [\"Close\", \"Filter\", \"+ CSV Download\"];\n        } else {\n          \/\/ Team Lead and Associate\n          btns = [\"Close\", \"Filter\"];\n        }\n      } else {\n        \/\/ Adhoc Tab\n        if (IS_ASSOCIATE) {\n          btns = [\"Close\", \"Filter\", \"+ CSV Download\", \"+ Add Adhoc\"];\n        } else if (IS_ADMIN) {\n          btns = [\"Close\", \"Filter\", \"+ CSV Download\", \"+ CSV Import\"];\n        } else if (IS_TEAMLEAD) {\n          btns = [\n            \"Close\",\n            \"Filter\",\n            \"+ CSV Download\",\n            \"+ Add Adhoc\",\n            \"Approve All\",\n            \"Reset All\",\n          ];\n        } else {\n          \/\/ Manager \/ Deputy Manager (PHP teamLeadAndAbove)\n          btns = [\n            \"Close\",\n            \"Filter\",\n            \"+ CSV Download\",\n            \"+ CSV Import\",\n            \"+ Add Adhoc\",\n          ];\n          if (CAN_BULK_ADHOC) {\n            btns.push(\"Approve All\", \"Reset All\");\n          }\n        }\n        if (both(CAN_BULK_ADHOC, !btns.includes(\"Approve All\"))) {\n          btns.push(\"Approve All\", \"Reset All\");\n        }\n      }\n    \n      document.getElementById(\"btnGroup\").innerHTML = btns\n        .map(\n          (b) =>\n            `<button class=\"btn ${b === \"Filter\" ? \"btn-filter\" : b === \"Close\" ? \"btn-clear\" : \"btn-blue\"}\" onclick=\"handleActionClick('${b}')\">${b}<\/button>`,\n        )\n        .join(\"\");\n    \n      \/\/ Table Headers\n      const headers = isAssigned\n        ? [\n            \"Assigned Date\",\n            \"Hrs\",\n            \"Assigned To\",\n            \"Pseudo Name\",\n            \"File Name\",\n            \"Received On\",\n            \"Insurance\",\n            \"Account\",\n            \"Project\",\n            \"Entity\",\n            \"Client\",\n            \"Category\",\n            \"Assigned DOS\",\n            \"Action\",\n          ]\n        : [\n            \"Date\",\n            \"Client\",\n            \"Project\",\n            \"Work Type\",\n            \"Desc.\",\n            \"Comments\",\n            \"Time Utilized\",\n            \"Time Approved\",\n            \"Created By\",\n            \"Updated By\",\n            \"Updated At\",\n            \"Action\",\n          ];\n    \n      lastFetchedHeaders = headers.filter((h) => h !== \"Action\");\n      let headHtml = headers.map((h) => `<th>${h}<\/th>`).join(\"\");\n      if (both(!isAssigned, CAN_BULK_ADHOC)) {\n        headHtml += `<th class=\"adhoc-select-col\"><input type=\"checkbox\" id=\"adhocSelectAll\" class=\"adhoc-bulk-checkbox\" title=\"Select all\" onchange=\"toggleSelectAllAdhoc(this)\"><\/th>`;\n      }\n      document.getElementById(\"tblHead\").innerHTML = `<tr>${headHtml}<\/tr>`;\n    \n      const perPageEl = document.getElementById(\"filterPerPage\");\n      if (perPageEl) {\n        perPageEl.onchange = () => fetchTableData(1);\n      }\n    \n      const perPageAdhocEl = document.getElementById(\"filterPerPageAdhoc\");\n      if (perPageAdhocEl) {\n        perPageAdhocEl.onchange = () => fetchAdhocTableData(1);\n      }\n    }\n    \n    function renderSelect(\n      label,\n      selectId,\n      data,\n      labelKey,\n      valueKey = \"id\",\n      multi = false,\n    ) {\n      const optionsData = (data || []).map((item) => ({\n        _val: item[valueKey] ?? \"\",\n        _label: item[labelKey] ?? \"\",\n      }));\n      const optionsHtml =\n        `\n            <div class=\"custom-select-option placeholder-option\" style=\"display:none;\" data-value=\"\" onclick=\"csSelect('${selectId}', '', this, ${multi})\">\n                <div class=\"cs-checkbox\"><\/div>\n                <span class=\"opt-label\">Select ${label}<\/span>\n            <\/div>\n        ` +\n        optionsData\n          .map(\n            (o, i) =>\n              `<div class=\"custom-select-option\" data-value=\"${o._val}\" onclick=\"csSelect('${selectId}', '${o._val.toString().replace(\/'\/g, \"\\\\'\")}', this, ${multi})\">\n                    <div class=\"cs-checkbox\"><\/div>\n                    <span class=\"opt-label\">${o._label}<\/span>\n                <\/div>`,\n          )\n          .join(\"\");\n      return `\n                <div class=\"form-group\">\n                    <label>${label}<\/label>\n                    <div class=\"custom-select-wrapper${multi ? \" multi\" : \"\"}\" id=\"csWrapper_${selectId}\">\n                        <input type=\"hidden\" id=\"${selectId}\" value=\"\">\n                        <div class=\"custom-select-trigger placeholder-shown\" onclick=\"csTriggerClick('${selectId}', event)\">\n                            <div class=\"cs-label\">\n                                <input type=\"text\" class=\"cs-search-input\" id=\"csInput_${selectId}\" placeholder=\"Select ${label}\" autocomplete=\"off\" oninput=\"csIntegratedFilter('${selectId}', this.value)\" onkeydown=\"csKeyDown(event, '${selectId}')\" onclick=\"csOpenDropdown('${selectId}'); event.stopPropagation();\" onfocus=\"csOpenDropdown('${selectId}')\">\n                            <\/div>\n                            <svg class=\"cs-arrow\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" viewBox=\"0 0 24 24\"><polyline points=\"6 9 12 15 18 9\"\/><\/svg>\n                        <\/div>\n                        <div class=\"custom-select-dropdown\" id=\"csDrop_${selectId}\">\n                            <div class=\"custom-select-options\">\n                                ${optionsHtml}\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                <\/div>\n            `;\n    }\n    \n    function csToggle(selectId, e) {\n      if (e) e.stopPropagation();\n      const wrapper = document.getElementById(\"csWrapper_\" + selectId);\n      const isOpen = wrapper.classList.contains(\"open\");\n      document.querySelectorAll(\".custom-select-wrapper.open\").forEach((w) => {\n        if (w !== wrapper) w.classList.remove(\"open\");\n      });\n      if (isOpen) {\n        wrapper.classList.remove(\"open\");\n      } else {\n        wrapper.classList.add(\"open\");\n        \/\/ Reset filter state and focus the integrated search input if present\n        const searchInput = document.getElementById(\"csInput_\" + selectId);\n        if (searchInput) {\n          searchInput.value = \"\";\n          csIntegratedFilter(selectId, \"\");\n          setTimeout(() => searchInput.focus(), 50);\n        } else {\n          csIntegratedFilter(selectId, \"\");\n        }\n        csHighlightFirst(selectId);\n      }\n    }\n    \n    function csTriggerClick(selectId, e) {\n      e.stopPropagation();\n      csToggle(selectId, e);\n    }\n    \n    function csOpenDropdown(selectId) {\n      const wrapper = document.getElementById(\"csWrapper_\" + selectId);\n      if (!wrapper || wrapper.classList.contains(\"open\")) return;\n      document.querySelectorAll(\".custom-select-wrapper.open\").forEach((w) => {\n        if (w !== wrapper) w.classList.remove(\"open\");\n      });\n      wrapper.classList.add(\"open\");\n      csHighlightFirst(selectId);\n    }\n    \n    function csFilter(selectId, query) {\n      csIntegratedFilter(selectId, query);\n    }\n    \n    function csIntegratedFilter(selectId, query) {\n      const drop = document.getElementById(\"csDrop_\" + selectId);\n      if (!drop) return;\n      const options = drop.querySelectorAll(\".custom-select-option\");\n      const q = (query || \"\").toLowerCase();\n      options.forEach((opt) => {\n        const text = opt.textContent.toLowerCase();\n        if (text.includes(q) || opt.classList.contains(\"placeholder-option\")) {\n          opt.style.display = \"\";\n        } else {\n          opt.style.display = \"none\";\n        }\n      });\n      \/\/ Open dropdown automatically whenever the user types in the field\n      const wrapper = document.getElementById(\"csWrapper_\" + selectId);\n      if (both(wrapper, !wrapper.classList.contains(\"open\"))) {\n        wrapper.classList.add(\"open\");\n      }\n      csHighlightFirst(selectId);\n    }\n    \n    function csHighlightFirst(selectId) {\n      const drop = document.getElementById(\"csDrop_\" + selectId);\n      if (!drop) return;\n      drop\n        .querySelectorAll(\".custom-select-option\")\n        .forEach((o) => o.classList.remove(\"highlighted\"));\n      const visible = Array.from(\n        drop.querySelectorAll(\".custom-select-option\"),\n      ).filter(\n        (o) =>\n          both(\n            o.style.display !== \"none\",\n            !o.classList.contains(\"placeholder-option\"),\n          ),\n      );\n      if (visible.length > 0) {\n        visible[0].classList.add(\"highlighted\");\n      }\n    }\n    \n    function csKeyDown(e, selectId) {\n      const wrapper = document.getElementById(\"csWrapper_\" + selectId);\n      const drop = document.getElementById(\"csDrop_\" + selectId);\n      if (!wrapper || !drop) return;\n      const isOpen = wrapper.classList.contains(\"open\");\n    \n      if (e.key === \"Enter\") {\n        e.preventDefault();\n        if (!isOpen) {\n          csToggle(selectId, e);\n        } else {\n          const highlighted = drop.querySelector(\n            \".custom-select-option.highlighted\",\n          );\n          if (highlighted) {\n            const multi = wrapper.classList.contains(\"multi\");\n            const value = highlighted.dataset.value;\n            csSelect(selectId, value, highlighted, multi);\n          } else {\n            csToggle(selectId, e);\n          }\n        }\n        return;\n      }\n    \n      if (e.key === \"ArrowDown\") {\n        e.preventDefault();\n        if (!isOpen) {\n          csToggle(selectId, e);\n          return;\n        }\n        const visibleOptions = Array.from(\n          drop.querySelectorAll(\".custom-select-option\"),\n        ).filter(\n          (o) =>\n            both(\n              o.style.display !== \"none\",\n              !o.classList.contains(\"placeholder-option\"),\n            ),\n        );\n        if (visibleOptions.length === 0) return;\n        let currentIdx = visibleOptions.findIndex((o) =>\n          o.classList.contains(\"highlighted\"),\n        );\n        visibleOptions.forEach((o) => o.classList.remove(\"highlighted\"));\n        currentIdx = (currentIdx + 1) % visibleOptions.length;\n        visibleOptions[currentIdx].classList.add(\"highlighted\");\n        visibleOptions[currentIdx].scrollIntoView({ block: \"nearest\" });\n        return;\n      }\n    \n      if (e.key === \"ArrowUp\") {\n        e.preventDefault();\n        if (!isOpen) {\n          csToggle(selectId, e);\n          return;\n        }\n        const visibleOptions = Array.from(\n          drop.querySelectorAll(\".custom-select-option\"),\n        ).filter(\n          (o) =>\n            both(\n              o.style.display !== \"none\",\n              !o.classList.contains(\"placeholder-option\"),\n            ),\n        );\n        if (visibleOptions.length === 0) return;\n        let currentIdx = visibleOptions.findIndex((o) =>\n          o.classList.contains(\"highlighted\"),\n        );\n        visibleOptions.forEach((o) => o.classList.remove(\"highlighted\"));\n        if (currentIdx <= 0) currentIdx = visibleOptions.length - 1;\n        else currentIdx -= 1;\n        visibleOptions[currentIdx].classList.add(\"highlighted\");\n        visibleOptions[currentIdx].scrollIntoView({ block: \"nearest\" });\n        return;\n      }\n    \n      if (e.key === \"Escape\") {\n        wrapper.classList.remove(\"open\");\n        return;\n      }\n    }\n    \n    function csSelect(selectId, value, optionEl, multi = false) {\n      const wrapper = document.getElementById(\"csWrapper_\" + selectId);\n      const input = document.getElementById(selectId);\n      const trigger = wrapper.querySelector(\".custom-select-trigger\");\n      const labelEl = trigger.querySelector(\".cs-label\");\n    \n      if (value === \"\") {\n        input.value = \"\";\n        \/\/ If trigger has an integrated search input, restore it; otherwise show option label\n        const placeholderLabel = wrapper.querySelector(\n          \".placeholder-option .opt-label\",\n        );\n        const hadIntegratedInput = !!document.getElementById(\"csInput_\" + selectId);\n        if (hadIntegratedInput) {\n          const phText = placeholderLabel\n            ? placeholderLabel.textContent.trim()\n            : \"\";\n          labelEl.innerHTML = `<input type=\"text\" class=\"cs-search-input\" id=\"csInput_${selectId}\" placeholder=\"${phText}\" autocomplete=\"off\" oninput=\"csIntegratedFilter('${selectId}', this.value)\" onkeydown=\"csKeyDown(event, '${selectId}')\" onclick=\"csOpenDropdown('${selectId}'); event.stopPropagation();\" onfocus=\"csOpenDropdown('${selectId}')\">`;\n        } else {\n          labelEl.innerHTML = optionEl\n            .querySelector(\".opt-label\")\n            .textContent.trim();\n        }\n        trigger.classList.add(\"placeholder-shown\");\n        wrapper\n          .querySelectorAll(\".custom-select-option\")\n          .forEach((o) => o.classList.remove(\"selected\"));\n        if (!multi) wrapper.classList.remove(\"open\");\n        handleActionClick(\"Filter\");\n        return;\n      }\n    \n      if (!multi) {\n        input.value = value;\n        const selectedText = optionEl\n          .querySelector(\".opt-label\")\n          .textContent.trim();\n        const hadIntegratedInput = !!document.getElementById(\"csInput_\" + selectId);\n        if (hadIntegratedInput) {\n          labelEl.innerHTML = `<input type=\"text\" class=\"cs-search-input\" id=\"csInput_${selectId}\" placeholder=\"${selectedText}\" autocomplete=\"off\" oninput=\"csIntegratedFilter('${selectId}', this.value)\" onkeydown=\"csKeyDown(event, '${selectId}')\" onclick=\"csOpenDropdown('${selectId}'); event.stopPropagation();\" onfocus=\"csOpenDropdown('${selectId}')\">`;\n        } else {\n          labelEl.textContent = selectedText;\n        }\n        trigger.classList.remove(\"placeholder-shown\");\n        wrapper\n          .querySelectorAll(\".custom-select-option\")\n          .forEach((o) => o.classList.remove(\"selected\"));\n        optionEl.classList.add(\"selected\");\n        wrapper.classList.remove(\"open\");\n      } else {\n        let values = input.value ? input.value.split(\",\") : [];\n        const idx = values.indexOf(value);\n        if (idx > -1) {\n          values.splice(idx, 1);\n          optionEl.classList.remove(\"selected\");\n        } else {\n          values.push(value);\n          optionEl.classList.add(\"selected\");\n        }\n        input.value = values.join(\",\");\n    \n        const placeholderLabel = wrapper.querySelector(\n          \".placeholder-option .opt-label\",\n        );\n        const phText = placeholderLabel ? placeholderLabel.textContent.trim() : \"\";\n    \n        if (values.length === 0) {\n          labelEl.innerHTML = `<input type=\"text\" class=\"cs-search-input\" id=\"csInput_${selectId}\" placeholder=\"${phText}\" autocomplete=\"off\" oninput=\"csIntegratedFilter('${selectId}', this.value)\" onkeydown=\"csKeyDown(event, '${selectId}')\" onclick=\"csOpenDropdown('${selectId}'); event.stopPropagation();\" onfocus=\"csOpenDropdown('${selectId}')\">`;\n          trigger.classList.add(\"placeholder-shown\");\n        } else {\n          trigger.classList.remove(\"placeholder-shown\");\n          const selectedLabels = Array.from(\n            wrapper.querySelectorAll(\".custom-select-option.selected\"),\n          ).map((opt) => ({\n            val: opt.dataset.value,\n            label: opt.querySelector(\".opt-label\").textContent.trim(),\n          }));\n    \n          const chipsHtml = selectedLabels\n            .map(\n              (item) => `\n                    <div class=\"cs-chip\">\n                        <span>${item.label}<\/span>\n                        <span class=\"cs-chip-remove\" onclick=\"csRemoveChip(event, '${selectId}', '${item.val}')\">&times;<\/span>\n                    <\/div>\n                `,\n            )\n            .join(\"\");\n    \n          labelEl.innerHTML =\n            chipsHtml +\n            `<input type=\"text\" class=\"cs-search-input\" id=\"csInput_${selectId}\" placeholder=\"\" autocomplete=\"off\" oninput=\"csIntegratedFilter('${selectId}', this.value)\" onkeydown=\"csKeyDown(event, '${selectId}')\" onclick=\"csOpenDropdown('${selectId}'); event.stopPropagation();\" onfocus=\"csOpenDropdown('${selectId}')\">`;\n        }\n    \n        \/\/ Keep dropdown open and refocus the integrated input so user can continue searching\n        if (wrapper.classList.contains(\"open\")) {\n          const newInput = document.getElementById(\"csInput_\" + selectId);\n          if (newInput) setTimeout(() => newInput.focus(), 0);\n        }\n      }\n      handleActionClick(\"Filter\");\n    }\n    \n    function csRemoveChip(e, selectId, value) {\n      e.stopPropagation();\n      const wrapper = document.getElementById(\"csWrapper_\" + selectId);\n      const optionEl = wrapper.querySelector(\n        `.custom-select-option[data-value=\"${value}\"]`,\n      );\n      if (optionEl) {\n        csSelect(selectId, value, optionEl, true);\n      }\n    }\n    \n    function csGetValue(selectId) {\n      const el = document.getElementById(selectId);\n      return el ? el.value : \"\";\n    }\n    \n    \/\/ Close custom selects when clicking outside\n    document.addEventListener(\"click\", function (e) {\n      if (!e.target.closest(\".custom-select-wrapper\")) {\n        document\n          .querySelectorAll(\".custom-select-wrapper.open\")\n          .forEach((w) => w.classList.remove(\"open\"));\n      }\n    });\n    \n    function safeText(value) {\n      if (value === null || value === undefined || value === \"\") return \"-\";\n      return String(value)\n        .replaceAll(\"&\", \"&amp;\")\n        .replaceAll(\"<\", \"&lt;\")\n        .replaceAll(\">\", \"&gt;\")\n        .replaceAll('\"', \"&quot;\")\n        .replaceAll(\"'\", \"&#039;\");\n    }\n    \n    function getOnlyDate(val) {\n      if (!val) return \"\";\n      const str = String(val).trim();\n      if (str.includes(\"T\")) return str.split(\"T\")[0];\n      if (str.includes(\" \")) return str.split(\" \")[0];\n      return str;\n    }\n    \n    function formatAdhocDecimal(val) {\n      if (val === null || val === undefined || val === \"\") return \"-\";\n      const str = String(val).trim();\n      if (str.includes(\":\")) return str;\n      const num = parseFloat(str);\n      if (!isNaN(num)) {\n        return num.toFixed(2);\n      }\n      return str;\n    }\n    \n    function formatDate(dStr) {\n      if (!dStr) return \"\";\n      const str = String(dStr).trim();\n      if (str.includes(\"T\")) return str.split(\"T\")[0];\n      if (str.includes(\" \")) return str.split(\" \")[0];\n      if (str.includes(\"\/\")) {\n        const parts = str.split(\"\/\");\n        if (parts.length === 3) {\n          const mm = parts[0].padStart(2, \"0\");\n          const dd = parts[1].padStart(2, \"0\");\n          const yyyy = parts[2];\n          return `${yyyy}-${mm}-${dd}`;\n        }\n      }\n      return str;\n    }\n    function normalizeAssignmentRow(row) {\n      if (!row) return row;\n      return {\n        ...row,\n        file_id: row.file_id ?? row.file?.id ?? null,\n        account_id:\n          row.account_id ?? row.account?.id ?? row.account_relation_id ?? null,\n        assigned_to:\n          row.assigned_to ?? row.assigned_to_user_id ?? row.assignedTo?.id ?? null,\n        received_on: getOnlyDate(row.received_on ?? row.file_received_on),\n        assigned_date: getOnlyDate(row.assigned_date),\n        file_name: row.file_name ?? row.file?.file_name ?? \"\",\n        project_type_id: row.project_type_id ?? row.project_type?.id ?? null,\n        insurance_id: row.insurance_id ?? row.insurance?.id ?? null,\n      };\n    }\n   \n    function buildSelectOptions(\n      data,\n      valueKey,\n      labelKey,\n      selectedValue,\n      fallbackLabel = \"\",\n    ) {\n      const selected = String(selectedValue ?? \"\");\n      const options = (data || [])\n        .map(\n          (item) =>\n            `<option value=\"${item[valueKey] ?? \"\"}\" ${String(item[valueKey]) === selected ? \"selected\" : \"\"}>${item[labelKey] ?? \"\"}<\/option>`,\n        )\n        .join(\"\");\n      if (\n        selected &&\n        !(data || []).some((item) => String(item[valueKey]) === selected)\n      ) {\n        const label = fallbackLabel || `Selected (#${selected})`;\n        return `<option value=\"${selected}\" selected>${safeText(label)}<\/option>${options}`;\n      }\n      return options;\n    }\n  \n    function escapeAttr(value) {\n      return String(value ?? \"\")\n        .replace(\/&\/g, \"&amp;\")\n        .replace(\/\"\/g, \"&quot;\")\n        .replace(\/<\/g, \"&lt;\");\n    }\n  \n    function buildUserDirectory(sources) {\n      const map = new Map();\n      (sources || []).forEach((batch) => {\n        (batch || []).forEach((user) => {\n          if (!user || user.id == null) return;\n          const key = String(user.id);\n          map.set(key, { ...(map.get(key) || {}), ...user });\n        });\n      });\n      return [...map.values()];\n    }\n  \n    function getUserTeamLabel(user) {\n      return (\n        user?.team_name ||\n        user?.team ||\n        user?.department_name ||\n        user?.department ||\n        \"Other\"\n      );\n    }\n  \n    function getUserReportToLabel(user) {\n      return (\n        user?.report_to_name ||\n        user?.report_to ||\n        user?.manager_name ||\n        user?.team_lead ||\n        \"\"\n      );\n    }\n  \n    function getUserPseudoName(user) {\n      if (!user) return \"\";\n      return (\n        user.pesudo_name ||\n        user.pseudo_name ||\n        user.pesudoName ||\n        user.name ||\n        \"\"\n      );\n    }\n  \n    function enrichTeamMembersWithHierarchy(teamMembers, userDirectory) {\n      const directory = new Map();\n      (userDirectory || []).forEach((user) => {\n        if (user && user.id != null) directory.set(String(user.id), user);\n      });\n  \n      return (teamMembers || []).map((member) => {\n        const info = directory.get(String(member.id)) || {};\n        const merged = { ...info, ...member };\n        return {\n          ...merged,\n          pesudo_name: getUserPseudoName(member) || getUserPseudoName(info),\n          team_name: getUserTeamLabel(merged),\n          report_to_name: getUserReportToLabel(merged),\n        };\n      });\n    }\n  \n    function sortUsersByTeamHierarchy(users) {\n      return [...(users || [])].sort((a, b) => {\n        const teamCompare = getUserTeamLabel(a)\n          .toLowerCase()\n          .localeCompare(getUserTeamLabel(b).toLowerCase());\n        if (teamCompare !== 0) return teamCompare;\n  \n        const reportCompare = getUserReportToLabel(a)\n          .toLowerCase()\n          .localeCompare(getUserReportToLabel(b).toLowerCase());\n        if (reportCompare !== 0) return reportCompare;\n  \n        return getUserPseudoName(a)\n          .toLowerCase()\n          .localeCompare(getUserPseudoName(b).toLowerCase());\n      });\n    }\n  \n    function buildGroupedUserSelectOptions(selectedValue, fallbackLabel = \"\") {\n      const members = sortUsersByTeamHierarchy(dropDownData.teamMembers || []);\n      const selected = String(selectedValue ?? \"\");\n  \n      let html = members\n        .map((user) => {\n          const val = String(user.id ?? \"\");\n          return `<option value=\"${escapeAttr(val)}\" ${val === selected ? \"selected\" : \"\"}>${safeText(getUserPseudoName(user))}<\/option>`;\n        })\n        .join(\"\");\n  \n      if (selected && !members.some((user) => String(user.id) === selected)) {\n        const label = fallbackLabel || `Selected (#${selected})`;\n        html =\n          `<option value=\"${escapeAttr(selected)}\" selected>${safeText(label)}<\/option>` + html;\n      }\n  \n      return html;\n    }\n    function calcAdhocEditHrs() {\n      const mins =\n        parseInt(document.getElementById(\"editAdhocMinsUtilized\")?.value, 10) || 0;\n      const hrsEl = document.getElementById(\"editAdhocHrsUtilized\");\n      if (hrsEl) {\n        hrsEl.value = Math.floor(mins \/ 60);\n      }\n    }\n    \n    \/\/ PHP parity: public\/assets\/js\/custom.js timeConvert(n)\n    \/\/ Treats n as TOTAL minutes and splits into { hour, minutes }.\n    function timeConvert(n) {\n      const num = parseInt(n, 10) || 0;\n      const hours = num \/ 60;\n      const rhours = Math.floor(hours);\n      const rminutes = Math.round((hours - rhours) * 60);\n      return { hour: rhours, minutes: rminutes };\n    }\n    \n    \/\/ Holds the utilized hrs\/mins of the row currently open in the approval modal\n    let _approvalUtilized = { hrs: 0, mins: 0 };\n    \n    \/\/ PHP parity: custom.js blur handler on #minute_approved.\n    \/\/ The Mins Approved field is entered as TOTAL minutes and split into hrs + remainder.\n    function recalcApproveHrs() {\n      const minsEl = document.getElementById(\"approveMins\");\n      const hrsEl = document.getElementById(\"approveHrs\");\n      if (!minsEl || !hrsEl) return;\n      const t = timeConvert(minsEl.value);\n      hrsEl.value = t.hour;\n      minsEl.value = t.minutes;\n    }\n    \n    \/\/ PHP parity: custom.js change handler on #approveStatus.\n    \/\/   Approved     \u00e2\u2020\u2019 approved time = utilized time, comment \"Approved\"\n    \/\/   Not Approved \u00e2\u2020\u2019 approved time = 0, comment \"Not Approved\"\n    function onApproveStatusChange() {\n      const statusEl = document.getElementById(\"approveStatus\");\n      const minsEl = document.getElementById(\"approveMins\");\n      const hrsEl = document.getElementById(\"approveHrs\");\n      const commentEl = document.getElementById(\"approveComment\");\n      if (!statusEl) return;\n      const label = (statusEl.options[statusEl.selectedIndex]?.text || \"\").trim();\n      if (label === \"Approved\") {\n        if (minsEl) minsEl.value = _approvalUtilized.mins;\n        if (hrsEl) hrsEl.value = _approvalUtilized.hrs;\n        if (commentEl) commentEl.value = \"Approved\";\n      } else if (label === \"Not Approved\") {\n        if (minsEl) minsEl.value = 0;\n        if (hrsEl) hrsEl.value = 0;\n        if (commentEl) commentEl.value = \"Not Approved\";\n      }\n    }\n    \n    function getFilterValue(id) {\n      const el = document.getElementById(id);\n      return el ? el.value : \"\";\n    }\n    \n    function getAssignedFilters() {\n      return {\n        entity_id: getFilterValue(\"filterEntity\"),\n        category_id: getFilterValue(\"filterCategory\"),\n        account_id: getFilterValue(\"filterAccount\"),\n        client_id: getFilterValue(\"filterClient\"),\n        project_id: getFilterValue(\"filterProject\"),\n        assigned_to: getFilterValue(\"filterAssignedTo\"),\n        assigned_date: getFilterValue(\"filterDate\"),\n        perPage: getFilterValue(\"filterPerPage\") || \"25\",\n      };\n    }\n    \n    function buildUnsubmittedUrl(page = 1) {\n      const filters = getAssignedFilters();\n      \/\/ RBAC: scope tells backend whether to return personal \/ team \/ all\n      const url = new URL(withScope(ENDPOINTS.UNSUBMITTED));\n      url.searchParams.set(\"page\", String(page));\n      url.searchParams.set(\"perPage\", String(filters.perPage));\n    \n      Object.entries(filters).forEach(([key, value]) => {\n        if (every(key !== \"perPage\", key !== \"assigned_date\", value !== \"\")) {\n          url.searchParams.set(key, value);\n        }\n      });\n    \n      if (filters.assigned_date) {\n        const datesParam = formatDatesParam(filters.assigned_date);\n        if (datesParam) {\n          url.searchParams.set(\"dates\", datesParam);\n        }\n      }\n    \n      return url;\n    }\n    \n    function appendAssignedExportFilters(url) {\n      const filters = getAssignedFilters();\n      Object.entries({\n        assigned_to: filters.assigned_to,\n        entity_id: filters.entity_id,\n        client_id: filters.client_id,\n        account_id: filters.account_id,\n        category_id: filters.category_id,\n        project_id: filters.project_id,\n      }).forEach(([key, value]) => {\n        if (value !== \"\") url.searchParams.set(key, value);\n      });\n      if (filters.assigned_date) {\n        const datesParam = formatDatesParam(filters.assigned_date);\n        if (datesParam) url.searchParams.set(\"dates\", datesParam);\n      }\n    }\n    \n    function buildAssignedExportUrl() {\n      const url = new URL(withScope(ENDPOINTS.ASSIGNED_EXPORT));\n      appendAssignedExportFilters(url);\n      return url;\n    }\n    \n    function appendAdhocExportFilters(url) {\n      const filters = getAdhocFilters();\n      if (filters.assigned_to) {\n        url.searchParams.set(\"assigned_to\", filters.assigned_to);\n      }\n      const allowedStatus = new Set([\n        \"pending\",\n        \"approve\",\n        \"not approve\",\n        \"0\",\n        \"1\",\n        \"all\",\n      ]);\n      if (both(allowedStatus.has(filters.status), filters.status !== \"all\")) {\n        url.searchParams.set(\"status\", filters.status);\n      }\n      if (filters.date) {\n        const datesParam = formatDatesParam(filters.date);\n        if (datesParam) url.searchParams.set(\"dates\", datesParam);\n      }\n    }\n    \n    function buildAdhocExportUrl() {\n      const url = new URL(withScope(ENDPOINTS.ADHOC_EXPORT));\n      appendAdhocExportFilters(url);\n      return url;\n    }\n    \n    function getAdhocFilters() {\n      return {\n        assigned_to: getFilterValue(\"filterAssignedToAdhoc\"),\n        status: getFilterValue(\"filterStatusAdhoc\") || \"all\",\n        date: getFilterValue(\"filterAdhocDate\"),\n        perPage: getFilterValue(\"filterPerPageAdhoc\") || \"25\",\n      };\n    }\n    \n    function isPositiveIntegerString(value) {\n      return both(\/^\\d+$\/.test(String(value)), Number(value) > 0);\n    }\n    \n    \/\/ Validates a date string is in YYYY-MM-DD format\n    function isValidISODate(str) {\n      return \/^\\d{4}-\\d{2}-\\d{2}$\/.test(str.trim());\n    }\n    \n    \/\/ Formats the dates filter value for the API.\n    \/\/ Picker outputs: \"YYYY-MM-DD - YYYY-MM-DD\" (range) or \"YYYY-MM-DD\" (single).\n    \/\/ API expects:    \"YYYY-MM-DD - YYYY-MM-DD\" (range) or \"YYYY-MM-DD\" (single).\n    function formatDatesParam(rawValue) {\n      if (!rawValue) return \"\";\n      const val = rawValue.trim();\n    \n      \/\/ Range format: \"YYYY-MM-DD - YYYY-MM-DD\"\n      if (val.includes(\" - \")) {\n        const parts = val.split(\" - \");\n        if (\n          every(\n            parts.length === 2,\n            isValidISODate(parts[0]),\n            isValidISODate(parts[1]),\n          )\n        ) {\n          return `${parts[0].trim()} to ${parts[1].trim()}`;\n        }\n        return \"\";\n      }\n    \n      \/\/ Already in \"YYYY-MM-DD to YYYY-MM-DD\" format (e.g. typed manually)\n      if (val.includes(\" to \")) {\n        const parts = val.split(\" to \");\n        if (\n          every(\n            parts.length === 2,\n            isValidISODate(parts[0]),\n            isValidISODate(parts[1]),\n          )\n        ) {\n          return `${parts[0].trim()} to ${parts[1].trim()}`;\n        }\n        return \"\";\n      }\n    \n      \/\/ Single date format: \"YYYY-MM-DD\"\n      if (isValidISODate(val)) {\n        return val;\n      }\n    \n      return \"\";\n    }\n    \n    function buildAdhocUrl(page = 1) {\n      const filters = getAdhocFilters();\n      \/\/ RBAC: scope tells backend whether to return personal \/ team \/ all\n      const url = new URL(withScope(ENDPOINTS.ADHOC_ALL));\n      const pageValue = isPositiveIntegerString(page) ? String(page) : \"1\";\n      const perPageValue = isPositiveIntegerString(filters.perPage)\n        ? String(filters.perPage)\n        : \"25\";\n    \n      url.searchParams.set(\"page\", pageValue);\n      url.searchParams.set(\"perPage\", perPageValue);\n    \n      if (filters.assigned_to) {\n        url.searchParams.set(\"assigned_to\", filters.assigned_to);\n      }\n    \n      const allowedStatus = new Set([\n        \"pending\",\n        \"approve\",\n        \"not approve\",\n        \"0\",\n        \"1\",\n        \"all\",\n      ]);\n      if (both(allowedStatus.has(filters.status), filters.status !== \"all\")) {\n        url.searchParams.set(\"status\", filters.status);\n      }\n    \n      if (filters.date) {\n        const datesParam = formatDatesParam(filters.date);\n        if (datesParam) {\n          url.searchParams.set(\"dates\", datesParam);\n        }\n      }\n      return url;\n    }\n    \n    function clearAssignedFilters() {\n      const selectIds = [\n        \"filterAssignedTo\",\n        \"filterEntity\",\n        \"filterClient\",\n        \"filterAccount\",\n        \"filterCategory\",\n        \"filterProject\",\n      ];\n      selectIds.forEach((id) => {\n        const el = document.getElementById(id);\n        if (el) el.value = \"\";\n    \n        const wrapper = document.getElementById(\"csWrapper_\" + id);\n        if (wrapper) {\n          const trigger = wrapper.querySelector(\".custom-select-trigger\");\n          const labelEl = trigger.querySelector(\".cs-label\");\n          const placeholder = wrapper.querySelector(\".placeholder-option\");\n          const phText = placeholder\n            ? placeholder.querySelector(\".opt-label\").textContent.trim()\n            : \"Select\";\n          \/\/ Rebuild integrated search input so the field stays searchable after reset\n          labelEl.innerHTML = `<input type=\"text\" class=\"cs-search-input\" id=\"csInput_${id}\" placeholder=\"${phText}\" autocomplete=\"off\" oninput=\"csIntegratedFilter('${id}', this.value)\" onkeydown=\"csKeyDown(event, '${id}')\" onclick=\"csOpenDropdown('${id}'); event.stopPropagation();\" onfocus=\"csOpenDropdown('${id}')\">`;\n          trigger.classList.add(\"placeholder-shown\");\n          wrapper\n            .querySelectorAll(\".custom-select-option\")\n            .forEach((o) => o.classList.remove(\"selected\"));\n          \/\/ Make sure all options are visible again after a reset\n          wrapper.querySelectorAll(\".custom-select-option\").forEach((o) => {\n            o.style.display = \"\";\n          });\n        }\n      });\n    \n      const dateEl = document.getElementById(\"filterDate\");\n      if (dateEl) dateEl.value = \"\";\n    \n      \/\/ Also clear the date picker state\n      [\"assigned\", \"adhoc\"].forEach((inst) => {\n        if (both(dpState, dpState[inst])) {\n          dpState[inst].startDate = null;\n          dpState[inst].endDate = null;\n          dpState[inst].hoverDate = null;\n          dpState[inst].activePreset = null;\n          dpState[inst].selectedDate = null;\n          try {\n            dpUpdateFooterRange(inst);\n          } catch (e) {}\n          try {\n            dpRenderCalendar(inst);\n          } catch (e) {}\n        }\n      });\n    \n      const perPageEl = document.getElementById(\"filterPerPage\");\n      if (perPageEl) perPageEl.value = \"25\";\n    \n      currentPage = 1;\n      fetchTableData(1);\n    }\n    \n    function clearAdhocFilters() {\n      const assignedEl = document.getElementById(\"filterAssignedToAdhoc\");\n      if (assignedEl) {\n        assignedEl.value = \"\";\n        const wrapper = document.getElementById(\"csWrapper_filterAssignedToAdhoc\");\n        if (wrapper) {\n          const trigger = wrapper.querySelector(\".custom-select-trigger\");\n          const labelEl = trigger.querySelector(\".cs-label\");\n          const placeholder = wrapper.querySelector(\".placeholder-option\");\n          const phText = placeholder\n            ? placeholder.querySelector(\".opt-label\").textContent.trim()\n            : \"Select\";\n          \/\/ Rebuild integrated search input so the field stays searchable after reset\n          labelEl.innerHTML = `<input type=\"text\" class=\"cs-search-input\" id=\"csInput_filterAssignedToAdhoc\" placeholder=\"${phText}\" autocomplete=\"off\" oninput=\"csIntegratedFilter('filterAssignedToAdhoc', this.value)\" onkeydown=\"csKeyDown(event, 'filterAssignedToAdhoc')\" onclick=\"csOpenDropdown('filterAssignedToAdhoc'); event.stopPropagation();\" onfocus=\"csOpenDropdown('filterAssignedToAdhoc')\">`;\n          trigger.classList.add(\"placeholder-shown\");\n          wrapper\n            .querySelectorAll(\".custom-select-option\")\n            .forEach((o) => o.classList.remove(\"selected\"));\n          \/\/ Make sure all options are visible again after a reset\n          wrapper.querySelectorAll(\".custom-select-option\").forEach((o) => {\n            o.style.display = \"\";\n          });\n        }\n      }\n    \n      const statusEl = document.getElementById(\"filterStatusAdhoc\");\n      if (statusEl) statusEl.value = \"all\";\n    \n      const dateEl = document.getElementById(\"filterAdhocDate\");\n      if (dateEl) dateEl.value = \"\";\n    \n      \/\/ Also clear the date picker state\n      [\"assigned\", \"adhoc\"].forEach((inst) => {\n        if (both(dpState, dpState[inst])) {\n          dpState[inst].startDate = null;\n          dpState[inst].endDate = null;\n          dpState[inst].hoverDate = null;\n          dpState[inst].activePreset = null;\n          dpState[inst].selectedDate = null;\n          try {\n            dpUpdateFooterRange(inst);\n          } catch (e) {}\n          try {\n            dpRenderCalendar(inst);\n          } catch (e) {}\n        }\n      });\n    \n      const perPageEl = document.getElementById(\"filterPerPageAdhoc\");\n      if (perPageEl) perPageEl.value = \"25\";\n    \n      currentPage = 1;\n      fetchAdhocTableData(1);\n    }\n    \n    function handleActionClick(action) {\n      if (action === \"Filter\") {\n        if (activeView === \"assigned\") {\n          fetchTableData(1);\n        } else {\n          fetchAdhocTableData(1);\n        }\n        return;\n      }\n    \n      if (action === \"Clear\" || action === \"Close\") {\n        if (activeView === \"assigned\") {\n          clearAssignedFilters();\n        } else {\n          clearAdhocFilters();\n        }\n        return;\n      }\n    \n      if (action === \"+ Add New Assignment\") {\n        if (!CAN_ADD) {\n          alert(\"Access denied: you do not have permission to add assignments.\");\n          return;\n        }\n        window.location.href =\n          \"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/assign-work\/\";\n        return;\n      }\n    \n      if (action === \"+ CSV Import\") {\n        if (activeView === \"assigned\") {\n          window.location.href =\n            \"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/import-assignment-data\/\";\n        } else {\n          window.location.href =\n            \"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/import-adhoc-data\/\";\n        }\n        return;\n      }\n    \n      if (action === \"+ CSV Download\") {\n        downloadCSV();\n        return;\n      }\n    \n      if (action === \"+ Add Adhoc\" || action === \"+ Add Ad Hoc\") {\n        openAddAdHocModal();\n        return;\n      }\n    \n      if (action === \"Approve All\") {\n        if (!CAN_BULK_ADHOC) {\n          alert(\n            \"Access denied: you do not have permission to bulk approve ad hoc assignments.\",\n          );\n          return;\n        }\n        approveAllAdhoc();\n        return;\n      }\n    \n      if (action === \"Reset All\") {\n        if (!CAN_BULK_ADHOC) {\n          alert(\n            \"Access denied: you do not have permission to bulk reset ad hoc assignments.\",\n          );\n          return;\n        }\n        resetAllAdhoc();\n        return;\n      }\n    }\n    \n    \/* \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac CSV IMPORT \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac *\/\n    function handleCSVImport(event) {\n      const file = event.target.files[0];\n      if (!file) return;\n      if (!file.name.toLowerCase().endsWith(\".csv\")) {\n        alert(\"Please select a valid .csv file.\");\n        return;\n      }\n    \n      const reader = new FileReader();\n      reader.onload = function (e) {\n        const text = e.target.result;\n        const lines = text.trim().split(\"\\n\");\n        if (lines.length < 2) {\n          alert(\"CSV file is empty or has no data rows.\");\n          return;\n        }\n    \n        const headerRow = lines[0]\n          .split(\",\")\n          .map((h) => h.trim().replace(\/^\"|\"$\/g, \"\"));\n        const dataRows = lines\n          .slice(1)\n          .map((line) => {\n            return line.split(\",\").map((cell) => cell.trim().replace(\/^\"|\"$\/g, \"\"));\n          })\n          .filter((row) => row.some((cell) => cell !== \"\"));\n    \n        if (dataRows.length === 0) {\n          alert(\"No data rows found in CSV.\");\n          return;\n        }\n    \n        document.getElementById(\"tblHead\").innerHTML =\n          `<tr>${headerRow.map((h) => `<th>${h}<\/th>`).join(\"\")}<\/tr>`;\n        document.getElementById(\"tblBody\").innerHTML = dataRows\n          .map(\n            (row) =>\n              `<tr>${row.map((cell) => `<td>${cell || \"-\"}<\/td>`).join(\"\")}<\/tr>`,\n          )\n          .join(\"\");\n    \n        updatePaginationDisplay(\n          { total: dataRows.length, pages: 1, perPage: dataRows.length },\n          1,\n        );\n        alert(`CSV imported successfully: ${dataRows.length} row(s) loaded.`);\n      };\n      reader.onerror = function () {\n        alert(\"Failed to read the CSV file.\");\n      };\n      reader.readAsText(file);\n    }\n    \n    \/* \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac CSV DOWNLOAD (PHP parity: work_assignment\/export + ad_hoc_assignment\/export) \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac *\/\n    async function downloadCSV() {\n      const btn =\n        document.querySelector(\".action-bar .btn-primary:last-of-type\") ||\n        Array.from(document.querySelectorAll(\".action-bar button\")).find((b) =>\n          (b.textContent || \"\").includes(\"CSV Download\"),\n        );\n      const origHtml = btn ? btn.innerHTML : \"\";\n    \n      if (btn) {\n        btn.disabled = true;\n        btn.innerHTML = \"Downloading...\";\n      }\n    \n      try {\n        const token = getAuthToken();\n        if (!token) {\n          alert(\"You are not logged in. Please login again.\");\n          return;\n        }\n    \n        const exportUrl =\n          activeView === \"assigned\"\n            ? buildAssignedExportUrl()\n            : buildAdhocExportUrl();\n    \n        const res = await fetch(exportUrl.toString(), {\n          method: \"GET\",\n          headers: { Authorization: \"Bearer \" + token },\n        });\n    \n        if (handleAuthError(res)) return;\n    \n        if (!res.ok) {\n          let message = \"Failed to download CSV.\";\n          try {\n            const errJson = await res.json();\n            message =\n              errJson.message ||\n              (both(errJson.messages, errJson.messages[0])) ||\n              message;\n          } catch (_) {\n            message = message + \" (HTTP \" + res.status + \")\";\n          }\n          alert(message);\n          return;\n        }\n    \n        const blob = await res.blob();\n        if (!blob || blob.size === 0) {\n          alert(\"No data available to export for the selected filters.\");\n          return;\n        }\n    \n        let filename =\n          activeView === \"assigned\"\n            ? \"work-assignment-\" + Date.now() + \".csv\"\n            : \"allAdHocAssignment_\" +\n              new Date().toLocaleString(\"en-US\", { month: \"short\" }) +\n              \".csv\";\n        const disposition = res.headers.get(\"Content-Disposition\");\n        if (disposition) {\n          const match = disposition.match(\/filename=\"?([^\";\\n]+)\"?\/i);\n          if (both(match, match[1])) filename = match[1].trim();\n        }\n    \n        const objectUrl = URL.createObjectURL(blob);\n        const link = document.createElement(\"a\");\n        link.href = objectUrl;\n        link.download = filename;\n        document.body.appendChild(link);\n        link.click();\n        document.body.removeChild(link);\n        URL.revokeObjectURL(objectUrl);\n      } catch (err) {\n        console.error(\"CSV Download Error:\", err);\n        alert(\"Failed to download CSV. Please try again.\");\n      } finally {\n        if (btn) {\n          btn.disabled = false;\n          btn.innerHTML = origHtml;\n        }\n      }\n    }\n    \n    function headerToKey(header) {\n      const map = {\n        \"Assigned Date\": \"assigned_date\",\n        Hrs: \"hours\",\n        \"Assigned To\": \"assigned_to_name\",\n        \"Pseudo Name\": \"pesudo_name\",\n        \"File Name\": \"file_name\",\n        \"Received On\": \"received_on\",\n        Insurance: \"insurance_name\",\n        Account: \"account_name\",\n        Project: \"project_name\",\n        Entity: \"entity_name\",\n        Client: \"client_name\",\n        Category: \"category_name\",\n        \"Assigned DOS\": \"assigned_dos\",\n        Pages: \"pages\",\n        DOS: \"dos_count\",\n        Amount: \"amount\",\n        \"DOS Completed\": \"dos_completed\",\n        \"Pending DOS\": \"pending_dos\",\n        Remarks: \"remarks\",\n        Date: \"date\",\n        \"Work Type\": \"ad_hoc_work_type\",\n        \"Desc.\": \"description\",\n        Comments: \"comments\",\n        \"Time Utilized\": \"time_utilized_display\",\n        \"Time Approved\": \"time_approved_display\",\n        \"Created By\": \"created_by_name\",\n        \"Updated By\": \"approved_by_name\",\n        \"Updated At\": \"updated_at\",\n      };\n      return map[header] || header.toLowerCase().replace(\/\\s+\/g, \"_\");\n    }\n    \n    \/* \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac PAGINATION RENDER \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac *\/\n    function updatePagination(meta) {\n      const container = document.getElementById(\"pageNumbers\");\n      container.innerHTML = \"\";\n    \n      const total = Number(meta.total) || 0;\n      const perPage = Number(meta.perPage || meta.limit || meta.per_page) || 25;\n      const totalPages = Math.ceil(total \/ perPage) || 1;\n      const current = currentPage;\n    \n      const startEntry = total === 0 ? 0 : (current - 1) * perPage + 1;\n      const endEntry = Math.min(current * perPage, total);\n      document.getElementById(\"entryInfo\").textContent =\n        `Showing ${startEntry} to ${endEntry} of ${total} entries`;\n    \n      const maxVisible = 5;\n      let startPage = Math.max(1, current - Math.floor(maxVisible \/ 2));\n      let endPage = Math.min(totalPages, startPage + maxVisible - 1);\n    \n      if (endPage - startPage + 1 < maxVisible) {\n        startPage = Math.max(1, endPage - maxVisible + 1);\n      }\n    \n      \/\/ First page + ellipsis\n      if (startPage > 1) {\n        appendPageItem(container, 1, current);\n        if (startPage > 2) appendEllipsis(container);\n      }\n    \n      \/\/ Middle pages\n      for (let i = startPage; i <= endPage; i++) {\n        appendPageItem(container, i, current);\n      }\n    \n      \/\/ Ellipsis + last page\n      if (endPage < totalPages) {\n        if (endPage < totalPages - 1) appendEllipsis(container);\n        appendPageItem(container, totalPages, current);\n      }\n    \n      const prevBtn = document.getElementById(\"prevBtn\");\n      const nextBtn = document.getElementById(\"nextBtn\");\n    \n      prevBtn.className = `nav-link ${current === 1 ? \"disabled\" : \"\"}`;\n      nextBtn.className = `nav-link ${current === totalPages || totalPages === 0 ? \"disabled\" : \"\"}`;\n    \n      prevBtn.onclick = () => {\n        if (currentPage > 1) {\n          currentPage--;\n          triggerFetch();\n        }\n      };\n      nextBtn.onclick = () => {\n        if (currentPage < totalPages) {\n          currentPage++;\n          triggerFetch();\n        }\n      };\n    }\n    \n    function appendPageItem(container, pageNum, activePage) {\n      const p = document.createElement(\"div\");\n      p.className = `page-item ${pageNum === activePage ? \"active\" : \"\"}`;\n      p.textContent = pageNum;\n      p.onclick = () => {\n        currentPage = pageNum;\n        triggerFetch();\n      };\n      container.appendChild(p);\n    }\n    \n    function appendEllipsis(container) {\n      const el = document.createElement(\"div\");\n      el.className = \"page-item\";\n      el.textContent = \"...\";\n      el.style.cursor = \"default\";\n      container.appendChild(el);\n    }\n    \n    function triggerFetch() {\n      if (activeView === \"assigned\") fetchTableData(currentPage);\n      else fetchAdhocTableData(currentPage);\n    }\n    \n    function updatePaginationDisplay(meta, page) {\n      currentPage = page;\n      updatePagination(meta);\n    }\n    \n    async function fetchTableData(page = 1) {\n      if (activeView !== \"assigned\") return;\n      const url = buildUnsubmittedUrl(page);\n    \n      try {\n        const res = await fetch(url.toString(), { headers: getHeaders() });\n        if (handleAuthError(res)) return;\n        const json = await res.json();\n        const rows = Array.isArray(json?.data?.data) ? json.data.data : [];\n        lastFetchedRows = rows;\n    \n        if (rows.length === 0) {\n          document.getElementById(\"tblBody\").innerHTML =\n            '<tr><td colspan=\"14\" style=\"text-align:center;\">No data found<\/td><\/tr>';\n          updatePaginationDisplay({ total: 0, pages: 1, perPage: 25 }, 1);\n          return;\n        }\n    \n        document.getElementById(\"tblBody\").innerHTML = rows\n          .map(\n            (row) => `\n                    <tr>\n                        <td>${safeText(getOnlyDate(row.assigned_date))}<\/td>\n                        <td>${formatTableHours(row.hours)}<\/td>\n                        <td>${safeText(row.assigned_to_name)}<\/td>\n                        <td>${safeText(row.pesudo_name)}<\/td>\n                        <td>${safeText(row.file_name)}<\/td>\n                        <td>${safeText(getOnlyDate(row.received_on))}<\/td>\n                        <td>${safeText(row.insurance_name)}<\/td>\n                        <td>${safeText(row.account_name)}<\/td>\n                        <td>${safeText(row.project_name)}<\/td>\n                        <td>${safeText(row.entity_name)}<\/td>\n                        <td><span class=\"entity-badge\">${safeText(row.client_name)}<\/span><\/td>\n                        <td>${safeText(row.category_name)}<\/td>\n                        <td>${safeText(row.assigned_dos)}<\/td>\n                        <td>\n                            <div style=\"display: flex; gap: 8px;\">\n                                ${\n                                  CAN_EDIT\n                                    ? `\n                                <button class=\"edit-icon-btn\" onclick=\"openEditModal('assigned', ${Number(row.id) || 0})\" title=\"Edit\">\n                                    ${editIconSVG}<span class=\"edit-label\">Edit<\/span>\n                                <\/button>`\n                                    : \"\"\n                                }\n                                ${\n                                  !IS_ADMIN\n                                    ? `\n                                <button class=\"edit-icon-btn\" onclick=\"openSubmitModal(${Number(row.id) || 0})\" title=\"Submit\">\n                                    ${editIconSVG}<span class=\"edit-label\">Submit<\/span>\n                                <\/button>`\n                                    : \"\"\n                                }\n                                ${both(!CAN_EDIT, IS_ADMIN) ? `<span style=\"color: var(--text-muted); font-size: 12px;\">\u00e2\u20ac\u201d<\/span>` : \"\"}\n                            <\/div>\n                        <\/td>\n                    <\/tr>\n                `,\n          )\n          .join(\"\");\n    \n        const meta = {\n          total: json?.data?.total || json?.data?.pagination?.total || rows.length,\n          pages:\n            json?.data?.pages ||\n            json?.data?.pagination?.pages ||\n            json?.data?.last_page ||\n            1,\n          perPage:\n            json?.data?.perPage ||\n            json?.data?.pagination?.limit ||\n            json?.data?.per_page ||\n            25,\n        };\n        updatePaginationDisplay(meta, page);\n      } catch (error) {\n        console.error(\"Un-submitted fetch error\", error);\n        document.getElementById(\"tblBody\").innerHTML =\n          '<tr><td colspan=\"14\" style=\"text-align:center;\">Failed to load data<\/td><\/tr>';\n      }\n    }\n    \n    async function fetchAdhocTableData(page = 1) {\n      if (activeView !== \"adhoc\") return;\n      const url = buildAdhocUrl(page);\n    \n      try {\n        const res = await fetch(url.toString(), { headers: getHeaders() });\n        if (handleAuthError(res)) return;\n        const json = await res.json();\n        const rows = Array.isArray(json?.data?.rows) ? json.data.rows : [];\n        lastFetchedRows = rows;\n    \n        if (!rows.length) {\n          document.getElementById(\"tblBody\").innerHTML =\n            `<tr><td colspan=\"${getAdhocTableColspan()}\" style=\"text-align:center;\">No data found<\/td><\/tr>`;\n          updatePaginationDisplay({ total: 0, pages: 1, perPage: 25 }, 1);\n          return;\n        }\n    \n        document.getElementById(\"tblBody\").innerHTML = rows\n          .map((row) => {\n            \/\/ \u00e2\u201d\u20ac\u00e2\u201d\u20ac STATUS: derive the freshest possible label & class \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\n            \/\/ Backend may return: status_text ('Approved'\/'Pending'\/'Not Approved'),\n            \/\/ status (string), or is_approved (0\/1). Prefer the most specific.\n            const rawStatus = String(row.status_text || row.status || \"\")\n              .trim()\n              .toLowerCase();\n            const isApprovedRow =\n              rawStatus === \"approved\" ||\n              rawStatus === \"approve\" ||\n              Number(row.is_approved) === 1;\n            const isNotApprovedRow =\n              rawStatus === \"not approved\" ||\n              rawStatus === \"not approve\" ||\n              Number(row.is_approved) === 2;\n            const statusClass = isApprovedRow\n              ? \"approved\"\n              : isNotApprovedRow\n                ? \"not-approved\"\n                : \"pending\";\n            const statusLabel = isApprovedRow\n              ? \"Approved\"\n              : isNotApprovedRow\n                ? \"Not Approved\"\n                : row.status_text || row.status || \"Pending\";\n    \n            \/\/ \u00e2\u201d\u20ac\u00e2\u201d\u20ac UPDATED BY: prefer explicit updated_by fields; fall back to approver \u00e2\u201d\u20ac\n            const updatedBy =\n              row.updated_by_name ||\n              row.updated_by ||\n              row.modified_by_name ||\n              row.approved_by_name ||\n              \"\";\n    \n            return `\n                    <tr>\n                        <td>${safeText(row.date)}<\/td>\n                        <td>${safeText(row.client_name)}<\/td>\n                        <td>${safeText(row.project_name)}<\/td>\n                        <td style=\"white-space: normal; word-break: break-word;\">${safeText(row.ad_hoc_work_type)}<\/td>\n                        <td style=\"white-space: normal; word-break: break-word;\">${safeText(row.description)}<\/td>\n                        <td>${safeText(row.comments)}<\/td>\n                        <td>${safeText(formatAdhocDecimal(row.time_utilized_display || row.time_utilized_decimal))}<\/td>\n                        <td>${safeText(formatAdhocDecimal(row.time_approved_display || row.time_approved_decimal))}<\/td>\n                        <td>${safeText(row.created_by_name)}<\/td>\n                        <td>${safeText(updatedBy)}<\/td>\n                        <td>${safeText(getOnlyDate(row.updated_at || row.approved_at))}<\/td>\n                        <td>\n                            <div class=\"action-stack\">\n                                ${\n                                  canEditAdhocRow(row)\n                                    ? `\n                                <button class=\"edit-icon-btn\" onclick=\"openEditModal('adhoc', ${Number(row.id) || 0})\" title=\"Edit\">\n                                    ${editIconSVG}<span class=\"edit-label\">Edit<\/span>\n                                <\/button>`\n                                    : ``\n                                }\n                                ${\n                                  statusClass === \"pending\"\n                                    ? canApproveAdhocRow(row)\n                                      ? `<span class=\"status-pill pending\" style=\"cursor: pointer;\" onclick=\"openApprovalModal(${Number(row.id) || 0})\">${safeText(statusLabel)}<\/span>`\n                                      : `<span class=\"status-pill pending\">${safeText(statusLabel)}<\/span>`\n                                    : `<span class=\"status-pill ${statusClass}\">${safeText(statusLabel)}<\/span>`\n                                }\n                            <\/div>\n                        <\/td>\n                        ${\n                          CAN_BULK_ADHOC\n                            ? `\n                        <td class=\"adhoc-select-col\">\n                            <input type=\"checkbox\" class=\"adhoc-bulk-checkbox adhoc-id-checkbox\" name=\"adhoc_id[]\" value=\"${Number(row.id) || 0}\" onchange=\"syncAdhocSelectAll()\">\n                        <\/td>`\n                            : \"\"\n                        }\n                    <\/tr>\n                `;\n          })\n          .join(\"\");\n        syncAdhocSelectAll();\n    \n        const meta = {\n          total: json?.data?.total || json?.data?.pagination?.total || rows.length,\n          pages:\n            json?.data?.pages ||\n            json?.data?.pagination?.pages ||\n            json?.data?.last_page ||\n            1,\n          perPage:\n            json?.data?.perPage ||\n            json?.data?.pagination?.limit ||\n            json?.data?.per_page ||\n            25,\n        };\n        updatePaginationDisplay(meta, page);\n      } catch (error) {\n        console.error(\"Adhoc fetch error\", error);\n        document.getElementById(\"tblBody\").innerHTML =\n          `<tr><td colspan=\"${getAdhocTableColspan()}\" style=\"text-align:center;\">Failed to load data<\/td><\/tr>`;\n      }\n    }\n    \n    function toggleTab(view) {\n      activeView = view;\n      lastFetchedRows = [];\n      document\n        .getElementById(\"tab-assigned\")\n        .classList.toggle(\"active\", view === \"assigned\");\n      document\n        .getElementById(\"tab-adhoc\")\n        .classList.toggle(\"active\", view === \"adhoc\");\n      renderUI();\n      if (view === \"adhoc\") {\n        fetchAdhocTableData(1);\n      } else {\n        fetchTableData();\n      }\n    }\n    \n    \/\/ Currently editing record id (stored for update calls)\n    let _editingAssignedId = null;\n    let _editingAssignedRow = null;\n  \n  function parseFormInt(value) {\n    if (value === \"\" || value === null || value === undefined) return null;\n    const n = parseInt(String(value), 10);\n    return Number.isNaN(n) ? null : n;\n  }\n  \n  function resolveEditFileId() {\n    const fromInput = document.getElementById(\"editFileId\")?.value;\n    if (fromInput !== \"\" && fromInput != null) {\n      const parsed = parseFormInt(fromInput);\n      if (parsed != null) return parsed;\n    }\n    const fromRow = _editingAssignedRow?.file_id ?? _editingAssignedRow?.file?.id;\n    if (fromRow !== \"\" && fromRow != null) {\n      const parsed = parseFormInt(fromRow);\n      if (parsed != null) return parsed;\n    }\n    return null;\n  }\n    let _editingAdhocId = null;\n    let _editingAdhocRow = null;\n    let _currentEditBenchmark = 0;\n    let _currentSubmitBenchmark = 0;\n    let _currentSubmitAssignedDos = 0;\n    \n    function calculateHoursEdit() {\n      const assignedDos =\n        parseFloat(document.getElementById(\"editAssignedDos\").value) || 0;\n      const benchmark = _currentEditBenchmark || 0;\n    \n      if (both(benchmark, benchmark > 0)) {\n        const hours = assignedDos \/ benchmark;\n        document.getElementById(\"editHours\").value =\n          hours % 1 === 0 ? hours : hours.toFixed(2);\n      } else {\n        document.getElementById(\"editHours\").value = 0;\n      }\n    }\n    \n    async function fetchEditAccountBenchmark(accountId) {\n      if (!accountId) {\n        _currentEditBenchmark = 0;\n        calculateHoursEdit();\n        return;\n      }\n      try {\n        const res = await fetch(ENDPOINTS.ACCOUNT_DETAIL, {\n          method: \"POST\",\n          headers: getHeaders(),\n          body: JSON.stringify({ id: parseInt(accountId, 10) }),\n        });\n        if (handleAuthError(res, { logoutOnUnauthorized: false })) return;\n        const result = await res.json();\n        if (result.code === 200) {\n          _currentEditBenchmark = result.data.operational_benchmark || 0;\n          calculateHoursEdit();\n        }\n      } catch (err) {\n        console.error(\"Account Detail Error:\", err);\n        _currentEditBenchmark = 0;\n      }\n    }\n    \n    \/\/ \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac SUBMIT ASSIGNMENT: HOURS + PENDING (PHP munvalueSubmitted parity) \u00e2\u201d\u20ac\n    \/\/   pending = assigned_dos - dos_complete (min 0)\n    \/\/   hours   = dos_complete \/ operational_benchmark\n    function calculateHoursSubmit() {\n      const dosCompletedEl = document.getElementById(\"submitDosCompleted\");\n      const hoursEl = document.getElementById(\"submitHours\");\n      const pendingEl = document.getElementById(\"submitPendingDos\");\n      if (!dosCompletedEl || !hoursEl || !pendingEl) return;\n    \n      const raw = String(dosCompletedEl.value ?? \"\").trim();\n      if (!raw) {\n        hoursEl.value = \"\";\n        pendingEl.value = \"\";\n        return;\n      }\n    \n      const dosCompleted = parseFloat(raw) || 0;\n      const assignedDos = _currentSubmitAssignedDos || 0;\n      pendingEl.value = Math.max(0, assignedDos - dosCompleted);\n    \n      const benchmark = _currentSubmitBenchmark || 0;\n      if (benchmark > 0) {\n        const hours = dosCompleted \/ benchmark;\n        hoursEl.value = hours % 1 === 0 ? String(hours) : hours.toFixed(2);\n      } else {\n        hoursEl.value = \"\";\n      }\n    }\n    \n    function resolveSubmitHours() {\n      calculateHoursSubmit();\n      const raw = String(\n        document.getElementById(\"submitHours\")?.value ?? \"\",\n      ).trim();\n      if (both(raw !== \"\", !isNaN(parseFloat(raw)))) {\n        return parseFloat(raw);\n      }\n      const dosCompleted =\n        parseFloat(document.getElementById(\"submitDosCompleted\")?.value) || 0;\n      const benchmark = _currentSubmitBenchmark || 0;\n      if (both(benchmark > 0, dosCompleted > 0)) {\n        return parseFloat((dosCompleted \/ benchmark).toFixed(4));\n      }\n      return 0;\n    }\n    \n    async function fetchSubmitAccountBenchmark(accountId) {\n      if (!accountId) {\n        _currentSubmitBenchmark = 0;\n        calculateHoursSubmit();\n        return;\n      }\n      try {\n        const res = await fetch(ENDPOINTS.ACCOUNT_DETAIL, {\n          method: \"POST\",\n          headers: getHeaders(),\n          body: JSON.stringify({ id: parseInt(accountId, 10) }),\n        });\n        if (handleAuthError(res, { logoutOnUnauthorized: false })) return;\n        const result = await res.json();\n        if (result.code === 200) {\n          _currentSubmitBenchmark = result.data.operational_benchmark || 0;\n          calculateHoursSubmit();\n        }\n      } catch (err) {\n        console.error(\"Account Detail Error:\", err);\n        _currentSubmitBenchmark = 0;\n      }\n    }\n    \n    async function openEditModal(type, id) {\n      \/\/ Assigned edit is gated by the global edit capability.\n      \/\/ Ad hoc edit is gated per-row (PHP parity) once the record is loaded below,\n      \/\/ so a user can always edit their OWN pending ad hoc.\n      if (both(type === \"assigned\", !CAN_EDIT)) {\n        alert(\"Access denied: you do not have permission to edit assignments.\");\n        return;\n      }\n    \n      const buildOptions = (data, valueKey, labelKey, selectedValue) =>\n        buildSelectOptions(data, valueKey, labelKey, selectedValue);\n  \n      if (type === \"assigned\") {\n        _editingAssignedId = id;\n    \n        \/\/ Try to fetch the record detail from the API\n        let row = null;\n        try {\n          const res = await fetchWorkAssignmentDetail(id);\n          if (res.status === 401) {\n            \/\/ Fall back to table row without logging out (list data already loaded).\n          } else if (handleAuthError(res)) {\n            return;\n          }\n          if (res.ok) {\n            const json = await res.json();\n            row = json?.data?.id ? json.data : json?.data?.data || json;\n          }\n        } catch (e) {\n          \/* ignore, try fallback *\/\n        }\n    \n        \/\/ Fallback: find in already-fetched table rows\n        if (!row || !row.id) {\n          row = lastFetchedRows.find((r) => String(r.id) === String(id)) || null;\n        }\n    \n        if (!row) {\n          alert(\"Could not load assignment data. Please try again.\");\n          return;\n        }\n  \n        row = normalizeAssignmentRow(row);\n        _editingAssignedRow = row;\n    \n        document.getElementById(\"assignedModalFields\").innerHTML = `\n                  <input type=\"hidden\" id=\"editFileId\" value=\"${row.file_id ?? \"\"}\">\n                    <input type=\"hidden\" id=\"editFileFieldEdit\" value=\"${row.file_id || \"\"}\">\n                    <div class=\"form-group\"><label class=\"required\">Assigned Date<\/label>\n                        <input type=\"date\" class=\"form-control\" id=\"editAssignedDate\" value=\"${formatDate(row.assigned_date)}\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Assigned To<\/label>\n                        <select class=\"form-control\" id=\"editAssignedTo\">\n                            <option value=\"\">Select User<\/option>\n                            ${buildGroupedUserSelectOptions(\n                              row.assigned_to,\n                              row.pesudo_name || row.assigned_to_name,\n                            )}\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Received On<\/label>\n                        <input type=\"date\" class=\"form-control\" id=\"editReceivedOn\" value=\"${formatDate(row.received_on)}\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">File Name<\/label>\n                        <input type=\"text\" class=\"form-control\" id=\"editFileName\" value=\"${safeText(row.file_name || \"\")}\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Insurance<\/label>\n                        <select class=\"form-control\" id=\"editInsurance\">\n                            <option value=\"\">Select Insurance<\/option>\n                            ${buildOptions(dropDownData.insurances, \"id\", \"name\", row.insurance_id)}\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Account<\/label>\n                        <select class=\"form-control\" id=\"editAccount\">\n                            <option value=\"\">Select Account<\/option>\n                            ${buildSelectOptions(\n                              dropDownData.accounts,\n                              \"id\",\n                              \"name\",\n                              row.account_id,\n                              row.account_name || row.account?.name,\n                            )}\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Client<\/label>\n                        <select class=\"form-control\" id=\"editClient\">\n                            <option value=\"\">Select Client<\/option>\n                            ${buildOptions(dropDownData.clients, \"id\", \"name\", row.client_id)}\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Category<\/label>\n                        <select class=\"form-control\" id=\"editCategory\">\n                            <option value=\"\">Select Category<\/option>\n                            ${buildOptions(dropDownData.categories, \"id\", \"category\", row.category_id)}\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Project<\/label>\n                        <select class=\"form-control\" id=\"editProject\">\n                            <option value=\"\">Select Project<\/option>\n                            ${buildOptions(dropDownData.projects, \"id\", \"name\", row.project_id)}\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Project Type<\/label>\n                        <select class=\"form-control\" id=\"editProjectType\">\n                            <option value=\"\">Select Project Type<\/option>\n                            ${buildOptions(dropDownData.projectTypes, \"id\", \"type\", row.project_type_id)}\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Entity<\/label>\n                        <select class=\"form-control\" id=\"editEntity\">\n                            <option value=\"\">Select Entity<\/option>\n                            ${buildOptions(dropDownData.entities, \"id\", \"entity\", row.entity_id)}\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Amount<\/label>\n                        <input type=\"number\" class=\"form-control\" id=\"editAmount\" value=\"${row.amount ?? 0}\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Pages<\/label>\n                        <input type=\"number\" class=\"form-control\" id=\"editPages\" value=\"${row.pages ?? 1}\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Dos Count<\/label>\n                        <input type=\"number\" class=\"form-control\" id=\"editDosCount\" value=\"${row.dos_count ?? 0}\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Assigned DOS<\/label>\n                        <input type=\"number\" class=\"form-control\" id=\"editAssignedDos\" value=\"${row.assigned_dos ?? 0}\" oninput=\"calculateHoursEdit()\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Hours<\/label>\n                        <input type=\"number\" step=\"0.01\" class=\"form-control\" id=\"editHours\" value=\"${row.hours ?? 0}\">\n                    <\/div>\n                `;\n        document.getElementById(\"modalAssigned\").style.display = \"flex\";\n    \n        \/\/ Initial benchmark fetch for the existing account\n        const initialAccountId =\n          row.account_id || document.getElementById(\"editAccount\").value;\n        if (initialAccountId) {\n          fetchEditAccountBenchmark(initialAccountId);\n        }\n    \n        \/\/ Add listener to account change in modal\n        document.getElementById(\"editAccount\").addEventListener(\"change\", (e) => {\n          fetchEditAccountBenchmark(e.target.value);\n        });\n      } else {\n        _editingAdhocId = id;\n    \n        \/\/ Try to fetch the ad hoc record detail from the API\n        let row = null;\n        try {\n          const res = await fetchAdHocDetail(id);\n          if (handleAuthError(res)) return;\n          if (res.ok) {\n            const json = await res.json();\n            row = json?.data?.id ? json.data : json?.data?.data || json;\n          }\n        } catch (e) {\n          \/* ignore, try fallback *\/\n        }\n    \n        \/\/ Fallback: find in already-fetched table rows\n        if (!row || !row.id) {\n          row = lastFetchedRows.find((r) => String(r.id) === String(id)) || null;\n        }\n    \n        if (!row) {\n          alert(\"Could not load ad hoc assignment data. Please try again.\");\n          return;\n        }\n    \n        \/\/ Per-row RBAC (PHP parity): own pending ad hoc is editable; otherwise admin only.\n        if (!canEditAdhocRow(row)) {\n          alert(\n            \"Access denied: you can only edit your own pending ad hoc assignment.\",\n          );\n          return;\n        }\n    \n        \/\/ Store row for use in updateAdHoc payload\n        _editingAdhocRow = row;\n    \n        \/\/ Parse time values: time_utilized \/ time_approved may be \"HH:MM\" or decimal hours\n        const parseHrsMins = (val) => {\n          if (both(!val, val !== 0)) return { hrs: 0, mins: 0 };\n          const str = String(val);\n          if (str.includes(\":\")) {\n            const [h, m] = str.split(\":\").map(Number);\n            return { hrs: isNaN(h) ? 0 : h, mins: isNaN(m) ? 0 : m };\n          }\n          const dec = parseFloat(str) || 0;\n          return { hrs: Math.floor(dec), mins: Math.round((dec % 1) * 60) };\n        };\n    \n        const utilized = parseHrsMins(\n          row.time_utilized ||\n            row.time_utilized_decimal ||\n            row.time_utilized_display,\n        );\n        const totalMins = utilized.hrs * 60 + utilized.mins;\n    \n        document.getElementById(\"adhocModalFields\").innerHTML = `\n                    <div class=\"form-group\"><label class=\"required\">Assigned date<\/label>\n                        <input type=\"date\" class=\"form-control\" id=\"editAdhocDate\" value=\"${formatDate(row.date)}\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Created By<\/label>\n                        <select class=\"form-control\" id=\"editAdhocCreatedBy\" disabled style=\"-webkit-appearance: none; -moz-appearance: none; appearance: none; background-color: #F1F3F4;\">\n                            <option value=\"${row.created_by || \"\"}\">${row.created_by_name || \"\"}<\/option>\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Client<\/label>\n                        <select class=\"form-control\" id=\"editAdhocClient\">\n                            <option value=\"\">Select Client<\/option>\n                            ${buildOptions(dropDownData.clients, \"id\", \"name\", row.client_id)}\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Project<\/label>\n                        <select class=\"form-control\" id=\"editAdhocProject\">\n                            <option value=\"\">Select Project<\/option>\n                            ${buildOptions(dropDownData.projects, \"id\", \"name\", row.project_id)}\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Hoc Work Type<\/label>\n                        <input type=\"text\" class=\"form-control\" id=\"editAdhocWorkType\" value=\"${row.ad_hoc_work_type || \"\"}\" placeholder=\"Hoc Work Type\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Description<\/label>\n                        <input type=\"text\" class=\"form-control\" id=\"editAdhocDescription\" value=\"${row.description || \"\"}\" placeholder=\"Enter Description\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Mins Utilized<\/label>\n                        <input type=\"number\" class=\"form-control\" id=\"editAdhocMinsUtilized\" value=\"${totalMins}\" placeholder=\"Enter Mins\" oninput=\"calcAdhocEditHrs()\">\n                    <\/div>\n                    <div class=\"form-group\"><label class=\"required\">Hrs Utilized<\/label>\n                        <input type=\"number\" class=\"form-control\" id=\"editAdhocHrsUtilized\" value=\"${utilized.hrs}\" placeholder=\"Enter Hrs\" disabled style=\"background-color: #F1F3F4;\">\n                    <\/div>\n                    <div class=\"form-group\"><label>Comment\/Remarks<\/label>\n                        <input type=\"text\" class=\"form-control\" id=\"editAdhocComments\" value=\"${row.comments || \"\"}\" placeholder=\"Write Something...\">\n                    <\/div>\n                `;\n        document.getElementById(\"modalAdhoc\").style.display = \"flex\";\n      }\n    }\n    \n    function closeModals() {\n      document.getElementById(\"modalAssigned\").style.display = \"none\";\n      document.getElementById(\"modalAdhoc\").style.display = \"none\";\n      document.getElementById(\"modalSubmit\").style.display = \"none\";\n      document.getElementById(\"modalAddAdHoc\").style.display = \"none\";\n      const approvalEl = document.getElementById(\"modalAdhocApproval\");\n      if (approvalEl) approvalEl.style.display = \"none\";\n    }\n    \n    async function updateAssignment() {\n      \/\/ Function-level RBAC guard \u00e2\u20ac\u201d backend must also enforce this on \/work_assignment\/update.\n      if (!CAN_EDIT) {\n        alert(\"Access denied: you do not have permission to edit assignments.\");\n        return;\n      }\n      if (!_editingAssignedId) {\n        alert(\"No assignment selected for update.\");\n        return;\n      }\n      const fileId = resolveEditFileId();\n      if (fileId == null) {\n        alert(\"File ID is missing for this assignment. Please reload the page and try again.\");\n        return;\n      }\n      const payload = {\n        work_assignment_id: _editingAssignedId,\n        file_id: fileId,\n        file_field_edit: String(\n          document.getElementById(\"editFileName\")?.value ||\n          document.getElementById(\"editFileFieldEdit\")?.value ||\n            document.getElementById(\"editFileId\")?.value ||\n            \"\",\n        ),\n        assigned_date: document.getElementById(\"editAssignedDate\")?.value || \"\",\n        assigned_to:\n          parseInt(document.getElementById(\"editAssignedTo\")?.value, 10) || null,\n        received_on: document.getElementById(\"editReceivedOn\")?.value || \"\",\n        file_name: document.getElementById(\"editFileName\")?.value || \"\",\n        insurance_id:\n          parseInt(document.getElementById(\"editInsurance\")?.value, 10) || null,\n        account_id:\n          parseInt(document.getElementById(\"editAccount\")?.value, 10) || null,\n        client_id:\n          parseInt(document.getElementById(\"editClient\")?.value, 10) || null,\n        category_id:\n          parseInt(document.getElementById(\"editCategory\")?.value, 10) || null,\n        project_id:\n          parseInt(document.getElementById(\"editProject\")?.value, 10) || null,\n        project_type_id:\n          parseInt(document.getElementById(\"editProjectType\")?.value, 10) || null,\n        entity_id:\n          parseInt(document.getElementById(\"editEntity\")?.value, 10) || null,\n        amount: parseFloat(document.getElementById(\"editAmount\")?.value) || 0,\n        pages: parseInt(document.getElementById(\"editPages\")?.value, 10) || 0,\n        dos_count:\n          parseInt(document.getElementById(\"editDosCount\")?.value, 10) || 0,\n        assigned_dos:\n          parseInt(document.getElementById(\"editAssignedDos\")?.value, 10) || 0,\n        hours: parseFloat(document.getElementById(\"editHours\")?.value) || 0,\n      };\n    \n      try {\n        const res = await fetch(ENDPOINTS.UPDATE_ASSIGNMENT, {\n          method: \"POST\",\n          headers: getHeaders(),\n          body: JSON.stringify(payload),\n        });\n        if (handleAuthError(res)) return;\n        let result;\n        try {\n          result = await res.json();\n        } catch (parseErr) {\n          alert(\"Update failed: invalid server response.\");\n          return;\n        }\n        if (res.status === 403) {\n          alert(\n            result.message ||\n              result.messages?.[0] ||\n              \"Access denied: you do not have permission to edit assignments.\",\n          );\n          return;\n        }\n        if (both(res.ok, result.code === 200 || result.status === \"success\")) {\n          alert(\"Assignment updated successfully.\");\n          closeModals();\n          fetchTableData(currentPage);\n        } else {\n          const errMsg = result.errors\n            ?.map((e) => e.msg || e.message)\n            .filter(Boolean)\n            .join(\"\\n\");\n          alert(\n            errMsg ||\n              result.message ||\n              result.messages?.[0] ||\n              \"Update failed. Please try again.\",\n          );\n        }\n      } catch (err) {\n        console.error(\"Update Assignment error:\", err);\n        alert(\"Network error. Please try again.\");\n      }\n    }\n    \n    async function updateAdHoc() {\n      \/\/ Per-row RBAC (PHP parity): own pending ad hoc is editable; otherwise admin only.\n      \/\/ Backend must also enforce this on \/ad_hoc_assignment\/update.\n      if (!_editingAdhocRow || !canEditAdhocRow(_editingAdhocRow)) {\n        alert(\n          \"Access denied: you can only edit your own pending ad hoc assignment.\",\n        );\n        return;\n      }\n      if (!_editingAdhocId) {\n        alert(\"No ad hoc assignment selected for update.\");\n        return;\n      }\n    \n      const date = document.getElementById(\"editAdhocDate\")?.value || \"\";\n      const clientId =\n        parseInt(document.getElementById(\"editAdhocClient\")?.value, 10) || null;\n      const projectId =\n        parseInt(document.getElementById(\"editAdhocProject\")?.value, 10) || null;\n      const workType = document.getElementById(\"editAdhocWorkType\")?.value || \"\";\n      const description =\n        document.getElementById(\"editAdhocDescription\")?.value || \"\";\n      const comments = document.getElementById(\"editAdhocComments\")?.value || \"\";\n    \n      const totalMins =\n        parseInt(document.getElementById(\"editAdhocMinsUtilized\")?.value, 10) || 0;\n      const hrsUtilized = Math.floor(totalMins \/ 60);\n      const minsUtilized = totalMins % 60;\n    \n      const payload = {\n        id: _editingAdhocId,\n        date: date,\n        client_id: clientId,\n        project_id: projectId,\n        ad_hoc_work_type: workType,\n        description: description,\n        minute_utilized: minsUtilized,\n        hour_utilized: hrsUtilized,\n        comments: comments,\n      };\n    \n      try {\n        const res = await fetch(ENDPOINTS.UPDATE_ADHOC, {\n          method: \"POST\",\n          headers: getHeaders(),\n          body: JSON.stringify(payload),\n        });\n        if (handleAuthError(res)) return;\n        const result = await res.json();\n        if (both(res.ok, result.code === 200 || result.status === \"success\")) {\n          alert(\"Ad Hoc assignment updated successfully.\");\n          closeModals();\n          fetchAdhocTableData(currentPage);\n        } else {\n          alert(\n            result.message ||\n              result.messages?.[0] ||\n              \"Update failed. Please try again.\",\n          );\n        }\n      } catch (err) {\n        console.error(\"Update AdHoc error:\", err);\n        alert(\"Network error. Please try again.\");\n      }\n    }\n    \n    let _editingAdhocApprovalId = null;\n    let _editingAdhocApprovalRow = null;\n    \n    async function openApprovalModal(id) {\n      \/\/ Function-level RBAC guard: Only Managers and Admins and Team Leads can approve\n      if (!CAN_APPROVE) {\n        alert(\n          \"Access denied: approving\/reverting ad hoc assignments requires a Manager or Team Lead role.\",\n        );\n        return;\n      }\n    \n      \/\/ Try to fetch the ad hoc record detail from the API\n      let row = null;\n      try {\n        const res = await fetchAdHocDetail(id);\n        if (handleAuthError(res)) return;\n        if (res.ok) {\n          const json = await res.json();\n          row = json?.data?.id ? json.data : json?.data?.data || json;\n        }\n      } catch (e) {\n        \/* ignore, try fallback *\/\n      }\n    \n      \/\/ Fallback: find in already-fetched table rows\n      if (!row || !row.id) {\n        row = lastFetchedRows.find((r) => String(r.id) === String(id)) || null;\n      }\n    \n      if (!row) {\n        alert(\"Could not load ad hoc assignment data. Please try again.\");\n        return;\n      }\n    \n      _editingAdhocApprovalId = id;\n      _editingAdhocApprovalRow = row;\n    \n      \/\/ Parse time values\n      const parseHrsMins = (val) => {\n        if (both(!val, val !== 0)) return { hrs: 0, mins: 0 };\n        const str = String(val);\n        if (str.includes(\":\")) {\n          const [h, m] = str.split(\":\").map(Number);\n          return { hrs: isNaN(h) ? 0 : h, mins: isNaN(m) ? 0 : m };\n        }\n        const dec = parseFloat(str) || 0;\n        return { hrs: Math.floor(dec), mins: Math.round((dec % 1) * 60) };\n      };\n    \n      const utilized = parseHrsMins(\n        row.time_utilized || row.time_utilized_decimal || row.time_utilized_display,\n      );\n      _approvalUtilized = { hrs: utilized.hrs, mins: utilized.mins };\n    \n      \/\/ Let's format the date to YYYY-MM-DD for the input fields\n      const today = new Date().toISOString().split(\"T\")[0];\n    \n      document.getElementById(\"adhocApprovalFields\").innerHTML = `\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Assigned date <span style=\"color: red;\">*<\/span><\/label>\n                <input type=\"date\" id=\"approveAssignedDate\" class=\"form-control\" value=\"${formatDate(row.date)}\" style=\"background-color: white; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #212529; outline: none;\">\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Client <span style=\"color: red;\">*<\/span><\/label>\n                <select class=\"form-control\" disabled style=\"background-color: #F1F3F4; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #555; -webkit-appearance: none;\">\n                    <option value=\"${row.client_id || \"\"}\">${row.client_name || \"\"}<\/option>\n                <\/select>\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Project <span style=\"color: red;\">*<\/span><\/label>\n                <select class=\"form-control\" disabled style=\"background-color: #F1F3F4; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #555; -webkit-appearance: none;\">\n                    <option value=\"${row.project_id || \"\"}\">${row.project_name || \"\"}<\/option>\n                <\/select>\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Hoc Work Type <span style=\"color: red;\">*<\/span><\/label>\n                <input type=\"text\" class=\"form-control\" value=\"${row.ad_hoc_work_type || \"\"}\" disabled style=\"background-color: #F1F3F4; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #555;\">\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Description <span style=\"color: red;\">*<\/span><\/label>\n                <input type=\"text\" class=\"form-control\" value=\"${row.description || \"\"}\" disabled style=\"background-color: #F1F3F4; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #555;\">\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Mins Utilized <span style=\"color: red;\">*<\/span><\/label>\n                <input type=\"number\" class=\"form-control\" value=\"${utilized.mins}\" disabled style=\"background-color: #F1F3F4; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #555;\">\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Hrs Utilized <span style=\"color: red;\">*<\/span><\/label>\n                <input type=\"number\" class=\"form-control\" value=\"${utilized.hrs}\" disabled style=\"background-color: #F1F3F4; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #555;\">\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Status <span style=\"color: red;\">*<\/span><\/label>\n                <select id=\"approveStatus\" class=\"form-control\" onchange=\"onApproveStatusChange()\" style=\"background-color: white; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #212529; outline: none;\">\n                    <option value=\"1\" selected>Approved<\/option>\n                    <option value=\"0\">Not Approved<\/option>\n                <\/select>\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Approved on <span style=\"color: red;\">*<\/span><\/label>\n                <input type=\"date\" id=\"approveDate\" class=\"form-control\" value=\"${today}\" style=\"background-color: white; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #212529; outline: none;\">\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Mins Approved <span style=\"color: red;\">*<\/span><\/label>\n                <input type=\"number\" id=\"approveMins\" class=\"form-control\" value=\"${utilized.mins}\" onblur=\"recalcApproveHrs()\" style=\"background-color: white; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #212529; outline: none;\">\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Hrs Approved <span style=\"color: red;\">*<\/span><\/label>\n                <input type=\"number\" id=\"approveHrs\" class=\"form-control\" value=\"${utilized.hrs}\" disabled style=\"background-color: #F1F3F4; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #555;\">\n            <\/div>\n            <div class=\"form-group\" style=\"display: flex; flex-direction: column; gap: 5px;\">\n                <label style=\"font-weight: 500; font-size: 13px; color: #212529;\">Comment<\/label>\n                <input type=\"text\" id=\"approveComment\" class=\"form-control\" value=\"${row.comments || \"Approved\"}\" style=\"background-color: white; border: 1px solid #D1D5DB; border-radius: 6px; padding: 8px 12px; font-size: 14px; color: #212529; outline: none;\">\n            <\/div>\n        `;\n    \n      document.getElementById(\"modalAdhocApproval\").style.display = \"flex\";\n    }\n    \n    async function submitAdhocApproval() {\n      if (!_editingAdhocApprovalId) {\n        alert(\"No ad hoc assignment selected for approval.\");\n        return;\n      }\n    \n      \/\/ PHP parity (AdHocAssignmentService::approve):\n      \/\/   $status      = request status  (1 = Approved, 0 = Not Approved)\n      \/\/   is_approved  = ($status == 1) ? 1 : 2\n      \/\/   status       = $status  (stored as numeric 1\/0)\n      const status = parseInt(document.getElementById(\"approveStatus\")?.value, 10);\n      const isApproved = status === 1 ? 1 : 2;\n      const approvedOn = document.getElementById(\"approveDate\")?.value || \"\";\n      const minsApproved =\n        parseInt(document.getElementById(\"approveMins\")?.value, 10) || 0;\n      const hrsApproved =\n        parseInt(document.getElementById(\"approveHrs\")?.value, 10) || 0;\n      const comments = document.getElementById(\"approveComment\")?.value || \"\";\n      const assignedDate =\n        document.getElementById(\"approveAssignedDate\")?.value || \"\";\n    \n      const payload = {\n        id: _editingAdhocApprovalId,\n        date: assignedDate,\n        client_id: _editingAdhocApprovalRow?.client_id || null,\n        project_id: _editingAdhocApprovalRow?.project_id || null,\n        ad_hoc_work_type: _editingAdhocApprovalRow?.ad_hoc_work_type || \"\",\n        description: _editingAdhocApprovalRow?.description || \"\",\n        minute_utilized:\n          _editingAdhocApprovalRow?.minute_utilized ||\n          _editingAdhocApprovalRow?.time_utilized_decimal * 60 ||\n          0,\n        hour_utilized:\n          _editingAdhocApprovalRow?.hour_utilized ||\n          _editingAdhocApprovalRow?.time_utilized_decimal ||\n          0,\n        is_approved: isApproved,\n        approved_by: CURRENT_USER_DATA.id || 1,\n        minute_approved: minsApproved,\n        hour_approved: hrsApproved,\n        comments: comments,\n        approved_at: approvedOn,\n        status: status,\n        updated_by: CURRENT_USER_DATA.id || 1,\n      };\n    \n      try {\n        const res = await fetch(ENDPOINTS.UPDATE_ADHOC, {\n          method: \"POST\",\n          headers: getHeaders(),\n          body: JSON.stringify(payload),\n        });\n        if (handleAuthError(res)) return;\n        const result = await res.json();\n        if (both(res.ok, result.code === 200 || result.status === \"success\")) {\n          alert(\"Ad Hoc assignment approved successfully.\");\n          closeModals();\n          fetchAdhocTableData(currentPage);\n        } else {\n          alert(\n            result.message ||\n              result.messages?.[0] ||\n              \"Approval submission failed. Please try again.\",\n          );\n        }\n      } catch (err) {\n        console.error(\"Submit AdHoc Approval error:\", err);\n        alert(\"Network error. Please try again.\");\n      }\n    }\n    \n    \/\/ \u00e2\u201d\u20ac\u00e2\u201d\u20ac CUSTOM DATE PICKER \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\n    \/\/ Two independent picker instances: 'assigned' and 'adhoc'\n    const dpState = {\n      assigned: {\n        viewYear: null,\n        viewMonth: null,\n        startDate: null,\n        endDate: null,\n        hoverDate: null,\n        activePreset: null,\n        selectedDate: null,\n      },\n      adhoc: {\n        viewYear: null,\n        viewMonth: null,\n        startDate: null,\n        endDate: null,\n        hoverDate: null,\n        activePreset: null,\n        selectedDate: null,\n      },\n    };\n    \n    const DP_IDS = {\n      assigned: {\n        wrapper: \"dpWrapperAssigned\",\n        display: \"filterDate\",\n        dropdown: \"dpDropdownAssigned\",\n        backdrop: \"dpBackdropAssigned\",\n        title: \"dpCalTitleAssigned\",\n        title2: \"dpCalTitleAssigned2\",\n        days: \"dpDaysAssigned\",\n        days2: \"dpDaysAssigned2\",\n      },\n      adhoc: {\n        wrapper: \"dpWrapperAdhoc\",\n        display: \"filterAdhocDate\",\n        dropdown: \"dpDropdownAdhoc\",\n        backdrop: \"dpBackdropAdhoc\",\n        title: \"dpCalTitleAdhoc\",\n        title2: \"dpCalTitleAdhoc2\",\n        days: \"dpDaysAdhoc\",\n        days2: \"dpDaysAdhoc2\",\n      },\n    };\n    const DP_MONTHS = [\n      \"January\",\n      \"February\",\n      \"March\",\n      \"April\",\n      \"May\",\n      \"June\",\n      \"July\",\n      \"August\",\n      \"September\",\n      \"October\",\n      \"November\",\n      \"December\",\n    ];\n    \n    function dpToday() {\n      const d = new Date();\n      d.setHours(0, 0, 0, 0);\n      return d;\n    }\n    \n    function dpFmt(d) {\n      if (!d) return \"\";\n      const dd = String(d.getDate()).padStart(2, \"0\");\n      const mm = String(d.getMonth() + 1).padStart(2, \"0\");\n      return `${dd}-${mm}-${d.getFullYear()}`;\n    }\n    \n    function dpFmtISO(d) {\n      if (!d) return \"\";\n      const dd = String(d.getDate()).padStart(2, \"0\");\n      const mm = String(d.getMonth() + 1).padStart(2, \"0\");\n      return `${d.getFullYear()}-${mm}-${dd}`;\n    }\n    \n    function dpSameDay(a, b) {\n      if (!a) return false;\n      if (!b) return false;\n      if (a.getFullYear() !== b.getFullYear()) return false;\n      if (a.getMonth() !== b.getMonth()) return false;\n      return a.getDate() === b.getDate();\n    }\n    \n    function dpRenderCalendar(inst) {\n      const s = dpState[inst];\n      const ids = DP_IDS[inst];\n    \n      const titleEl = document.getElementById(ids.title);\n      const title2El = document.getElementById(ids.title2);\n      const daysEl = document.getElementById(ids.days);\n      const days2El = document.getElementById(ids.days2);\n    \n      if (!titleEl || !title2El || !daysEl || !days2El) return;\n    \n      \/\/ Second month = first month + 1\n      let y2 = s.viewYear,\n        m2 = s.viewMonth + 1;\n      if (m2 > 11) {\n        m2 = 0;\n        y2++;\n      }\n    \n      titleEl.textContent = `${DP_MONTHS[s.viewMonth]} ${s.viewYear}`;\n      title2El.textContent = `${DP_MONTHS[m2]} ${y2}`;\n    \n      daysEl.innerHTML = dpBuildDays(s.viewYear, s.viewMonth, s, inst);\n      days2El.innerHTML = dpBuildDays(y2, m2, s, inst);\n    }\n    \n    function dpBuildDays(year, month, s, inst) {\n      const today = dpToday();\n      const startDay = new Date(year, month, 1).getDay();\n      const daysInMonth = new Date(year, month + 1, 0).getDate();\n      let html = \"\";\n      for (let i = 0; i < startDay; i++)\n        html += `<div class=\"dp-day other-month\"><\/div>`;\n      for (let d = 1; d <= daysInMonth; d++) {\n        const cur = new Date(year, month, d);\n        let cls = \"dp-day\";\n        if (dpSameDay(cur, today)) cls += \" today\";\n        const dayOfWeek = cur.getDay();\n        if (s.startDate) {\n          if (s.endDate) {\n            if (dpSameDay(cur, s.startDate)) {\n              cls += \" selected selected-start\";\n            } else if (dpSameDay(cur, s.endDate)) {\n              cls += \" selected selected-end\";\n            } else if (cur > s.startDate) {\n              if (cur < s.endDate) {\n                cls += \" in-range\";\n                if (dayOfWeek === 0) cls += \" row-start\";\n                if (dayOfWeek === 6) cls += \" row-end\";\n              }\n            }\n          } else if (dpSameDay(cur, s.startDate)) {\n            cls += \" selected selected-start selected-end\";\n          } else if (s.hoverDate) {\n            let rS = s.startDate,\n              rE = s.hoverDate;\n            if (rE < rS) {\n              const t = rS;\n              rS = rE;\n              rE = t;\n            }\n            if (dpSameDay(cur, s.hoverDate)) {\n              cls +=\n                s.hoverDate < s.startDate\n                  ? \" hover-start hover-range\"\n                  : \" hover-end hover-range\";\n            } else if (cur > rS) {\n              if (cur < rE) {\n                cls += \" hover-range\";\n                if (dayOfWeek === 0) cls += \" row-start\";\n                if (dayOfWeek === 6) cls += \" row-end\";\n              }\n            }\n          }\n        }\n        html += `<div class=\"${cls}\" onclick=\"dpPickDay(event,${year},${month},${d},'${inst}')\" onmouseover=\"dpHoverDay('${inst}',${year},${month},${d})\">${d}<\/div>`;\n      }\n      return html;\n    }\n    \n    function dpPickDay(e, y, m, d, inst) {\n      e.stopPropagation();\n      const s = dpState[inst];\n      const chosen = new Date(y, m, d);\n    \n      if (!s.startDate) {\n        s.startDate = chosen;\n        s.endDate = null;\n      } else if (s.endDate) {\n        s.startDate = chosen;\n        s.endDate = null;\n      } else {\n        if (chosen < s.startDate) {\n          s.endDate = s.startDate;\n          s.startDate = chosen;\n        } else {\n          s.endDate = chosen;\n        }\n      }\n    \n      s.hoverDate = null;\n      s.activePreset = null;\n      const dropId = inst === \"assigned\" ? \"dpDropdownAssigned\" : \"dpDropdownAdhoc\";\n      document\n        .querySelectorAll(`#${dropId} .dp-preset-item`)\n        .forEach((el) => el.classList.remove(\"active\"));\n      dpRenderCalendar(inst);\n      dpUpdateFooterRange(inst);\n    }\n    \n    function dpHoverDay(inst, y, m, d) {\n      const s = dpState[inst];\n      if (s.startDate) {\n        if (!s.endDate) {\n          const h = new Date(y, m, d);\n          if (!dpSameDay(h, s.hoverDate)) {\n            s.hoverDate = h;\n            dpRenderCalendar(inst);\n          }\n        }\n      }\n    }\n    \n    function dpUpdateFooterRange(inst) {\n      const s = dpState[inst];\n      const el = document.getElementById(\n        inst === \"assigned\" ? \"dpRangeDisplayAssigned\" : \"dpRangeDisplayAdhoc\",\n      );\n      if (!el) return;\n      if (s.startDate) {\n        if (s.endDate) {\n          el.textContent = `${dpFmtISO(s.startDate)} to ${dpFmtISO(s.endDate)}`;\n        } else {\n          el.textContent = `${dpFmtISO(s.startDate)} to Select end date`;\n        }\n      } else {\n        el.textContent = \"Select Date Range\";\n      }\n    }\n    \n    function dpChangeMonth(e, dir, inst) {\n      e.stopPropagation();\n      const s = dpState[inst];\n      s.viewMonth += dir;\n      if (s.viewMonth > 11) {\n        s.viewMonth = 0;\n        s.viewYear++;\n      }\n      if (s.viewMonth < 0) {\n        s.viewMonth = 11;\n        s.viewYear--;\n      }\n      dpRenderCalendar(inst);\n    }\n    \n    function selectPreset(e, preset, inst) {\n      e.stopPropagation();\n      const s = dpState[inst];\n      const today = dpToday();\n      s.activePreset = preset;\n      const dropId = DP_IDS[inst].dropdown;\n      document\n        .querySelectorAll(`#${dropId} .dp-preset-item`)\n        .forEach((el) =>\n          el.classList.toggle(\"active\", el.dataset.preset === preset),\n        );\n    \n      switch (preset) {\n        case \"today\":\n          s.startDate = new Date(today);\n          s.endDate = new Date(today);\n          break;\n        case \"yesterday\": {\n          const y = new Date(today);\n          y.setDate(y.getDate() - 1);\n          s.startDate = y;\n          s.endDate = y;\n          break;\n        }\n        case \"last7\": {\n          const y = new Date(today);\n          y.setDate(y.getDate() - 6);\n          s.startDate = y;\n          s.endDate = new Date(today);\n          break;\n        }\n        case \"last30\": {\n          const y = new Date(today);\n          y.setDate(y.getDate() - 29);\n          s.startDate = y;\n          s.endDate = new Date(today);\n          break;\n        }\n        case \"thisMonth\":\n          s.startDate = new Date(today.getFullYear(), today.getMonth(), 1);\n          s.endDate = new Date(today);\n          break;\n        case \"lastMonth\":\n          s.startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1);\n          s.endDate = new Date(today.getFullYear(), today.getMonth(), 0);\n          break;\n      }\n      s.selectedDate = s.startDate;\n      s.viewYear = s.startDate.getFullYear();\n      s.viewMonth = s.startDate.getMonth();\n      dpRenderCalendar(inst);\n      dpUpdateFooterRange(inst);\n      \/\/ Auto-apply preset\n      dpApply(e, inst);\n    }\n    \n    function dpApply(e, inst) {\n      if (e) e.stopPropagation();\n      const s = dpState[inst];\n      const display = document.getElementById(DP_IDS[inst].display);\n      if (s.startDate) {\n        if (s.endDate) {\n          if (dpSameDay(s.startDate, s.endDate)) {\n            display.value = dpFmtISO(s.startDate);\n          } else {\n            display.value = `${dpFmtISO(s.startDate)} to ${dpFmtISO(s.endDate)}`;\n          }\n        } else {\n          display.value = dpFmtISO(s.startDate);\n        }\n      } else {\n        display.value = \"\";\n      }\n      closeDatePicker(inst);\n      \/\/ Auto-filter\n      handleActionClick(\"Filter\");\n    }\n    \n    function dpClear(e, inst) {\n      e.stopPropagation();\n      const s = dpState[inst];\n      s.startDate = null;\n      s.endDate = null;\n      s.hoverDate = null;\n      s.selectedDate = null;\n      s.activePreset = null;\n      document.getElementById(DP_IDS[inst].display).value = \"\";\n      const dropId = DP_IDS[inst].dropdown;\n      document\n        .querySelectorAll(`#${dropId} .dp-preset-item`)\n        .forEach((el) => el.classList.remove(\"active\"));\n      dpRenderCalendar(inst);\n      dpUpdateFooterRange(inst);\n      closeDatePicker(inst);\n    }\n    \n    function toggleDatePicker(e, inst) {\n      e.stopPropagation();\n      const ids = DP_IDS[inst];\n      const dd = document.getElementById(ids.dropdown);\n      if (dd.classList.contains(\"open\")) {\n        closeDatePicker(inst);\n      } else {\n        const s = dpState[inst];\n        const ref = s.selectedDate || dpToday();\n        s.viewYear = ref.getFullYear();\n        s.viewMonth = ref.getMonth();\n        if (!s.selectedDate) {\n          s.activePreset = \"today\";\n          document\n            .querySelectorAll(`#${ids.dropdown} .dp-preset-item`)\n            .forEach((el) =>\n              el.classList.toggle(\"active\", el.dataset.preset === \"today\"),\n            );\n        }\n        dpRenderCalendar(inst);\n        dpUpdateFooterRange(inst);\n        dd.classList.add(\"open\");\n        document.getElementById(ids.backdrop).classList.add(\"show\");\n        \/\/ Align to the right edge of the input (opening to the left)\n        \/\/ to ensure it stays on screen and matches \"not on right side\" requirement.\n        dd.classList.add(\"align-right\");\n      }\n    }\n    \n    function closeDatePicker(inst) {\n      const ids = DP_IDS[inst];\n      document.getElementById(ids.dropdown).classList.remove(\"open\");\n      document.getElementById(ids.backdrop).classList.remove(\"show\");\n    }\n    \n    \/\/ Close pickers when clicking outside\n    document.addEventListener(\"click\", function (e) {\n      [\"assigned\", \"adhoc\"].forEach((inst) => {\n        const wrapId = inst === \"assigned\" ? \"dpWrapperAssigned\" : \"dpWrapperAdhoc\";\n        const wrapEl = document.getElementById(wrapId);\n        if (both(wrapEl, !wrapEl.contains(e.target))) {\n          closeDatePicker(inst);\n        }\n      });\n    });\n    \n    let _submittingAssignedId = null;\n    \n    async function openSubmitModal(id) {\n      _submittingAssignedId = id;\n    \n      const buildOptions = (data, valueKey, labelKey, selectedValue) =>\n        data\n          .map(\n            (item) =>\n              `<option value=\"${item[valueKey] ?? \"\"}\" ${String(item[valueKey]) === String(selectedValue) ? \"selected\" : \"\"}>${item[labelKey] ?? \"\"}<\/option>`,\n          )\n          .join(\"\");\n    \n      let row = null;\n      try {\n        const res = await fetchWorkAssignmentDetail(id);\n        if (handleAuthError(res)) return;\n        if (res.ok) {\n          const json = await res.json();\n          row = json?.data?.id ? json.data : json?.data?.data || json;\n        }\n      } catch (e) {\n        console.warn(\"POST detail failed, trying fallback\");\n      }\n    \n      if (!row || !row.id) {\n        row = lastFetchedRows.find((r) => String(r.id) === String(id)) || null;\n      }\n    \n      if (!row) {\n        alert(\"Could not load assignment data. Please try again.\");\n        return;\n      }\n    \n      document.getElementById(\"submitModalFields\").innerHTML = `\n            <div class=\"form-group\"><label class=\"required\">Assigned date<\/label>\n                <input type=\"text\" class=\"form-control\" value=\"${getOnlyDate(row.assigned_date)}\" disabled>\n            <\/div>\n            <div class=\"form-group\"><label class=\"required\">Assigned to<\/label>\n                <select class=\"form-control\" disabled>\n                    <option value=\"\">Select User<\/option>\n                    ${buildGroupedUserSelectOptions(\n                      row.assigned_to || row.assigned_to_id,\n                      row.pesudo_name || row.assigned_to_name,\n                    )}\n                <\/select>\n            <\/div>\n            <div class=\"form-group\"><label class=\"required\">Received on<\/label>\n                <input type=\"text\" class=\"form-control\" value=\"${getOnlyDate(row.received_on)}\" disabled>\n            <\/div>\n        \n            <div class=\"form-group\"><label class=\"required\">File Name<\/label>\n                <input type=\"text\" class=\"form-control\" value=\"${row.file_name || \"\"}\" disabled>\n            <\/div>\n            <div class=\"form-group\"><label class=\"required\">Insurance<\/label>\n                <select class=\"form-control\" disabled>\n                    <option value=\"\">Select Insurance<\/option>\n                    ${buildOptions(dropDownData.insurances, \"id\", \"name\", row.insurance_id)}\n                <\/select>\n            <\/div>\n            <div class=\"form-group\"><label class=\"required\">Pages<\/label>\n                <input type=\"number\" class=\"form-control\" value=\"${row.pages ?? 0}\" disabled>\n            <\/div>\n        \n            <div class=\"form-group\"><label class=\"required\">Project<\/label>\n                <select class=\"form-control\" disabled>\n                    <option value=\"\">Select Project<\/option>\n                    ${buildOptions(dropDownData.projects, \"id\", \"name\", row.project_id)}\n                <\/select>\n            <\/div>\n            <div class=\"form-group\"><label class=\"required\">Project Type<\/label>\n                <select class=\"form-control\" disabled>\n                    <option value=\"\">Select Project Type<\/option>\n                    ${buildOptions(dropDownData.projectTypes, \"id\", \"type\", row.project_type_id)}\n                <\/select>\n            <\/div>\n            <div class=\"form-group\"><label class=\"required\">Entity<\/label>\n                <select class=\"form-control\" disabled>\n                    <option value=\"\">Select Entity<\/option>\n                    ${buildOptions(dropDownData.entities, \"id\", \"entity\", row.entity_id)}\n                <\/select>\n            <\/div>\n        \n            <div class=\"form-group\"><label class=\"required\">Dos Count<\/label>\n                <input type=\"number\" class=\"form-control\" value=\"${row.dos_count ?? 0}\" disabled>\n            <\/div>\n            <div class=\"form-group\"><label class=\"required\">Amount<\/label>\n                <input type=\"number\" class=\"form-control\" value=\"${row.amount ?? 0}\" disabled>\n            <\/div>\n            <div class=\"form-group\"><label class=\"required\">Assigned DOS<\/label>\n                <input type=\"number\" class=\"form-control\" id=\"submitAssignedDos\" value=\"${row.assigned_dos ?? 0}\" disabled>\n            <\/div>\n    \n            <div class=\"form-group\"><label class=\"required\">DOS Completed<\/label>\n                <input type=\"number\" class=\"form-control\" id=\"submitDosCompleted\" placeholder=\"Enter DOS Completed\" min=\"0\" value=\"\" oninput=\"calculateHoursSubmit()\">\n            <\/div>\n            <div class=\"form-group\"><label class=\"required\">Pending DOS<\/label>\n                <input type=\"text\" class=\"form-control\" id=\"submitPendingDos\" placeholder=\"Auto calculated\" value=\"\" readonly style=\"pointer-events:none;background:#f9f9f9;\">\n            <\/div>\n            <div class=\"form-group\"><label class=\"required\">Hours<\/label>\n                <input type=\"text\" class=\"form-control\" id=\"submitHours\" placeholder=\"Auto calculated\" value=\"\" readonly style=\"pointer-events:none;background:#f9f9f9;\">\n            <\/div>\n        \n            <div class=\"form-group\"><label>Remarks<\/label>\n                <input type=\"text\" class=\"form-control\" id=\"submitRemarks\" placeholder=\"Enter Remarks\" value=\"${row.remarks ?? \"\"}\">\n            <\/div>\n        `;\n    \n      document.getElementById(\"modalSubmit\").style.display = \"flex\";\n    \n      \/\/ PHP parity: benchmark + assigned DOS drive auto hours\/pending on dos_complete input.\n      _currentSubmitBenchmark = 0;\n      _currentSubmitAssignedDos = parseFloat(row.assigned_dos) || 0;\n      fetchSubmitAccountBenchmark(row.account_id);\n    }\n    \n    async function submitAssignmentLog() {\n      if (!_submittingAssignedId) return;\n    \n      const payload = {\n        work_assignment_id: _submittingAssignedId,\n        dos_complete: document.getElementById(\"submitDosCompleted\")?.value || 0,\n        pending_dos: document.getElementById(\"submitPendingDos\")?.value || 0,\n        hours: resolveSubmitHours(),\n        remarks: document.getElementById(\"submitRemarks\")?.value || \"\",\n      };\n    \n      try {\n        const res = await fetch(ENDPOINTS.SUBMIT_LOG, {\n          method: \"POST\",\n          headers: getHeaders(),\n          body: JSON.stringify(payload),\n        });\n        if (handleAuthError(res)) return;\n        const result = await res.json();\n    \n        if (\n          both(\n            res.ok,\n            result.code === 200 || result.status === \"success\" || result.message,\n          )\n        ) {\n          lastFetchedRows = lastFetchedRows.filter(\n            (r) => String(r.id) !== String(_submittingAssignedId),\n          );\n          _submittingAssignedId = null;\n          closeModals();\n          fetchTableData(currentPage);\n        } else {\n          alert(\n            result.message ||\n              result.messages?.[0] ||\n              \"Submit failed. Please try again.\",\n          );\n        }\n      } catch (err) {\n        console.error(\"Submit Log Error:\", err);\n        alert(\"Network error. Please try again.\");\n      }\n    }\n    \n    \/\/ \u00e2\u201d\u20ac\u00e2\u201d\u20ac ADD AD HOC ASSIGNMENT \u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\u00e2\u201d\u20ac\n    function openAddAdHocModal() {\n      \/\/ Set today's date as default\n      const today = new Date();\n      const yyyy = today.getFullYear();\n      const mm = String(today.getMonth() + 1).padStart(2, \"0\");\n      const dd = String(today.getDate()).padStart(2, \"0\");\n      document.getElementById(\"addAdHocDate\").value = `${yyyy}-${mm}-${dd}`;\n    \n      \/\/ Populate Client dropdown\n      const clientSel = document.getElementById(\"addAdHocClient\");\n      clientSel.innerHTML =\n        '<option value=\"\">Select Client<\/option>' +\n        dropDownData.clients\n          .map((c) => `<option value=\"${c.id}\">${c.name || \"\"}<\/option>`)\n          .join(\"\");\n    \n      \/\/ Populate Project dropdown\n      const projSel = document.getElementById(\"addAdHocProject\");\n      projSel.innerHTML =\n        '<option value=\"\">Select Project<\/option>' +\n        dropDownData.projects\n          .map((p) => `<option value=\"${p.id}\">${p.name || \"\"}<\/option>`)\n          .join(\"\");\n    \n      \/\/ Reset fields\n      document.getElementById(\"addAdHocWorkType\").value = \"\";\n      document.getElementById(\"addAdHocDescription\").value = \"\";\n      document.getElementById(\"addAdHocMinsUtilized\").value = \"\";\n      document.getElementById(\"addAdHocHrsUtilized\").value = \"\";\n    \n      document.getElementById(\"modalAddAdHoc\").style.display = \"flex\";\n    }\n    \n    function calcAdHocHrs() {\n      const mins =\n        parseInt(document.getElementById(\"addAdHocMinsUtilized\").value, 10) || 0;\n      document.getElementById(\"addAdHocHrsUtilized\").value = (mins \/ 60).toFixed(2);\n    }\n    \n    async function submitAdHocAssignment() {\n      const date = document.getElementById(\"addAdHocDate\").value;\n      const clientId = document.getElementById(\"addAdHocClient\").value;\n      const projectId = document.getElementById(\"addAdHocProject\").value;\n      const workType = document.getElementById(\"addAdHocWorkType\").value.trim();\n      const description = document\n        .getElementById(\"addAdHocDescription\")\n        .value.trim();\n      const minsUtilized = document.getElementById(\"addAdHocMinsUtilized\").value;\n    \n      if (\n        !date ||\n        !clientId ||\n        !projectId ||\n        !workType ||\n        !description ||\n        !minsUtilized\n      ) {\n        alert(\"Please fill in all required fields.\");\n        return;\n      }\n    \n      const totalMins = parseInt(minsUtilized, 10) || 0;\n      const hrs = Math.floor(totalMins \/ 60);\n      const mins = totalMins % 60;\n    \n      const payload = {\n        date: date,\n        client_id: parseInt(clientId, 10),\n        project_id: parseInt(projectId, 10),\n        ad_hoc_work_type: workType,\n        description: description,\n        minute_utilized: mins,\n        hour_utilized: hrs,\n      };\n    \n      try {\n        const res = await fetch(ENDPOINTS.ADHOC_ADD, {\n          method: \"POST\",\n          headers: getHeaders(),\n          body: JSON.stringify(payload),\n        });\n        if (handleAuthError(res)) return;\n    \n        if (!res.ok) {\n          const text = await res.text();\n          let message = \"Failed to add. Server error.\";\n          try {\n            const errorJson = JSON.parse(text);\n            message = errorJson.message || errorJson.messages?.[0] || message;\n          } catch (e) {\n            console.error(\"Non-JSON error:\", text);\n          }\n          alert(message);\n          return;\n        }\n    \n        const result = await res.json();\n        if (result.code === 200 || result.status === \"success\" || result.message) {\n          alert(\"Ad Hoc Assignment added successfully.\");\n          closeModals();\n          if (activeView === \"adhoc\") {\n            fetchAdhocTableData(currentPage);\n          }\n        } else {\n          alert(\n            result.message ||\n              result.messages?.[0] ||\n              \"Failed to add. Please try again.\",\n          );\n        }\n      } catch (err) {\n        console.error(\"Add Ad Hoc error:\", err);\n        alert(\"Network error. Please try again.\");\n      }\n    }\n    \n    async function approveAllAdhoc() {\n      if (!CAN_BULK_ADHOC) {\n        alert(\n          \"Access denied: you do not have permission to bulk approve ad hoc assignments.\",\n        );\n        return;\n      }\n      const ids = getSelectedAdhocIds();\n      if (ids.length === 0) {\n        alert(\"Please select at least one ad hoc assignment to approve.\");\n        return;\n      }\n      if (!confirm(\"Are you sure you want to approve selected item\")) {\n        return;\n      }\n      try {\n        const res = await fetch(ENDPOINTS.ADHOC_APPROVE_BULK, {\n          method: \"POST\",\n          headers: getHeaders(),\n          body: JSON.stringify({ adhoc_id: ids }),\n        });\n        if (handleAuthError(res)) return;\n        const result = await res.json();\n        if (\n          both(\n            res.ok,\n            result.code === 200 || result.status === \"success\" || result.message,\n          )\n        ) {\n          alert(result.messages?.[0] || \"Ad Hoc Assignments Approved.\");\n          fetchAdhocTableData(currentPage);\n        } else {\n          alert(\n            result.message ||\n              result.messages?.[0] ||\n              \"Approve failed. Please try again.\",\n          );\n        }\n      } catch (err) {\n        console.error(\"Approve All error:\", err);\n        alert(\"Network error. Please try again.\");\n      }\n    }\n    \n    async function resetAllAdhoc() {\n      if (!CAN_BULK_ADHOC) {\n        alert(\n          \"Access denied: you do not have permission to bulk reset ad hoc assignments.\",\n        );\n        return;\n      }\n      const ids = getSelectedAdhocIds();\n      if (ids.length === 0) {\n        alert(\"Please select at least one ad hoc assignment to reset.\");\n        return;\n      }\n      if (!confirm(\"Are you sure you want to reset selected item\")) {\n        return;\n      }\n      try {\n        const res = await fetch(ENDPOINTS.ADHOC_RESET_BULK, {\n          method: \"POST\",\n          headers: getHeaders(),\n          body: JSON.stringify({ adhoc_id: ids }),\n        });\n        if (handleAuthError(res)) return;\n        const result = await res.json();\n        if (\n          both(\n            res.ok,\n            result.code === 200 || result.status === \"success\" || result.message,\n          )\n        ) {\n          alert(result.messages?.[0] || \"Ad Hoc Assignments Reset.\");\n          fetchAdhocTableData(currentPage);\n        } else {\n          alert(\n            result.message ||\n              result.messages?.[0] ||\n              \"Reset failed. Please try again.\",\n          );\n        }\n      } catch (err) {\n        console.error(\"Reset All error:\", err);\n        alert(\"Network error. Please try again.\");\n      }\n    }\n    \n    window.onload = init;\n<\/script>\n\n\n    \n    <div class=\"ph-title\" id=\"pageHeading\">Ad Hoc Assignment<\/div> <br>\n    \n    <div class=\"filter-grid\" id=\"filterForm\"><\/div>\n    \n    <div class=\"action-row\" id=\"btnGroup\"><\/div>\n    \n    <!-- Hidden CSV Import Input -->\n    <input type=\"file\" id=\"csvImportInput\" accept=\".csv\" onchange=\"handleCSVImport(event)\">\n    \n    <div class=\"tabs-nav\">\n        <div class=\"tab-link\" id=\"tab-assigned\" onclick=\"toggleTab('assigned')\">Assigned Assignment<\/div>\n        <div class=\"tab-link active\" id=\"tab-adhoc\" onclick=\"toggleTab('adhoc')\">Ad Hoc Assignment<\/div>\n    <\/div>\n    \n    <div class=\"table-container\">\n        <table>\n            <thead id=\"tblHead\"><\/thead>\n            <tbody id=\"tblBody\"><\/tbody>\n        <\/table>\n    <\/div>\n    \n    <!-- Pagination Footer -->\n    <div class=\"pagination-container\">\n        <div class=\"pagination-controls\">\n            <span class=\"nav-link\" id=\"prevBtn\">&laquo; Previous<\/span>\n            <div id=\"pageNumbers\" style=\"display:flex; gap: 4px; flex-wrap: wrap; justify-content: center;\"><\/div>\n            <span class=\"nav-link\" id=\"nextBtn\">Next &raquo;<\/span>\n        <\/div>\n        <div id=\"entryInfo\" style=\"font-size: 12px; color: var(--text-muted);\">\n            Showing 0 to 0 of 0 entries\n        <\/div>\n    <\/div>\n    \n    \n    <div id=\"modalSubmit\" class=\"modal-overlay\">\n        <div class=\"modal-content\">\n            <div class=\"modal-header\">Submit Assignment<\/div>\n            <div class=\"modal-grid\" id=\"submitModalFields\" style=\"grid-template-columns: repeat(3, 1fr);\"><\/div>\n            <div class=\"modal-footer\">\n                <button class=\"btn btn-clear\" onclick=\"closeModals()\">Close<\/button>\n                <button class=\"btn btn-blue\" style=\"width: 150px;\" onclick=\"submitAssignmentLog()\">Submit<\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n    \n    <div id=\"modalAssigned\" class=\"modal-overlay\">\n        <div class=\"modal-content\">\n            <div class=\"modal-header\">Edit Assigned Assignments<\/div>\n            <div class=\"modal-grid\" id=\"assignedModalFields\"><\/div>\n            <div class=\"modal-footer\">\n                <button class=\"btn btn-clear\" onclick=\"closeModals()\">Close<\/button>\n                <button class=\"btn btn-blue\" style=\"width: 200px;\" onclick=\"updateAssignment()\">Edit Assignment<\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n    \n    <div id=\"modalAdhoc\" class=\"modal-overlay\">\n        <div class=\"modal-content\">\n            <div class=\"modal-header\">Edit Ad Hoc Assignment<\/div>\n            <div class=\"modal-grid\" id=\"adhocModalFields\" style=\"grid-template-columns: repeat(3, 1fr);\"><\/div>\n            <div class=\"modal-footer\">\n                <button class=\"btn btn-clear\" onclick=\"closeModals()\">Close<\/button>\n                <button class=\"btn btn-blue\" style=\"width: 150px;\" onclick=\"updateAdHoc()\">Submit<\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n    \n    <div id=\"modalAdhocApproval\" class=\"modal-overlay\">\n        <div class=\"modal-content\" style=\"max-width: 800px; width: 90%; padding: 24px;\">\n            <div class=\"modal-header\" style=\"font-size: 20px; font-weight: 600; margin-bottom: 20px; border-bottom: 1px solid #EFEFEF; padding-bottom: 10px;\">Approve Ad Hoc Assignment<\/div>\n            <div class=\"modal-grid\" id=\"adhocApprovalFields\" style=\"display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-bottom: 20px;\"><\/div>\n            <div class=\"modal-footer\" style=\"display: flex; justify-content: flex-end; gap: 15px; border-top: 1px solid #EFEFEF; padding-top: 15px;\">\n                <button class=\"btn btn-clear\" onclick=\"closeModals()\">Close<\/button>\n                <button class=\"btn btn-blue\" style=\"width: 150px;\" onclick=\"submitAdhocApproval()\">Submit<\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n    \n    <!-- Add Ad Hoc Assignment Modal -->\n\n    \n    <div id=\"modalAddAdHoc\" class=\"modal-overlay\">\n        <div class=\"adhoc-modal-content\">\n            <div class=\"adhoc-modal-title\">Add Ad Hoc Assignment<\/div>\n            <div class=\"adhoc-form-group\">\n                <label>Date <span class=\"req\">*<\/span><\/label>\n                <input type=\"date\" class=\"adhoc-form-control\" id=\"addAdHocDate\">\n            <\/div>\n            <div class=\"adhoc-form-group\">\n                <label>Client <span class=\"req\">*<\/span><\/label>\n                <select class=\"adhoc-form-control select-control\" id=\"addAdHocClient\">\n                    <option value=\"\">Select Client<\/option>\n                <\/select>\n            <\/div>\n            <div class=\"adhoc-form-group\">\n                <label>Project <span class=\"req\">*<\/span><\/label>\n                <select class=\"adhoc-form-control select-control\" id=\"addAdHocProject\">\n                    <option value=\"\">Select Project<\/option>\n                <\/select>\n            <\/div>\n            <div class=\"adhoc-form-group\">\n                <label>Hoc Work Type <span class=\"req\">*<\/span><\/label>\n                <input type=\"text\" class=\"adhoc-form-control\" id=\"addAdHocWorkType\" placeholder=\"Hoc Work Type\">\n            <\/div>\n            <div class=\"adhoc-form-group\">\n                <label>Description <span class=\"req\">*<\/span><\/label>\n                <input type=\"text\" class=\"adhoc-form-control\" id=\"addAdHocDescription\" placeholder=\"Enter Description\">\n            <\/div>\n            <div class=\"adhoc-form-group\">\n                <label>Mins Utilized <span class=\"req\">*<\/span><\/label>\n                <input type=\"number\" class=\"adhoc-form-control\" id=\"addAdHocMinsUtilized\" placeholder=\"Enter Mins\" oninput=\"calcAdHocHrs()\">\n            <\/div>\n            <div class=\"adhoc-form-group\">\n                <label>Hrs Utilized <span class=\"req\">*<\/span><\/label>\n                <input type=\"number\" class=\"adhoc-form-control\" id=\"addAdHocHrsUtilized\" placeholder=\"Enter Hrs\" disabled=\"\">\n            <\/div>\n            <div class=\"adhoc-modal-footer\">\n                <button class=\"adhoc-btn-close\" onclick=\"closeModals()\">Close<\/button>\n                <button class=\"adhoc-btn-submit\" onclick=\"submitAdHocAssignment()\">Submit<\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n    \n\n<\/div><\/div>\n\n<\/div><\/div><\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ad Hoc Assignment Assigned Assignment Ad Hoc Assignment &laquo; Previous Next &raquo; Showing 0 to 0 of 0 entries Submit Assignment Close Submit Edit Assigned Assignments Close Edit Assignment Edit Ad Hoc Assignment Close Submit Approve Ad Hoc Assignment Close Submit Add Ad Hoc Assignment Date * Client * Select Client Project * Select Project&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_kad_post_transparent":"disable","_kad_post_title":"hide","_kad_post_layout":"fullwidth","_kad_post_sidebar_id":"","_kad_post_content_style":"unboxed","_kad_post_vertical_padding":"hide","_kad_post_feature":"hide","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"class_list":["post-200","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/wp-json\/wp\/v2\/pages\/200","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/wp-json\/wp\/v2\/comments?post=200"}],"version-history":[{"count":39,"href":"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/wp-json\/wp\/v2\/pages\/200\/revisions"}],"predecessor-version":[{"id":1231,"href":"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/wp-json\/wp\/v2\/pages\/200\/revisions\/1231"}],"wp:attachment":[{"href":"https:\/\/ph-portal-v2.zyneventures.com\/index.php\/wp-json\/wp\/v2\/media?parent=200"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}