{"context":{"domain":"tm-logistica-poc"},"layers":{"ApplicationLayer":{"reference":"ApplicationLayer","availableInstances":[{"reference":"ComponentsDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"component":"data2-core@DataSet","reference":"SystemsDataSet","params":{"filter":{"domain":"data2"},"pagination":{"size":1},"datasource":{"component":"data2-core-types@ProcessReference","params":{"reference":"SystemsDataSource"}}}},{"reference":"ExternalComponentInstancesDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"reference":"SystemsDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"5e3b796d6228227ca637d0f4","name":"data2","domain":"data2","organization":"62292184611f480b3191c37c","visibility":"public","updatedAt":"2026-07-27T14:19:36.810Z"}]}},{"reference":"OrganizationsDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"reference":"DataComponentInstancesDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"component":"data2-core@DataSet","reference":"OneFileComponentInstancesDataSet","params":{"pagination":{"size":1},"master":{"dataset":{"component":"data2-core-types@ProcessReference","params":{"reference":"SystemsDataSet"}},"localField":"system","masterField":"_id"},"datasource":{"component":"data2-core-types@ProcessReference","params":{"reference":"FileComponentInstancesDataSource"}}}},{"reference":"ApplicationsDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"reference":"ComponentInstancesDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"reference":"ServiceComponentInstancesDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"component":"data2-core@Data2TableDataSource","reference":"FileComponentInstancesDataSource","params":{"table":"fileComponentInstances","schema":[{"component":"data2-core-types@Field","params":{"key":"component","title":"Component","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"system","title":"System","component":"data2-core-primitives@ObjectId"}},{"component":"data2-core-types@Field","params":{"key":"displayName","title":"Display Name","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"params","title":"Params","component":"data2-core-primitives@Object"}},{"component":"data2-core-types@Field","params":{"key":"reference","title":"Reference","component":"data2-core-primitives@String"}}]}},{"component":"data2-core@MemoryDataSource","reference":"EmptyDataSource","params":{"initialData":[]}},{"reference":"ComponentsDataSet","component":"data2-core@DataSet","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"EmptyDataSource"}}}},{"reference":"UserComponentsDataSet","component":"data2-core@DataSet","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"EmptyDataSource"}}}},{"reference":"DataComponentInstancesDataSet","component":"data2-core@DataSet","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"EmptyDataSource"}}}},{"reference":"ServiceComponentInstancesDataSet","component":"data2-core@DataSet","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"EmptyDataSource"}}}},{"reference":"ComponentInstancesDataSet","component":"data2-core@DataSet","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"EmptyDataSource"}}}},{"reference":"ExternalComponentInstancesDataSet","component":"data2-core@DataSet","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"EmptyDataSource"}}}},{"reference":"ApplicationsDataSet","component":"data2-core@DataSet","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"EmptyDataSource"}}}}],"processesParams":{}},"HostApplicationLayer":{"reference":"HostApplicationLayer","availableInstances":[{"_id":"5f15ff190528b92601890f71","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"SystemsTableDataSource"}},"filter":{"domain":{"component":"data2-core-types@Reference","params":{"reference":"domain"}}},"pk":"_id","fields":[{"component":"data2-core-types@FieldReference","params":{"key":"_id"}},{"component":"data2-core-types@FieldReference","params":{"key":"name"}},{"component":"data2-core-types@FieldReference","params":{"key":"domain"}},{"component":"data2-core-types@FieldReference","params":{"key":"visibility"}},{"component":"data2-core-types@FieldReference","params":{"key":{"component":"data2-core-primitives@String","params":{"content":"customDomains"}}},"break":true},{"component":"data2-core-types@FieldReference","params":{"key":{"component":"data2-core-primitives@String","params":{"content":"organization._id"}}},"break":true},{"component":"data2-core-types@FieldReference","params":{"key":{"component":"data2-core-primitives@String","params":{"content":"organization.name"}}},"break":true},{"component":"data2-core-types@FieldReference","params":{"key":{"component":"data2-core-primitives@String","params":{"content":"organization.billingStatus"}}},"break":true},{"component":"data2-core-types@FieldReference","params":{"key":{"component":"data2-core-primitives@String","params":{"content":"organization.publicTrial.active"}}},"break":true},{"component":"data2-core-types@FieldReference","params":{"key":{"component":"data2-core-primitives@String","params":{"content":"settings.defaultAccessPolicy"}}},"break":true}],"pagination":{"size":{"component":"data2-core-primitives@Number","params":{"content":1}}},"staticPagination":{"size":{"component":"data2-core-primitives@Number","params":{"content":1}}},"policies":[{"component":"data2-core-auth@Policy","params":{"allow":{"params":{"actions":[{"params":{"components":[{"params":{"query":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$params.query"}}}},"field":{"component":"data2-core-primitives@String","params":{"content":"_id"}},"fieldType":"string"},"component":"data2@7KkQq0vK4a7D2gg6IVJT7"},{"params":{"query":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$params.query"}}}},"field":{"component":"data2-core-primitives@String","params":{"content":"domain"}},"fieldType":"string"},"component":"data2@7KkQq0vK4a7D2gg6IVJT7"},{"params":{"query":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$params.query"}}}},"field":{"component":"data2-core-primitives@String","params":{"content":"customDomains"}},"fieldType":"string"},"component":"data2@7KkQq0vK4a7D2gg6IVJT7"}]},"component":"data2-core-logical-operators@Or"}]},"component":"data2-core-flow@Series"}}}]},"reference":"SystemsDataSet","updatedAt":"2026-08-07T21:51:24.037Z","createdAt":"2020-07-20T20:31:21.838Z"},{"_id":"5f1601ce0528b92601890f7c","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"pagination":{"size":1000},"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"ComponentsTableDataSource"}},"sort":{"params.package":1,"params.component":1},"pk":"_id","autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"staticFilter":{"system":{"exists":{"params":{"content":false},"component":"data2-core-primitives@Boolean"}}},"filter":{"system":{"exists":{"params":{"content":false},"component":"data2-core-primitives@Boolean"}}}},"reference":"ComponentsDataSet","updatedAt":"2025-11-05T19:37:01.935Z","createdAt":"2020-07-20T20:42:54.898Z"},{"_id":"5f9041dbc8da12be8b94aea4","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"pagination":{"size":2000},"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"ComponentsTableDataSource"}},"pk":"_id","autoEdit":true,"master":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"policies":{"params":{"allowGet":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2@hkXy-UhMjhyfptdE6_fpW"}},"reference":"UserComponentsDataSet","updatedAt":"2025-11-06T21:06:58.095Z","createdAt":"2020-07-20T20:44:09.350Z"},{"_id":"65d8c4fabc9dbb8f94de8d53","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"ExternalComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"policies":{"params":{"allowGet":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2@hkXy-UhMjhyfptdE6_fpW"}},"reference":"ExternalComponentInstancesDataSet","updatedAt":"2025-11-06T21:07:23.742Z","createdAt":"2024-02-23T16:17:01.816Z"},{"reference":"SystemsTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"6a8c48a1e9d7f931a6fd649e","name":"TM Logistica","domain":"tm-logistica-poc","visibility":"private","updatedAt":"2026-08-24T13:35:29.471Z","createdAt":"2026-08-24T13:35:29.471Z"}]}},{"reference":"ComponentsTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"5f52a278a575399a45d239b4","component":"data2-core-types@Component","params":{"package":"data2-core-primitives","component":"Router","interactions":{"component":"data2-core-types@FieldSet","params":{"fields":{"goBack":{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-types@Function"}},"definition":{"component":"data2-core-functions@Function","params":{"body":{"preventEvaluation":true,"component":"data2-core-types@Getter","params":{"module":{"component":"data2-core-types@This","params":{}},"prop":"history.goBack","args":[]}}}},"icon":{"component":"data2-core-primitives@String","params":{"content":"arrow-left"}},"visibility":"public"}},"goTo":{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"definition":{"component":"data2-core-functions@Function","params":{"body":{"preventEvaluation":true,"component":"data2-core-types@Getter","params":{"module":{"component":"data2-core-types@This","params":{}},"prop":"history.push","args":[{"component":"data2-core-types@Reference","params":{"reference":"url"}},{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"preserveQuery"}}}}]}},"parameters":[{"component":"data2-core-primitives@String","params":{"content":"url"}},{"component":"data2-core-primitives@String","params":{"content":"preserveQuery"}}]},"break":true},"icon":{"component":"data2-core-primitives@String","params":{"content":"share"}},"visibility":"public","arguments":[{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Path to route"}},"description":{"component":"data2-core-primitives@String","params":{"content":"Path to redirect user"}},"visibility":"public","required":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2-core-types@ComponentParameter"},{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Boolean"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Preserve Query"}},"description":{"component":"data2-core-primitives@String","params":{"content":"Preserve query string parameters  preserve query parameters on navigating."}},"visibility":"public","required":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2-core-types@ComponentParameter"}]}},"open":{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-types@Function"}},"definition":{"component":"data2-core-functions@Function","params":{"body":{"preventEvaluation":true,"component":"data2-core-types@Getter","params":{"module":{"component":"data2-core-types@This","params":{}},"prop":"history.push","args":[{"pathname":{"component":"data2-core-types@Reference","params":{"reference":"value"}}}]}},"parameters":["value"]}},"icon":{"component":"data2-core-primitives@String","params":{"content":"share"}},"visibility":"public","arguments":[{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Link to open"}},"description":{"component":"data2-core-primitives@String","params":{"content":""}},"visibility":"public","required":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2-core-types@ComponentParameter"},{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Target"}},"description":{"component":"data2-core-primitives@String","params":{"content":"Where to open the link"}},"visibility":"public","required":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"oneOf":[{"params":{"content":"_blank"},"component":"data2-core-primitives@String"},{"params":{"content":"_self"},"component":"data2-core-primitives@String"},{"params":{"content":"_parent"},"component":"data2-core-primitives@String"},{"params":{"content":"_top"},"component":"data2-core-primitives@String"}]},"component":"data2-core-types@ComponentParameter"}]}},"close":{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-types@Function"}},"definition":{"component":"data2-core-functions@Function","params":{"body":{"preventEvaluation":true,"component":"data2-core-types@Getter","params":{"module":{"params":{},"component":"data2-core-web@Window"},"prop":"close"}},"parameters":["value"]}},"icon":{"component":"data2-core-primitives@String","params":{"content":"times"}},"visibility":"public","arguments":[{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Link to open"}},"description":{"component":"data2-core-primitives@String","params":{"content":""}},"visibility":"public","required":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2-core-types@ComponentParameter"},{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Target"}},"description":{"component":"data2-core-primitives@String","params":{"content":"Where to open the link"}},"visibility":"public","required":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"oneOf":[{"params":{"content":"_blank"},"component":"data2-core-primitives@String"},{"params":{"content":"_self"},"component":"data2-core-primitives@String"},{"params":{"content":"_parent"},"component":"data2-core-primitives@String"},{"params":{"content":"_top"},"component":"data2-core-primitives@String"}]},"component":"data2-core-types@ComponentParameter"}],"description":{"component":"data2-core-primitives@String","params":{"content":"Closes a window that was opened via router.open."}}}}}}}}},{"_id":"620d28658271aa4129919d89","component":"data2-core-types@Component","params":{"package":"data2-interface-services","component":"DeviceController","interactions":{"params":{"fields":{"postMessage":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"arguments":[{"component":"data2-core-types@ComponentParameter","params":{"component":"data2-core-primitives@String","title":{"component":"data2-core-primitives@String","params":{"content":"data"}}}}]},"component":"data2-core-types@ComponentParameter"},"print":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"arguments":[{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Object"}},"flat":{"component":"data2-core-primitives@Boolean","params":{"content":true}},"parameters":{"zoom":{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Number"}},"title":{"component":"data2-core-primitives@String","params":{"content":"zoom"}},"visibility":"public"}}},"visibility":"public"},"component":"data2-core-types@ComponentParameter"}],"visibility":"public"},"component":"data2-core-types@ComponentParameter"},"share":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}}},"component":"data2-core-types@ComponentParameter"},"clipboard.copy":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"arguments":[{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}}}}]},"component":"data2-core-types@ComponentParameter"},"clipboard.paste":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"arguments":[{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}}}}]},"component":"data2-core-types@ComponentParameter"},"download":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"visibility":"public","arguments":[{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Filename"}}}},{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Content"}}}},{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Object"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Options"}},"parameters":{"params":{"fields":{"type":{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Mimetype"}}}}}},"component":"data2-core-types@FieldSet"}}}]},"component":"data2-core-types@ComponentParameter"},"downloadUrl":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"visibility":"public","arguments":[{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Filename"}}}},{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Url"}}}}]},"component":"data2-core-types@ComponentParameter"},"promptFiles":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"arguments":[{"component":"data2-core-types@ComponentParameter","params":{"component":"data2-core-primitives@Object","flat":{"component":"data2-core-primitives@Boolean","params":{"content":true}},"parameters":{"params":{"fields":{"multiple":{"component":"data2-core-types@ComponentParameter","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"Multiple"}},"description":{"component":"data2-core-primitives@String","params":{"content":"Whether or not to allow selecting multiple files"}},"component":"data2-core-primitives@Boolean"}},"acceptedFormats":{"component":"data2-core-types@ComponentParameter","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"Accepted Formats"}},"description":{"component":"data2-core-primitives@String","params":{"content":"Accepted file formats"}},"component":"data2-core-primitives@String","list":{"component":"data2-core-primitives@Boolean","params":{"content":true}}}},"timeout":{"component":"data2-core-types@ComponentParameter","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"Timeout"}},"description":{"component":"data2-core-primitives@String","params":{"content":"Max milliseconds to wait for file upload"}},"component":"data2-core-primitives@Number"}}}},"component":"data2-core-types@FieldSet"}}}],"visibility":"public"},"component":"data2-core-types@ComponentParameter"},"meetingRecord":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"visibility":"public","definition":{"params":{"actions":[{"params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"meeting"}},"script":{"component":"data2-core-primitives@String","params":{"content":"(function() {\n  let mediaRecorder;\n  let audioChunks = [];\n  let combinedStream;\n  let audioContext;\n  \n  window.meetingCapture = async function() {\n    try {\n      // Solicitar acesso ao áudio da guia (e vídeo, que será ignorado depois)\n      const tabStream = await navigator.mediaDevices.getDisplayMedia({ \n        video: true, // Necessário para alguns navegadores\n        audio: true\n      });\n      \n      // Remover a trilha de vídeo\n      const tabAudioTrack = tabStream.getAudioTracks()[0];\n      \n      // Solicitar acesso ao microfone\n      const micStream = await navigator.mediaDevices.getUserMedia({ audio: true });\n      const micAudioTrack = micStream.getAudioTracks()[0];\n      \n      // Criar um novo MediaStream com ambas as trilhas de áudio\n      combinedStream = new MediaStream([tabAudioTrack, micAudioTrack]);\n      \n      // Criar um contexto de áudio para misturar os streams\n      audioContext = new AudioContext();\n      const destination = audioContext.createMediaStreamDestination();\n      \n      // Conectar a trilha de áudio da guia\n      const tabSource = audioContext.createMediaStreamSource(new MediaStream([tabAudioTrack]));\n      tabSource.connect(destination);\n      \n      // Conectar a trilha de áudio do microfone\n      const micSource = audioContext.createMediaStreamSource(new MediaStream([micAudioTrack]));\n      micSource.connect(destination);\n      \n      // Iniciar gravação com o stream misturado\n      mediaRecorder = new MediaRecorder(destination.stream);\n      audioChunks = [];\n      mediaRecorder.ondataavailable = (e) => audioChunks.push(e.data);\n      mediaRecorder.start();\n      \n      console.log('Gravação iniciada. Chame meetingCaptureStop() para finalizar.');\n    } catch (error) {\n      console.error('Erro ao iniciar a captura:', error);\n    }\n  };\n  \n  window.meetingCaptureStop = function() {\n    return new Promise((resolve, reject) => {\n      if (!mediaRecorder) {\n        reject('Nenhuma gravação em andamento.');\n        return;\n      }\n      \n      mediaRecorder.onstop = () => {\n        const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });\n        combinedStream.getTracks().forEach(track => track.stop());\n        audioContext.close();\n        \n        resolve(audioBlob);\n        console.log('Gravação finalizada. O arquivo de áudio está pronto para upload.');\n      };\n      \n      mediaRecorder.stop();\n    });\n  };\n})();"}}},"component":"data2-core-web@Script"},{"component":"data2-core-types@Getter","params":{"module":{"params":{},"component":"data2-core-web@Window"},"prop":{"component":"data2-core-primitives@String","params":{"content":"meetingCapture"}}}}]},"component":"data2-core-flow@Series"}},"component":"data2-core-types@ComponentParameter"},"meetingRecordStop":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"visibility":"public","arguments":[{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Filename"}}}},{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Content"}}}},{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Object"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Options"}},"parameters":{"params":{"fields":{"type":{"component":"data2-core-types@ComponentParameter","params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@String"}},"title":{"component":"data2-core-primitives@String","params":{"content":"Mimetype"}}}}}},"component":"data2-core-types@FieldSet"}}}],"definition":{"params":{"actions":[{"component":"data2-core-types@Getter","params":{"module":{"params":{},"component":"data2-core-web@Window"},"prop":{"component":"data2-core-primitives@String","params":{"content":"meetingCaptureStop"}}}}]},"component":"data2-core-flow@Series"}},"component":"data2-core-types@ComponentParameter"},"notify":{"params":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core-primitives@Function"}},"visibility":"private","arguments":[{"component":"data2-core-types@ComponentParameter","params":{"component":"data2-core-primitives@Object","parameters":{"title":{"params":{"component":"data2-core-primitives@String","index":{"component":"data2-core-primitives@Number","params":{"content":0}},"title":{"component":"data2-core-primitives@String","params":{"content":"title"}}},"component":"data2-core-types@ComponentParameter"},"sound":{"params":{"component":"data2-core-types@FileComponentUrlReference","index":{"component":"data2-core-primitives@Number","params":{"content":1}},"title":{"component":"data2-core-primitives@String","params":{"content":"sound"}}},"component":"data2-core-types@ComponentParameter"}},"flat":{"component":"data2-core-primitives@Boolean","params":{"content":true}}}}]},"component":"data2-core-types@ComponentParameter"}}},"component":"data2-core-types@FieldSet"}}},{"_id":"6a8f51d15633ff3659f77f9c","component":"data2-core-types@Component","system":"6a8c48a1e9d7f931a6fd649e","params":{"extends":"data2-core-primitives@Block","component":"prazoeprova","package":"tm-logistica-poc","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"/* Central TM — plataforma unificada de dados da TM Logistica */\n\nconst META = 99.6;\n// ATENCAO: no CodeHost, `export default` se comporta como `return` — nada declarado\n// com const/let DEPOIS dele chega a inicializar (funcoes hoistam, constantes nao).\n// Toda constante de modulo tem que ficar aqui em cima.\nconst CORES = ['var(--c1)', 'var(--c2)', 'var(--c3)', 'var(--c4)', 'var(--c5)', 'var(--c6)'];\nconst PERFIS = {\n  admin:      { nome: 'Admin / Gestao',      menu: ['inicio', 'fluxo', 'pedidos', 'clientes', 'terceiros', 'financeiro', 'comissoes', 'cadastros'] },\n  contas:     { nome: 'Gerente de contas',   menu: ['inicio', 'clientes', 'comissoes', 'pedidos'] },\n  financeiro: { nome: 'Financeiro',          menu: ['inicio', 'financeiro', 'comissoes', 'clientes', 'cadastros'] },\n  operacao:   { nome: 'Gestao de pedidos',   menu: ['inicio', 'fluxo', 'pedidos', 'terceiros'] },\n  coleta:     { nome: 'Gestao de coleta',    menu: ['inicio', 'fluxo', 'pedidos', 'terceiros'] },\n  terceiros:  { nome: 'Gestao de terceiros', menu: ['inicio', 'terceiros', 'fluxo', 'pedidos'] },\n  vendedor:   { nome: 'Vendedor (generico)',  menu: ['vendedor', 'pedidos'] },\n  vendedor_rs:{ nome: 'Vendedor — Rodrigo Salles', menu: ['vendedor', 'pedidos'], fixo: 'Rodrigo Salles' }\n};\nconst TITULO = { inicio: 'Inicio', fluxo: 'Fluxo', pedidos: 'Pedidos', clientes: 'Clientes', terceiros: 'Terceiros', financeiro: 'Financeiro', comissoes: 'Comissoes', cadastros: 'Cadastros', vendedor: 'Minha carteira' };\nconst PAPEL = { comercial: { rot: 'Usuario comercial', desc: 'fecha o contrato e faz a proposta' }, sdr: { rot: 'SDR', desc: 'prospecta e capta o cliente' } };\n\nconst EST = {\n  agendado:          { rot: 'Agendado',        cls: 'ch-mute' },\n  aguardando_coleta: { rot: 'Aguardando coleta', cls: 'ch-info' },\n  no_galpao:         { rot: 'No galpao',       cls: 'ch-info' },\n  em_rota:           { rot: 'Em rota',         cls: 'ch-ok' },\n  em_risco:          { rot: 'Em risco',        cls: 'ch-warn' },\n  vai_estourar:      { rot: 'Vai estourar',    cls: 'ch-crit' },\n  estourado:         { rot: 'Estourado',       cls: 'ch-crit' },\n  sem_baixa:         { rot: 'Sem baixa',       cls: 'ch-crit' },\n  entregue_no_prazo: { rot: 'Entregue',        cls: 'ch-ok' },\n  entregue_fora:     { rot: 'Entregue fora',   cls: 'ch-crit' }\n};\nconst ABERTOS = ['agendado', 'aguardando_coleta', 'no_galpao', 'em_rota', 'em_risco', 'vai_estourar', 'estourado', 'sem_baixa'];\nconst PROBLEMA = ['em_risco', 'vai_estourar', 'estourado', 'sem_baixa'];\n\n/* ---------- utils ---------- */\nfunction esc(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;'); }\nfunction dt(s) { if (!s) return null; const d = new Date(s); return isNaN(d.getTime()) ? null : d; }\nfunction hhmm(d) { return d ? String(d.getHours()).padStart(2, '0') + ':' + String(d.getMinutes()).padStart(2, '0') : '-'; }\nfunction ddmm(d) { return d ? String(d.getDate()).padStart(2, '0') + '/' + String(d.getMonth() + 1).padStart(2, '0') : '-'; }\nfunction dtLabel(d, agora) {\n  if (!d) return '-';\n  const h = new Date(agora); h.setHours(0, 0, 0, 0);\n  const dia = new Date(d); dia.setHours(0, 0, 0, 0);\n  const diff = Math.round((dia - h) / 86400000);\n  if (diff === 0) return 'hoje ' + hhmm(d);\n  if (diff === -1) return 'ontem ' + hhmm(d);\n  if (diff === 1) return 'amanha ' + hhmm(d);\n  return ddmm(d) + ' ' + hhmm(d);\n}\nfunction dur(ms) {\n  const m = Math.abs(Math.round(ms / 60000));\n  if (m < 60) return m + ' min';\n  const h = Math.floor(m / 60), r = m % 60;\n  if (h < 24) return h + 'h' + String(r).padStart(2, '0');\n  return Math.floor(h / 24) + 'd' + (h % 24) + 'h';\n}\nfunction num(v) { return Number(v || 0).toLocaleString('pt-BR'); }\nfunction brl(v) { return 'R$ ' + Number(v || 0).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }\nfunction brlC(v) { const n = Number(v || 0); return n >= 1000 ? 'R$ ' + (n / 1000).toFixed(1).replace('.', ',') + 'k' : brl(n); }\nfunction pctS(n, d, casas) { return d > 0 ? ((n / d) * 100).toFixed(casas == null ? 1 : casas).replace('.', ',') + '%' : '-'; }\nfunction mesLabel(m) {\n  const N = ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'];\n  const p = String(m).split('-'); return N[Number(p[1]) - 1] + '/' + String(p[0]).slice(2);\n}\nfunction opt(v, atual, rot) { return '<option value=\"' + esc(v) + '\"' + (String(v) === String(atual) ? ' selected' : '') + '>' + esc(rot == null ? v : rot) + '</option>'; }\nfunction val(d2, id) { const el = d2.$('#' + id); return el ? String(el.value).trim() : ''; }\nfunction L(d2, k) { return (d2.state.dados && d2.state.dados[k]) || []; }\nasync function recarrega(d2) {\n  const res = await d2.rush('api-dados').invoke({});\n  const p = (res && res.data) ? res.data : res;\n  p.remessa = [].concat(p.remessa1 || [], p.remessa2 || [], p.remessa3 || []);\n  d2.state.dados = p;\n}\n\n/* ---------- motor de tempo ---------- */\nfunction agoraDe(d2) { return d2.state.relogio || new Date(); }\nfunction estadoDe(r, agora) {\n  const t = agora.getTime();\n  const cri = dt(r.criado_em), col = dt(r.coletado_em), gal = dt(r.galpao_em);\n  const rot = dt(r.rota_em), pra = dt(r.prazo_em), ent = dt(r.entrega_em);\n  if (cri && t < cri.getTime()) return 'agendado';\n  if (ent && t >= ent.getTime()) return ent.getTime() <= (pra ? pra.getTime() : Infinity) ? 'entregue_no_prazo' : 'entregue_fora';\n  if (rot && t >= rot.getTime()) {\n    if (!ent) { if (pra && t > pra.getTime()) return 'sem_baixa'; return 'em_rota'; }\n    if (pra) {\n      const falta = pra.getTime() - t;\n      if (falta < 0) return 'estourado';\n      if (falta <= 30 * 60000) return 'vai_estourar';\n      if (falta <= 120 * 60000) return 'em_risco';\n    }\n    return 'em_rota';\n  }\n  if (r.origem === 'full') { if (gal && t >= gal.getTime()) return 'no_galpao'; return 'aguardando_coleta'; }\n  if (col && t >= col.getTime()) return 'no_galpao';\n  return 'aguardando_coleta';\n}\nfunction enriquece(d2) {\n  const agora = agoraDe(d2);\n  const rem = L(d2, 'remessa');\n  return rem.map(r => ({ r: r, e: estadoDe(r, agora), pra: dt(r.prazo_em), ent: dt(r.entrega_em) }));\n}\n\n/* ---------- agregacoes ---------- */\nfunction porMesCliente(d2) {\n  const out = {};\n  L(d2, 'clientemes').forEach(c => {\n    const k = c.cliente_cnpj;\n    if (!out[k]) out[k] = { nome: c.cliente_nome, meses: {}, lojas: {} };\n    out[k].meses[c.mes] = (out[k].meses[c.mes] || 0) + (c.pedidos || 0);\n    if (!out[k].lojas[c.loja_nome]) out[k].lojas[c.loja_nome] = { canal: c.canal, meses: {} };\n    out[k].lojas[c.loja_nome].meses[c.mes] = (out[k].lojas[c.loja_nome].meses[c.mes] || 0) + (c.pedidos || 0);\n  });\n  return out;\n}\nfunction mesesOrdenados(d2) {\n  return Array.from(new Set(L(d2, 'clientemes').map(c => c.mes))).sort();\n}\nfunction diagnosticoCliente(meses, lista) {\n  const n = lista.length;\n  const atual = meses[lista[n - 1]] || 0;\n  const ant = meses[lista[n - 2]] || 0;\n  const base = [lista[n - 4], lista[n - 3], lista[n - 2]].map(m => meses[m] || 0);\n  const media = base.reduce((a, b) => a + b, 0) / 3;\n  const anoPassado = meses[lista[n - 13]] != null ? meses[lista[n - 13]] : null;\n  const anoPassadoAnt = meses[lista[n - 14]] != null ? meses[lista[n - 14]] : null;\n  if (atual === 0 && ant === 0) return { tag: 'evasao', rot: 'Evasao provavel', cls: 'ch-crit', txt: 'Sem envios ha 2 meses.' };\n  if (media > 0 && atual < media * 0.45) {\n    if (anoPassado != null && anoPassadoAnt != null && anoPassadoAnt > 0 && anoPassado < anoPassadoAnt * 0.6)\n      return { tag: 'sazonal', rot: 'Queda sazonal', cls: 'ch-info', txt: 'Caiu ' + pctS(media - atual, media, 0) + ', mas no mesmo mes do ano passado tambem caiu. Padrao sazonal.' };\n    return { tag: 'queda', rot: 'Queda anomala', cls: 'ch-crit', txt: 'Caiu ' + pctS(media - atual, media, 0) + ' contra a media dos 3 meses anteriores, sem padrao sazonal.' };\n  }\n  if (media > 0 && atual > media * 1.4) return { tag: 'cresce', rot: 'Crescendo', cls: 'ch-ok', txt: 'Subiu ' + pctS(atual - media, media, 0) + ' sobre a media dos 3 meses anteriores.' };\n  return { tag: 'ok', rot: 'Estavel', cls: 'ch-mute', txt: 'Volume dentro do padrao.' };\n}\nfunction metricasTerceiro(d2, usuario, funcao, dias) {\n  const agora = agoraDe(d2);\n  const corte = agora.getTime() - dias * 86400000;\n  let tot = 0, ok = 0, ruim = 0;\n  enriquece(d2).forEach(x => {\n    const r = x.r;\n    const chave = funcao === 'coletador' ? r.coletador_usuario : r.entregador_usuario;\n    if (chave !== usuario) return;\n    if (funcao === 'coletador') {\n      const c = dt(r.coletado_em), p = dt(r.coleta_prevista_em);\n      if (!c || c.getTime() > agora.getTime() || c.getTime() < corte) return;\n      tot++; if (p && c.getTime() <= p.getTime() + 30 * 60000) ok++; else ruim++;\n    } else {\n      if (x.e !== 'entregue_no_prazo' && x.e !== 'entregue_fora') return;\n      if (!x.ent || x.ent.getTime() < corte) return;\n      tot++; if (x.e === 'entregue_no_prazo') ok++; else ruim++;\n    }\n  });\n  const oc = L(d2, 'ocorrencia').filter(o => o.terceiro_usuario === usuario && dt(o.aberto_em) && dt(o.aberto_em).getTime() >= corte && dt(o.aberto_em).getTime() <= agora.getTime());\n  return { tot: tot, ok: ok, ruim: ruim, oc: oc.length, ocAbertas: oc.filter(o => o.situacao === 'aberta').length };\n}\n\n/* Autoteste: renderiza toda tela de todo perfil em memoria e reporta o que quebrar.\n   Usa um shim de state (nao toca em d2.state) para nao disparar re-render em loop. */\nconst CHAVES_STATE = ['dados', 'tema', 'relogio', 'horaReal', 'pedEstado', 'pedCliente', 'pedLoja', 'pedCanal', 'pedBusca', 'pedFuturos', 'cliOrdem', 'terFuncao', 'terDias', 'finStatus', 'cadTab', 'cadBusca', 'fxPonto', 'comComp', 'comAgrupar', 'vendedor'];\nfunction autoteste(d2, agora, VIEWS) {\n  const base = {};\n  CHAVES_STATE.forEach(k => { base[k] = d2.state[k]; });\n  const falhas = [];\n  Object.keys(PERFIS).forEach(p => {\n    PERFIS[p].menu.forEach(v => {\n      const shim = { state: Object.assign({}, base, { perfil: p, view: v }) };\n      try {\n        const html = VIEWS[v](shim, agora);\n        if (typeof html !== 'string' || !html.length) falhas.push(p + ' / ' + v + ': render vazio');\n      } catch (e) { falhas.push(p + ' / ' + v + ': ' + ((e && e.message) || e)); }\n    });\n  });\n  const DRAWERS = [\n    ['pedido', () => { const r = (base.dados.remessa || [])[0]; return r && dPedido({ state: base }, r.cod_remessa, agora); }],\n    ['cliente', () => { const c = (base.dados.cliente || [])[0]; return c && dCliente({ state: base }, c.cnpj_cpf, agora); }],\n    ['terceiro', () => { const t = (base.dados.terceiro || [])[0]; return t && dTerceiro({ state: base }, t.usuario, agora); }],\n    ['terceiro-form', () => dTerceiroForm({ state: base }, null, 'entregador')]\n  ];\n  DRAWERS.forEach(dw => { try { dw[1](); } catch (e) { falhas.push('drawer ' + dw[0] + ': ' + ((e && e.message) || e)); } });\n  return falhas;\n}\n\nexport default {\n  css: `\n:host, .app { display:block }\n.app{\n  --bg:#0d1218; --panel:#151d26; --panel2:#1b2531; --line:#26333f; --line2:#2f3f4d;\n  --ink:#e8eef5; --ink2:#9fb0c0; --ink3:#6b7d8d;\n  --ok:#3ecf8e; --ok-bg:#122a22; --warn:#f0b429; --warn-bg:#2b2313;\n  --crit:#f2604c; --crit-bg:#2c1a18; --info:#5aa2ff; --info-bg:#14202f;\n  --scrim:rgba(5,8,11,.72); --shadow:none;\n  position:relative; width:100%; height:100%; background:var(--bg); color:var(--ink);\n  font-family:\"IBM Plex Sans\",-apple-system,\"Segoe UI\",Roboto,sans-serif; font-size:14px;\n  display:flex; flex-direction:column; overflow:hidden;\n}\n.app.light{\n  --bg:#eef1f5; --panel:#fff; --panel2:#f4f7fa; --line:#dfe5ec; --line2:#c6d1dd;\n  --ink:#111a23; --ink2:#48596a; --ink3:#68798a;\n  --ok:#0c7048; --ok-bg:#e3f4ec; --warn:#8d5c05; --warn-bg:#fbf0d8;\n  --crit:#b53324; --crit-bg:#fbe5e1; --info:#2558bd; --info-bg:#e5ecfb;\n  --scrim:rgba(17,26,35,.42); --shadow:0 1px 2px rgba(17,26,35,.05);\n}\n.app{--c1:#5aa2ff;--c2:#3ecf8e;--c3:#f0b429;--c4:#f2604c;--c5:#a78bfa;--c6:#4dd0e1}\n.app.light{--c1:#2558bd;--c2:#0c7048;--c3:#8d5c05;--c4:#b53324;--c5:#6d4bc7;--c6:#0e7490}\n.app.light .panel,.app.light .card{box-shadow:var(--shadow)}\n.app.light .nav button.on{color:var(--info)} .app.light .seg button.on{color:var(--info)}\n.app *{box-sizing:border-box}\n.mono{font-family:\"IBM Plex Mono\",ui-monospace,Menlo,monospace;font-variant-numeric:tabular-nums}\n\n.top{display:flex;align-items:center;gap:18px;padding:10px 20px;border-bottom:1px solid var(--line);background:var(--panel);flex:none}\n.brand{display:flex;flex-direction:column;gap:1px;min-width:130px}\n.brand b{font-size:15px;letter-spacing:-.2px}\n.brand span{font-size:10px;color:var(--ink3);letter-spacing:.14em;text-transform:uppercase;font-family:\"IBM Plex Mono\",monospace}\n.nav{display:flex;gap:3px;flex:1;flex-wrap:wrap}\n.nav button{background:transparent;border:1px solid transparent;color:var(--ink2);padding:7px 13px;border-radius:4px;font:inherit;font-size:13px;cursor:pointer;white-space:nowrap}\n.nav button:hover{background:var(--panel2);color:var(--ink)}\n.nav button.on{background:var(--info-bg);border-color:var(--info);color:#cfe2ff}\n.nav button:focus-visible,.seg button:focus-visible,.btn:focus-visible,.inp:focus-visible{outline:2px solid var(--info);outline-offset:2px}\n.topright{display:flex;align-items:center;gap:10px}\n.relogio{text-align:right;font-size:10.5px;color:var(--ink3);font-family:\"IBM Plex Mono\",monospace;line-height:1.35}\n.relogio b{display:block;font-size:15px;color:var(--ink)}\n.temabtn{background:var(--panel2);border:1px solid var(--line2);color:var(--ink2);border-radius:3px;width:28px;height:28px;display:grid;place-items:center;font-size:13px;cursor:pointer;padding:0}\n.temabtn:hover{border-color:var(--info);color:var(--info)}\n.perfilsel{background:var(--panel2);border:1px solid var(--line2);color:var(--ink);border-radius:4px;padding:6px 9px;font:inherit;font-size:12.5px;cursor:pointer}\n\n.body{flex:1;overflow:auto;padding:18px 20px 40px}\n.h2{font-size:17px;font-weight:700;margin:0 0 3px}\n.sub{font-size:12.5px;color:var(--ink3);margin:0 0 15px;max-width:80ch}\n.grid{display:grid;gap:12px}\n.g4{grid-template-columns:repeat(4,1fr)} .g3{grid-template-columns:repeat(3,1fr)} .g2{grid-template-columns:1fr 1fr}\n@media (max-width:1100px){.g4{grid-template-columns:repeat(2,1fr)}.g3,.g2{grid-template-columns:1fr}}\n\n.card{background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:14px 16px;border-left-width:3px}\n.card .n{font-size:32px;font-weight:800;line-height:1;letter-spacing:-1px}\n.card .l{font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink2);margin-top:7px;font-family:\"IBM Plex Mono\",monospace}\n.card .x{font-size:11px;color:var(--ink3);margin-top:4px}\n.c-ok{border-left-color:var(--ok)} .c-ok .n{color:var(--ok)}\n.c-warn{border-left-color:var(--warn)} .c-warn .n{color:var(--warn)}\n.c-crit{border-left-color:var(--crit)} .c-crit .n{color:var(--crit)}\n.c-info{border-left-color:var(--info)} .c-info .n{color:var(--info)}\n\n.panel{background:var(--panel);border:1px solid var(--line);border-radius:6px;overflow:hidden}\n.panel h3{margin:0;padding:11px 15px;font-size:11.5px;letter-spacing:.11em;text-transform:uppercase;color:var(--ink2);border-bottom:1px solid var(--line);font-family:\"IBM Plex Mono\",monospace;font-weight:600;display:flex;justify-content:space-between;align-items:center;gap:10px}\n.panel h3 em{font-style:normal;color:var(--ink3);letter-spacing:0;text-transform:none;font-size:11.5px;font-family:\"IBM Plex Sans\",sans-serif}\n.scroll{overflow-x:auto}\ntable{width:100%;border-collapse:collapse}\nth{font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink3);text-align:left;padding:8px 12px;border-bottom:1px solid var(--line);font-weight:600;font-family:\"IBM Plex Mono\",monospace;white-space:nowrap}\ntd{padding:9px 12px;border-bottom:1px solid var(--line);font-size:12.5px;vertical-align:middle}\ntr:last-child td{border-bottom:0}\ntbody tr.sel:hover{background:var(--panel2);cursor:pointer}\n.num{text-align:right;font-family:\"IBM Plex Mono\",monospace;font-variant-numeric:tabular-nums}\n.tiny{font-size:10.5px;color:var(--ink3)} .strong{font-weight:600}\n.chip{display:inline-block;font-size:9.5px;letter-spacing:.07em;text-transform:uppercase;padding:2px 6px;border-radius:3px;font-family:\"IBM Plex Mono\",monospace;font-weight:600;white-space:nowrap}\n.ch-ok{background:var(--ok-bg);color:var(--ok);border:1px solid var(--ok)}\n.ch-warn{background:var(--warn-bg);color:var(--warn);border:1px solid var(--warn)}\n.ch-crit{background:var(--crit-bg);color:var(--crit);border:1px solid var(--crit)}\n.ch-info{background:var(--info-bg);color:var(--info);border:1px solid var(--info)}\n.ch-mute{background:var(--panel2);color:var(--ink3);border:1px solid var(--line2)}\n.lojachips{display:flex;gap:3px;flex-wrap:wrap}\n\n.toolbar{display:flex;gap:7px;align-items:center;margin-bottom:12px;flex-wrap:wrap}\n.seg{display:inline-flex;border:1px solid var(--line2);border-radius:4px;overflow:hidden}\n.seg button{background:transparent;border:0;color:var(--ink2);padding:6px 11px;font:inherit;font-size:12px;cursor:pointer}\n.seg button.on{background:var(--info-bg);color:#cfe2ff}\n.spacer{flex:1}\n.inp{background:var(--panel2);border:1px solid var(--line2);color:var(--ink);border-radius:4px;padding:6px 9px;font:inherit;font-size:12.5px;min-width:140px}\nselect.inp{cursor:pointer}\n.btn{background:var(--panel2);border:1px solid var(--line2);color:var(--ink);padding:6px 11px;border-radius:4px;font:inherit;font-size:12.5px;cursor:pointer}\n.btn:hover{border-color:var(--info)}\n.btn-ok{background:var(--ok-bg);border-color:var(--ok);color:var(--ok)}\n.btn-crit{background:var(--crit-bg);border-color:var(--crit);color:var(--crit)}\n\n.spark{display:flex;align-items:flex-end;gap:2px;height:38px}\n.spark i{flex:1;background:var(--info);border-radius:1px;min-height:2px;opacity:.75}\n.spark i.last{background:var(--ok);opacity:1}\n.spark i.down{background:var(--crit);opacity:1}\n.chartbox{padding:14px 16px}\n.bh{display:grid;grid-template-columns:1.1fr 2fr auto;gap:10px;align-items:center;padding:5px 0}\n.bh-l{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.bh-l small{display:block;font-size:10px;color:var(--ink3)}\n.bh-t{background:var(--panel2);border-radius:3px;height:16px;overflow:hidden;display:block}\n.bh-t i{display:block;height:100%;border-radius:3px;min-width:2px}\n.bh-v{font-family:\"IBM Plex Mono\",monospace;font-size:12px;font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap}\n.dnt{display:flex;align-items:center;gap:16px;padding:14px 16px}\n.dnt svg{flex:none;width:104px;height:104px}\n.dnt .leg{flex:1;display:flex;flex-direction:column;gap:5px;min-width:0}\n.dnt .leg > div{display:grid;grid-template-columns:10px 1fr auto;gap:8px;align-items:center;font-size:12px}\n.dnt .leg b{width:10px;height:10px;border-radius:2px;display:block}\n.dnt .leg span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dnt .leg em{font-style:normal;font-family:\"IBM Plex Mono\",monospace;font-size:11.5px;color:var(--ink2)}\n.fun{padding:14px 16px;display:flex;flex-direction:column;gap:7px}\n.fun .st{display:grid;grid-template-columns:132px 1fr auto;gap:10px;align-items:center}\n.fun .st .bar{background:var(--panel2);border-radius:3px;height:22px;overflow:hidden}\n.fun .st .bar i{display:block;height:100%;border-radius:3px;min-width:3px}\n.fun .st .lb{font-size:12px}\n.fun .st .vl{font-family:\"IBM Plex Mono\",monospace;font-size:12px;text-align:right}\n.eixo{display:flex;justify-content:space-between;padding:0 16px 12px;font-size:10px;color:var(--ink3);font-family:\"IBM Plex Mono\",monospace}\n.bars{display:flex;align-items:flex-end;gap:3px;height:130px;padding:12px 14px}\n.bars .w{flex:1;height:100%;display:flex;align-items:flex-end}\n.bars .b{width:100%;background:var(--ok);border-radius:2px 2px 0 0;min-height:2px}\n.bars .b.miss{background:var(--crit)}\n\n.drawer{position:absolute;inset:0;display:flex;justify-content:flex-end;z-index:20}\n.drawer .backdrop{position:absolute;inset:0;background:var(--scrim)}\n.drawer .sheet{position:relative;z-index:1;width:min(680px,94%);background:var(--panel);border-left:1px solid var(--line2);height:100%;overflow:auto;padding:20px 22px}\n.drawer h4{margin:0 0 4px;font-size:17px}\n.drawer .close{position:absolute;top:12px;right:16px;background:transparent;border:0;color:var(--ink2);font-size:22px;cursor:pointer;line-height:1}\n.kv{display:grid;grid-template-columns:140px 1fr;gap:6px 12px;font-size:12.5px;margin:14px 0}\n.kv dt{color:var(--ink3);font-size:10px;letter-spacing:.08em;text-transform:uppercase;font-family:\"IBM Plex Mono\",monospace;padding-top:2px}\n.kv dd{margin:0}\n.fgrid{display:grid;grid-template-columns:1fr 1fr;gap:11px 12px;margin:14px 0}\n.fitem{display:flex;flex-direction:column;gap:4px} .fitem.w2{grid-column:span 2}\n.fitem label{font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink3);font-family:\"IBM Plex Mono\",monospace}\n.fitem .inp{width:100%;min-width:0}\n\n.tl{list-style:none;margin:12px 0 0;padding:0}\n.tl li{position:relative;padding:0 0 14px 20px;border-left:1px solid var(--line2)}\n.tl li:last-child{border-left-color:transparent;padding-bottom:0}\n.tl li::before{content:'';position:absolute;left:-5px;top:3px;width:9px;height:9px;border-radius:50%;background:var(--ink3);border:2px solid var(--panel)}\n.tl li.done::before{background:var(--ok)} .tl li.futuro::before{background:var(--line2)} .tl li.bad::before{background:var(--crit)}\n.tl .t{font-size:12.5px;font-weight:600} .tl .d{font-size:11px;color:var(--ink3);margin-top:1px}\n.tl li.futuro .t{color:var(--ink3);font-weight:400}\n.note{background:var(--panel2);border:1px solid var(--line2);border-left:3px solid var(--info);border-radius:4px;padding:11px 13px;font-size:12.5px;color:var(--ink2);line-height:1.5}\n.note b{color:var(--ink)}\n.note.warn{border-left-color:var(--warn)} .note.crit{border-left-color:var(--crit)}\n.origem{font-size:10.5px;color:var(--ink3);font-family:\"IBM Plex Mono\",monospace;margin-top:14px;padding-top:10px;border-top:1px solid var(--line)}\n.center{display:flex;align-items:center;justify-content:center;height:100%;color:var(--ink3)}\n.vazio{padding:26px 14px;text-align:center;color:var(--ink3);font-size:12.5px}\n`,\n\n  render(d2) {\n    const tema = d2.state.tema === 'light' ? 'light' : '';\n    if (d2.state.erro) return `<div class=\"app ${tema}\"><div class=\"center\"><div style=\"max-width:640px;color:var(--crit);line-height:1.6\"><b>Nao consegui carregar os dados.</b><br>${esc(d2.state.erro)}</div></div></div>`;\n    if (!d2.state.ready) return `<div class=\"app ${tema}\"><div class=\"center\">Carregando a operacao...</div></div>`;\n    const perfil = d2.state.perfil || 'admin';\n    const menu = PERFIS[perfil].menu;\n    let view = d2.state.view || 'inicio';\n    if (menu.indexOf(view) < 0) view = menu[0];\n    const agora = agoraDe(d2);\n    const VIEWS = { inicio: vInicio, fluxo: vFluxo, pedidos: vPedidos, clientes: vClientes, terceiros: vTerceiros, financeiro: vFinanceiro, comissoes: vComissoes, cadastros: vCadastros, vendedor: vVendedor };\n    if (d2.state.selftest == null && d2.state.dados) {\n      try { d2.state.selftest = autoteste(d2, agora, VIEWS); } catch (e) { d2.state.selftest = ['autoteste: ' + ((e && e.message) || e)]; }\n    }\n    const falhas = d2.state.selftest || [];\n    const aviso = falhas.length ? `<div class=\"note crit\" style=\"margin-bottom:12px\"><b>Autoteste encontrou ${falhas.length} tela(s) com erro:</b><br>${falhas.map(f => esc(f)).join('<br>')}</div>` : '';\n    let corpo = '';\n    try { corpo = VIEWS[view](d2, agora); }\n    catch (e) { corpo = `<div class=\"note crit\"><b>Erro ao montar a tela ${esc(view)}.</b><br>${esc(e && e.message)}</div>`; }\n    return `<div class=\"app ${tema}\">\n      ${topo(d2, agora, view, perfil, menu)}\n      <div class=\"body\">${aviso}${corpo}</div>\n      ${drawer(d2, agora)}\n    </div>`;\n  },\n\n  mounted(d2) {\n    let tema = 'dark';\n    try { const s = window.localStorage.getItem('ctm-tema'); if (s === 'light' || s === 'dark') tema = s; else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) tema = 'light'; } catch (e) { }\n    d2.state.tema = tema;\n    d2.state.perfil = 'admin';\n    d2.state.view = 'inicio';\n    d2.state.pedEstado = 'abertos';\n    d2.state.pedCliente = 'todos';\n    d2.state.pedLoja = 'todas';\n    d2.state.pedCanal = 'todos';\n    d2.state.pedBusca = '';\n    d2.state.pedFuturos = false;\n    d2.state.cliOrdem = 'atencao';\n    d2.state.terFuncao = 'entregador';\n    d2.state.terDias = 30;\n    d2.state.finStatus = 'todas';\n    d2.state.cadTab = 'clientes';\n    d2.state.cadBusca = '';\n    d2.state.fxPonto = 'todos';\n    d2.state.comComp = '';\n    d2.state.comAgrupar = 'beneficiario';\n    d2.state.vendedor = '';\n\n    recarrega(d2).then(() => { d2.state.ready = true; })\n      .catch(e => { d2.state.erro = (e && e.message) ? e.message : String(e); });\n\n    const t = setInterval(() => { d2.state.relogio = new Date(); }, 30000);\n    d2.onUnmount(() => clearInterval(t));\n\n    const on = (sel, ev, fn) => d2.on(sel, ev, fn);\n    const sm = (sel, key, attr) => on('[' + sel + ']', 'click', e => { const el = e.target.closest('[' + sel + ']'); if (el) d2.state[key] = el.dataset[attr]; });\n\n    sm('data-view', 'view', 'view');\n    sm('data-pedestado', 'pedEstado', 'pedestado');\n    sm('data-cliordem', 'cliOrdem', 'cliordem');\n    sm('data-terfuncao', 'terFuncao', 'terfuncao');\n    sm('data-finstatus', 'finStatus', 'finstatus');\n    sm('data-cadtab', 'cadTab', 'cadtab');\n    on('[data-terdias]', 'click', e => { const el = e.target.closest('[data-terdias]'); if (el) d2.state.terDias = Number(el.dataset.terdias); });\n    on('[data-perfil]', 'change', e => { d2.state.perfil = e.target.value; d2.state.view = PERFIS[e.target.value].menu[0]; });\n    on('[data-tema]', 'click', () => { const n = d2.state.tema === 'light' ? 'dark' : 'light'; d2.state.tema = n; try { window.localStorage.setItem('ctm-tema', n); } catch (e) { } });\n    on('[data-pedcliente]', 'change', e => { d2.state.pedCliente = e.target.value; d2.state.pedLoja = 'todas'; });\n    on('[data-pedloja]', 'change', e => { d2.state.pedLoja = e.target.value; });\n    on('[data-pedcanal]', 'change', e => { d2.state.pedCanal = e.target.value; });\n    on('[data-pedbusca]', 'input', e => { d2.state.pedBusca = e.target.value; });\n    on('[data-pedfuturos]', 'click', () => { d2.state.pedFuturos = !d2.state.pedFuturos; });\n    on('[data-cadbusca]', 'input', e => { d2.state.cadBusca = e.target.value; });\n    on('[data-fxponto]', 'change', e => { d2.state.fxPonto = e.target.value; });\n    on('[data-comcomp]', 'change', e => { d2.state.comComp = e.target.value; });\n    on('[data-comagrupar]', 'click', e => { const el = e.target.closest('[data-comagrupar]'); if (el) d2.state.comAgrupar = el.dataset.comagrupar; });\n    on('[data-paga-com]', 'click', async e => {\n      const el = e.target.closest('[data-paga-com]'); if (!el) return;\n      const comp = el.dataset.pagaCom, ben = el.dataset.ben;\n      const alvos = L(d2, 'comissao').filter(x => x.competencia === comp && x.beneficiario === ben && !x.pago_em);\n      if (!alvos.length) return;\n      const tot = alvos.reduce((s, x) => s + (x.valor || 0), 0);\n      const ok = await d2.dialog.confirm('Registrar pagamento de ' + brl(tot) + ' para ' + ben + ' (competencia ' + comp + ', ' + alvos.length + ' cliente(s))?');\n      if (!ok) return;\n      el.disabled = true; el.textContent = 'pagando...';\n      const hoje = new Date(); const iso = hoje.getFullYear() + '-' + String(hoje.getMonth() + 1).padStart(2, '0') + '-' + String(hoje.getDate()).padStart(2, '0');\n      try {\n        for (let i = 0; i < alvos.length; i++) await d2.rush('act-comissao').invoke({ registro: { _id: alvos[i]._id, pago_em: iso, pago_por: 'financeiro.tm' } });\n        await recarrega(d2);\n      } catch (err) { d2.dialog.alert('Erro: ' + ((err && err.message) || err)); d2.state.relogio = new Date(); }\n    });\n    on('[data-estorna-com]', 'click', async e => {\n      const el = e.target.closest('[data-estorna-com]'); if (!el) return;\n      const alvos = L(d2, 'comissao').filter(x => x.competencia === el.dataset.estornaCom && x.beneficiario === el.dataset.ben && x.pago_em);\n      const ok = await d2.dialog.confirm('Estornar o pagamento de ' + el.dataset.ben + '?'); if (!ok) return;\n      el.disabled = true;\n      try {\n        for (let i = 0; i < alvos.length; i++) await d2.rush('act-comissao').invoke({ registro: { _id: alvos[i]._id, pago_em: '', pago_por: '' } });\n        await recarrega(d2);\n      } catch (err) { d2.dialog.alert('Erro: ' + ((err && err.message) || err)); d2.state.relogio = new Date(); }\n    });\n    on('[data-troca-coletador]', 'click', async e => {\n      const el = e.target.closest('[data-troca-coletador]'); if (!el) return;\n      const cnpj = el.dataset.trocaColetador;\n      const cols = L(d2, 'terceiro').filter(t => t.funcao === 'coletador' && t.situacao === 'ativo');\n      const nomes = cols.map((c, i) => (i + 1) + ') ' + c.nome).join('\\n');\n      const esc0 = await d2.dialog.prompt('Reatribuir a coleta deste cliente. Digite o numero do coletador:\\n' + nomes, '1');\n      const idx = Number(esc0) - 1;\n      if (!(idx >= 0 && idx < cols.length)) return;\n      const novo = cols[idx];\n      const agora = agoraDe(d2);\n      const alvos = L(d2, 'remessa').filter(r => r.cliente_cnpj === cnpj && r.origem === 'coleta' && dt(r.criado_em) && dt(r.criado_em) <= agora && (!dt(r.coletado_em) || dt(r.coletado_em) > agora));\n      el.disabled = true; el.textContent = 'salvando...';\n      try {\n        for (let i = 0; i < alvos.length; i++) {\n          await d2.rush('act-remessa').invoke({ registro: { _id: alvos[i]._id, coletador_usuario: novo.usuario, coletador_nome: novo.nome } });\n        }\n        await recarrega(d2);\n      } catch (err) { d2.dialog.alert('Erro: ' + ((err && err.message) || err)); d2.state.relogio = new Date(); }\n    });\n    on('[data-fecha]', 'click', () => { d2.state.drawer = null; });\n    on('[data-abre-pedido]', 'click', e => { const el = e.target.closest('[data-abre-pedido]'); if (el) d2.state.drawer = { tipo: 'pedido', id: el.dataset.abrePedido }; });\n    on('[data-abre-cliente]', 'click', e => { const el = e.target.closest('[data-abre-cliente]'); if (el) d2.state.drawer = { tipo: 'cliente', id: el.dataset.abreCliente }; });\n    on('[data-abre-terceiro]', 'click', e => { const el = e.target.closest('[data-abre-terceiro]'); if (el) d2.state.drawer = { tipo: 'terceiro', id: el.dataset.abreTerceiro }; });\n    on('[data-edita-terceiro]', 'click', e => { const el = e.target.closest('[data-edita-terceiro]'); if (el) d2.state.drawer = { tipo: 'terceiro-form', id: el.dataset.editaTerceiro }; });\n    on('[data-novo-terceiro]', 'click', e => { const el = e.target.closest('[data-novo-terceiro]'); d2.state.drawer = { tipo: 'terceiro-form', funcao: el.dataset.novoTerceiro }; });\n    on('[data-ir]', 'click', e => {\n      const el = e.target.closest('[data-ir]'); if (!el) return;\n      d2.state.view = el.dataset.ir;\n      if (el.dataset.filtro) d2.state.pedEstado = el.dataset.filtro;\n      if (el.dataset.cliente) { d2.state.pedCliente = el.dataset.cliente; d2.state.pedLoja = 'todas'; d2.state.pedEstado = 'todos'; }\n      d2.state.drawer = null;\n    });\n    on('[data-vend]', 'change', e => { d2.state.vendedor = e.target.value; });\n\n    on('[data-baixa]', 'click', async e => {\n      const el = e.target.closest('[data-baixa]'); if (!el) return;\n      const f = L(d2, 'fatura').find(x => x._id === el.dataset.baixa); if (!f) return;\n      const ok = await d2.dialog.confirm('Confirmar baixa de ' + brl(f.valor) + ' — ' + f.cliente_nome + ' (' + f.quinzena + ')?');\n      if (!ok) return;\n      el.disabled = true; el.textContent = 'baixando...';\n      const hoje = new Date(); const iso = hoje.getFullYear() + '-' + String(hoje.getMonth() + 1).padStart(2, '0') + '-' + String(hoje.getDate()).padStart(2, '0');\n      try { await d2.rush('act-fatura').invoke({ registro: { _id: f._id, status: 'paga', pago_em: iso, baixa_por: 'financeiro.tm' } }); await recarrega(d2); }\n      catch (err) { d2.dialog.alert('Nao consegui dar baixa: ' + ((err && err.message) || err)); d2.state.relogio = new Date(); }\n    });\n    on('[data-estorna]', 'click', async e => {\n      const el = e.target.closest('[data-estorna]'); if (!el) return;\n      const ok = await d2.dialog.confirm('Estornar a baixa desta fatura?'); if (!ok) return;\n      el.disabled = true;\n      try { await d2.rush('act-fatura').invoke({ registro: { _id: el.dataset.estorna, status: 'aberta', pago_em: '', baixa_por: '' } }); await recarrega(d2); }\n      catch (err) { d2.dialog.alert('Erro: ' + ((err && err.message) || err)); d2.state.relogio = new Date(); }\n    });\n    on('[data-bloqueia]', 'click', async e => {\n      const el = e.target.closest('[data-bloqueia]'); if (!el) return;\n      const t3 = L(d2, 'terceiro').find(x => x.usuario === el.dataset.bloqueia); if (!t3) return;\n      const bloq = t3.situacao !== 'bloqueado';\n      let motivo = '';\n      if (bloq) { motivo = await d2.dialog.prompt('Motivo do bloqueio de ' + t3.nome + ':', 'Reincidencia de ocorrencias'); if (!motivo) return; }\n      else { const ok = await d2.dialog.confirm('Desbloquear ' + t3.nome + '?'); if (!ok) return; }\n      el.disabled = true; el.textContent = '...';\n      const hoje = new Date().toISOString().slice(0, 16);\n      try {\n        await d2.rush('act-terceiro').invoke({ registro: { _id: t3._id, situacao: bloq ? 'bloqueado' : 'ativo', motivo_bloqueio: bloq ? motivo : '', bloqueado_em: bloq ? hoje : '', bloqueado_por: bloq ? 'luan.marins' : '' } });\n        await recarrega(d2);\n      } catch (err) { d2.dialog.alert('Erro: ' + ((err && err.message) || err)); d2.state.relogio = new Date(); }\n    });\n    on('[data-salva-terceiro]', 'click', async e => {\n      const el = e.target.closest('[data-salva-terceiro]');\n      const dw = d2.state.drawer || {};\n      const reg = { funcao: val(d2, 'ft-funcao'), nome: val(d2, 'ft-nome'), usuario: val(d2, 'ft-usuario'), telefone: val(d2, 'ft-tel'), equipe: val(d2, 'ft-equipe'), coordenador: val(d2, 'ft-coord'), veiculo: val(d2, 'ft-veiculo'), ponto_coleta: val(d2, 'ft-ponto'), situacao: val(d2, 'ft-sit') || 'ativo' };\n      if (!reg.nome || !reg.usuario) { d2.dialog.alert('Nome e usuario sao obrigatorios.'); return; }\n      if (dw.id) { const rec = L(d2, 'terceiro').find(x => x.usuario === dw.id); if (rec) reg._id = rec._id; }\n      else { reg.motivo_bloqueio = ''; reg.bloqueado_em = ''; reg.bloqueado_por = ''; }\n      el.disabled = true; el.textContent = 'salvando...';\n      try { await d2.rush('act-terceiro').invoke({ registro: reg }); await recarrega(d2); d2.state.drawer = { tipo: 'terceiro', id: reg.usuario }; }\n      catch (err) { d2.dialog.alert('Erro: ' + ((err && err.message) || err)); d2.state.relogio = new Date(); }\n    });\n    on('[data-resolve-oc]', 'click', async e => {\n      const el = e.target.closest('[data-resolve-oc]'); if (!el) return;\n      el.disabled = true; el.textContent = '...';\n      const hoje = new Date().toISOString().slice(0, 16);\n      try { await d2.rush('act-ocorrencia').invoke({ registro: { _id: el.dataset.resolveOc, situacao: el.dataset.sit, resolvido_em: hoje, resolvido_por: 'luan.marins' } }); await recarrega(d2); }\n      catch (err) { d2.dialog.alert('Erro: ' + ((err && err.message) || err)); d2.state.relogio = new Date(); }\n    });\n  }\n};\n\n/* ---------- topo ---------- */\nfunction topo(d2, agora, view, perfil, menu) {\n  const dias = ['dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sab'];\n  const fimSeed = new Date('2026-09-30T23:59');\n  const velho = agora.getTime() > fimSeed.getTime();\n  return `<div class=\"top\">\n    <div class=\"brand\"><b>Central TM</b><span>TM Logistica</span></div>\n    <div class=\"nav\">${menu.map(k => `<button data-view=\"${k}\" class=\"${view === k ? 'on' : ''}\">${TITULO[k]}</button>`).join('')}</div>\n    <div class=\"topright\">\n      ${velho ? '<span class=\"chip ch-warn\" title=\"A base simulada vai ate 30/09/2026\">base vencida</span>' : ''}\n      <select class=\"perfilsel\" data-perfil>${Object.keys(PERFIS).map(k => opt(k, perfil, PERFIS[k].nome)).join('')}</select>\n      <div class=\"relogio\"><b>${hhmm(agora)}</b>${dias[agora.getDay()]} ${ddmm(agora)}</div>\n      <button class=\"temabtn\" data-tema title=\"Alternar tema\">${d2.state.tema === 'light' ? '☽' : '☀'}</button>\n    </div>\n  </div>`;\n}\nfunction card(cls, n, l, x) { return `<div class=\"card ${cls}\"><div class=\"n mono\">${n}</div><div class=\"l\">${l}</div><div class=\"x\">${x || ''}</div></div>`; }\n\n/* ---------- kit de graficos ---------- */\nfunction pnl(titulo, extra, corpo, rodape) {\n  return `<div class=\"panel\"><h3>${titulo}${extra ? ' <em>' + extra + '</em>' : ''}</h3>${corpo}${rodape ? '<div class=\"eixo\">' + rodape + '</div>' : ''}</div>`;\n}\nfunction barsH(itens, opts) {\n  const o = opts || {};\n  const max = Math.max.apply(null, itens.map(i => i.v).concat([1]));\n  if (!itens.length) return '<div class=\"vazio\">Sem dados no periodo.</div>';\n  return '<div class=\"chartbox\">' + itens.map((i, k) => `<div class=\"bh\" data-key=\"${esc(i.l)}\">\n    <span class=\"bh-l\">${esc(i.l)}${i.sub ? '<small>' + esc(i.sub) + '</small>' : ''}</span>\n    <span class=\"bh-t\"><i style=\"width:${(i.v / max * 100).toFixed(1)}%;background:${i.cor || (o.cor || CORES[k % 6])}\"></i></span>\n    <span class=\"bh-v\">${i.rot != null ? i.rot : num(i.v)}</span>\n  </div>`).join('') + '</div>';\n}\nfunction donut(itens) {\n  const tot = itens.reduce((s, i) => s + i.v, 0);\n  if (!tot) return '<div class=\"vazio\">Sem dados no periodo.</div>';\n  const r = 40, C = 2 * Math.PI * r;\n  let acc = 0;\n  const segs = itens.map((i, k) => {\n    const f = i.v / tot;\n    const seg = `<circle cx=\"50\" cy=\"50\" r=\"${r}\" fill=\"none\" stroke=\"${i.cor || CORES[k % 6]}\" stroke-width=\"15\" stroke-dasharray=\"${(f * C).toFixed(2)} ${(C - f * C).toFixed(2)}\" stroke-dashoffset=\"${(-acc * C).toFixed(2)}\" transform=\"rotate(-90 50 50)\"/>`;\n    acc += f; return seg;\n  }).join('');\n  return `<div class=\"dnt\"><svg viewBox=\"0 0 100 100\" role=\"img\" aria-label=\"distribuicao\">${segs}\n    <text x=\"50\" y=\"53\" text-anchor=\"middle\" font-size=\"15\" font-weight=\"700\" fill=\"currentColor\" font-family=\"IBM Plex Mono, monospace\">${num(tot)}</text></svg>\n    <div class=\"leg\">${itens.map((i, k) => `<div data-key=\"${esc(i.l)}\"><b style=\"background:${i.cor || CORES[k % 6]}\"></b><span>${esc(i.l)}</span><em>${num(i.v)} &middot; ${((i.v / tot) * 100).toFixed(0)}%</em></div>`).join('')}</div></div>`;\n}\nfunction barsV(itens, opts) {\n  const o = opts || {};\n  if (!itens.length) return '<div class=\"vazio\">Sem dados no periodo.</div>';\n  const vals = itens.map(i => i.v);\n  const max = o.max != null ? o.max : Math.max.apply(null, vals.concat([1]));\n  const min = o.min != null ? o.min : 0;\n  return `<div class=\"bars\" style=\"height:${o.h || 130}px\">${itens.map(i => {\n    const h = Math.max(3, Math.min(100, ((i.v - min) / (max - min)) * 100));\n    return `<div class=\"w\" title=\"${esc(i.l)}: ${i.rot != null ? i.rot : num(i.v)}\"><div class=\"b ${i.mau ? 'miss' : ''}\" style=\"height:${h}%${i.cor ? ';background:' + i.cor : ''}\"></div></div>`;\n  }).join('')}</div>`;\n}\nfunction funil(passos) {\n  const max = Math.max.apply(null, passos.map(p => p.v).concat([1]));\n  return '<div class=\"fun\">' + passos.map((p, k) => `<div class=\"st\" data-key=\"${esc(p.l)}\">\n    <span class=\"lb\">${esc(p.l)}</span>\n    <span class=\"bar\"><i style=\"width:${(p.v / max * 100).toFixed(1)}%;background:${CORES[k % 6]}\"></i></span>\n    <span class=\"vl\">${num(p.v)}</span></div>`).join('') + '</div>';\n}\nfunction topN(mapa, n, fmtRot) {\n  return Object.keys(mapa).map(k => ({ l: k, v: mapa[k] })).sort((a, b) => b.v - a.v).slice(0, n)\n    .map(i => fmtRot ? Object.assign(i, { rot: fmtRot(i.v) }) : i);\n}\nfunction contaPor(arr, fn) {\n  const m = {}; arr.forEach(x => { const k = fn(x); if (k != null && k !== '') m[k] = (m[k] || 0) + 1; }); return m;\n}\nfunction somaPor(arr, fk, fv) {\n  const m = {}; arr.forEach(x => { const k = fk(x); if (k != null && k !== '') m[k] = (m[k] || 0) + (fv(x) || 0); }); return m;\n}\n\n/* ---------- INICIO: dashboards por perfil ---------- */\nfunction ctxDash(d2, agora) {\n  const t = agora.getTime();\n  const linhas = enriquece(d2);\n  const hojeStr = agora.getFullYear() + '-' + String(agora.getMonth() + 1).padStart(2, '0') + '-' + String(agora.getDate()).padStart(2, '0');\n  const kpi = L(d2, 'kpidiario').filter(k => k.dia <= hojeStr).sort((a, b) => a.dia < b.dia ? -1 : 1);\n  const kHoje = kpi.filter(k => k.dia === hojeStr)[0] || null;\n  const mes = kpi.filter(k => k.dia.slice(0, 7) === hojeStr.slice(0, 7));\n  const mEnt = mes.reduce((s, k) => s + (k.entregues || 0), 0);\n  const mOk = mes.reduce((s, k) => s + (k.no_prazo || 0), 0);\n  const abertos = linhas.filter(x => ABERTOS.indexOf(x.e) >= 0 && x.e !== 'agendado');\n  const prob = abertos.filter(x => PROBLEMA.indexOf(x.e) >= 0);\n  const d30 = t - 30 * 86400000;\n  const recentes = linhas.filter(x => { const c = dt(x.r.criado_em); return c && c.getTime() <= t && c.getTime() >= d30; });\n  const entregues30 = linhas.filter(x => x.ent && x.ent.getTime() <= t && x.ent.getTime() >= d30);\n  const mm = porMesCliente(d2), lista = mesesOrdenados(d2);\n  const diag = Object.keys(mm).map(k => ({ cnpj: k, nome: mm[k].nome, d: diagnosticoCliente(mm[k].meses, lista), atual: mm[k].meses[lista[lista.length - 1]] || 0 }));\n  const ocs = L(d2, 'ocorrencia');\n  const ocAbertas = ocs.filter(o => o.situacao === 'aberta');\n  const naColeta = L(d2, 'remessa').filter(r => r.origem === 'coleta' && dt(r.criado_em) && dt(r.criado_em).getTime() <= t && (!dt(r.coletado_em) || dt(r.coletado_em).getTime() > t));\n  const noPonto = L(d2, 'remessa').filter(r => { const g = dt(r.galpao_em), ro = dt(r.rota_em); return g && g.getTime() <= t && (!ro || ro.getTime() > t); });\n  return { t, linhas, hojeStr, kpi, kHoje, mes, mEnt, mOk, abertos, prob, recentes, entregues30, mm, lista, diag, ocs, ocAbertas, naColeta, noPonto };\n}\nfunction graficoSla(c) {\n  const ult = c.kpi.slice(-30);\n  return pnl('SLA por dia', 'ultimos ' + ult.length + ' dias &middot; meta 99,6%',\n    barsV(ult.map(k => { const p = (k.no_prazo / k.entregues) * 100; return { l: k.dia.slice(8) + '/' + k.dia.slice(5, 7), v: p, rot: p.toFixed(2) + '%', mau: p < META }; }), { min: 98.5, max: 100, h: 130 }),\n    'escala 98,5% a 100% &middot; barra vermelha = abaixo da meta');\n}\nfunction graficoVolume(c) {\n  const ult = c.kpi.slice(-30);\n  return pnl('Volume diario', 'pedidos recebidos na operacao',\n    barsV(ult.map(k => ({ l: k.dia.slice(8) + '/' + k.dia.slice(5, 7), v: k.pedidos, cor: 'var(--c1)' })), { h: 130 }),\n    (ult[0] ? ult[0].dia.slice(8) + '/' + ult[0].dia.slice(5, 7) : '') + ' &rarr; hoje &middot; media ' + num(Math.round(ult.reduce((s, k) => s + k.pedidos, 0) / (ult.length || 1))) + '/dia');\n}\nfunction graficoFunil(c) {\n  const est = {}; c.linhas.forEach(x => est[x.e] = (est[x.e] || 0) + 1);\n  const criados = c.linhas.filter(x => x.e !== 'agendado').length;\n  const passos = [\n    { l: 'Criados', v: criados },\n    { l: 'Coletados', v: criados - c.naColeta.length },\n    { l: 'No ponto / rota', v: (est.no_galpao || 0) + (est.em_rota || 0) + (est.em_risco || 0) + (est.vai_estourar || 0) + (est.estourado || 0) + (est.entregue_no_prazo || 0) + (est.entregue_fora || 0) },\n    { l: 'Entregues', v: (est.entregue_no_prazo || 0) + (est.entregue_fora || 0) },\n    { l: 'No prazo', v: (est.entregue_no_prazo || 0) }\n  ];\n  return pnl('Funil da base em acompanhamento', num(criados) + ' pedidos ja iniciados', funil(passos),\n    'da criacao ate a entrega no prazo &middot; base detalhada, nao a operacao completa');\n}\nfunction graficoCanal(c) {\n  return pnl('Pedidos por canal', 'ultimos 30 dias', donut(topN(contaPor(c.recentes, x => x.r.canal), 6)));\n}\nfunction graficoRegiao(c) {\n  const porReg = contaPor(c.recentes, x => x.r.regiao);\n  const okReg = {}; const totReg = {};\n  c.entregues30.forEach(x => { totReg[x.r.regiao] = (totReg[x.r.regiao] || 0) + 1; if (x.e === 'entregue_no_prazo') okReg[x.r.regiao] = (okReg[x.r.regiao] || 0) + 1; });\n  const itens = Object.keys(porReg).map(k => {\n    const p = totReg[k] ? (okReg[k] || 0) / totReg[k] * 100 : null;\n    return { l: k, v: porReg[k], sub: p == null ? '' : p.toFixed(1).replace('.', ',') + '% no prazo', cor: p != null && p < 95 ? 'var(--c4)' : 'var(--c1)' };\n  }).sort((a, b) => b.v - a.v);\n  return pnl('Volume por regiao', 'ultimos 30 dias', barsH(itens));\n}\nfunction graficoOcorrencias(c) {\n  const m = contaPor(c.ocs, o => o.tipo);\n  return pnl('Ocorrencias por tipo', c.ocAbertas.length + ' abertas de ' + c.ocs.length, donut(topN(m, 6)));\n}\nfunction painelCriticos(c) {\n  const lista = c.prob.slice().sort((a, b) => (a.pra ? a.pra.getTime() : 0) - (b.pra ? b.pra.getTime() : 0)).slice(0, 7);\n  return pnl('Precisam de atencao agora', '<a style=\"color:var(--info);cursor:pointer\" data-ir=\"pedidos\" data-filtro=\"atencao\">ver todos</a>',\n    `<div class=\"scroll\"><table><tbody>${lista.map(x => `<tr class=\"sel\" data-abre-pedido=\"${x.r.cod_remessa}\" data-key=\"${x.r._id}\">\n      <td style=\"width:118px\"><span class=\"chip ${EST[x.e].cls}\">${EST[x.e].rot}</span></td>\n      <td class=\"mono tiny\">${x.r.cod_remessa}</td>\n      <td><span class=\"strong\">${esc(x.r.cliente_nome)}</span><div class=\"tiny\">${esc(x.r.loja_nome)} &middot; ${esc(x.r.canal)}</div></td>\n      <td class=\"tiny\">${esc(x.r.entregador_nome)}</td>\n      <td class=\"num tiny mono\">${x.pra ? (x.pra.getTime() < c.t ? '-' : '') + dur(x.pra - new Date(c.t)) : '-'}</td>\n    </tr>`).join('') || '<tr><td class=\"vazio\">Nenhum pedido critico agora.</td></tr>'}</tbody></table></div>`);\n}\nfunction painelRiscoCliente(c) {\n  const risco = c.diag.filter(x => x.d.tag === 'evasao' || x.d.tag === 'queda');\n  return pnl('Clientes que pedem atencao', '<a style=\"color:var(--info);cursor:pointer\" data-ir=\"clientes\">ver carteira</a>',\n    `<table><tbody>${risco.slice(0, 6).map(x => `<tr class=\"sel\" data-abre-cliente=\"${x.cnpj}\" data-key=\"${x.cnpj}\">\n      <td><span class=\"strong\">${esc(x.nome)}</span><div class=\"tiny\">${esc(x.d.txt)}</div></td>\n      <td class=\"num\" style=\"width:126px\"><span class=\"chip ${x.d.cls}\">${x.d.rot}</span></td>\n    </tr>`).join('') || '<tr><td class=\"vazio\">Nenhum cliente em risco.</td></tr>'}</tbody></table>`);\n}\nfunction painelOcAbertas(c) {\n  return pnl('Ocorrencias abertas', c.ocAbertas.length + ' no total',\n    `<table><tbody>${c.ocAbertas.slice(0, 6).map(o => `<tr class=\"sel\" data-abre-pedido=\"${o.cod_remessa}\" data-key=\"${o._id}\">\n      <td style=\"width:96px\"><span class=\"chip ${o.tipo === 'extravio' ? 'ch-crit' : 'ch-warn'}\">${esc(o.tipo)}</span></td>\n      <td><span class=\"strong\">${esc(o.cliente_nome)}</span><div class=\"tiny\">${esc(o.terceiro_nome)} &middot; ${esc(o.terceiro_funcao)}</div></td>\n      <td class=\"num tiny\">${dtLabel(dt(o.aberto_em), new Date(c.t))}</td>\n    </tr>`).join('') || '<tr><td class=\"vazio\">Nenhuma ocorrencia aberta.</td></tr>'}</tbody></table>`);\n}\nfunction rankTerceiros(d2, c, funcao, pior) {\n  const t3 = L(d2, 'terceiro').filter(x => x.funcao === funcao);\n  const itens = t3.map(x => ({ t: x, m: metricasTerceiro(d2, x.usuario, funcao, 30) })).filter(x => x.m.tot >= 5)\n    .map(x => ({ l: x.t.nome, sub: x.t.equipe + (x.m.ocAbertas ? ' · ' + x.m.ocAbertas + ' ocorrencia(s) aberta(s)' : ''), v: (x.m.ok / x.m.tot) * 100, rot: ((x.m.ok / x.m.tot) * 100).toFixed(1).replace('.', ',') + '%', cor: (x.m.ok / x.m.tot) < 0.95 ? 'var(--c4)' : (x.m.ok / x.m.tot) < 0.985 ? 'var(--c3)' : 'var(--c2)' }));\n  itens.sort((a, b) => pior ? a.v - b.v : b.v - a.v);\n  return itens.slice(0, 7);\n}\n\nfunction vInicio(d2, agora) {\n  const perfil = d2.state.perfil || 'admin';\n  const c = ctxDash(d2, agora);\n  const D = { admin: dashAdmin, operacao: dashOperacao, coleta: dashColeta, contas: dashContas, financeiro: dashFinanceiro, terceiros: dashTerceiros };\n  return `<h2 class=\"h2\">${PERFIS[perfil].nome}</h2>\n  <p class=\"sub\">Tudo calculado agora, contra o relogio real: pedido criado hoje aparece em andamento, e amanha aparece entregue. Filas, listas e drill-down vem da base detalhada em acompanhamento (~45 pedidos/dia); SLA e volume diario vem do consolidado da operacao (~23 mil/dia).</p>\n  ${(D[perfil] || dashAdmin)(d2, c, agora)}\n  <div class=\"origem\">Fonte: base unificada da POC &middot; no projeto real, TRACKen (TMS) + WMS proprio</div>`;\n}\n\nfunction dashAdmin(d2, c, agora) {\n  const risco = c.diag.filter(x => x.d.tag === 'evasao' || x.d.tag === 'queda').length;\n  return `<div class=\"grid g4\">\n    ${card('c-info', num(c.abertos.length), 'Em andamento', 'pedidos ainda nao entregues')}\n    ${card(c.prob.length ? 'c-crit' : 'c-ok', num(c.prob.length), 'Precisam de atencao', 'em risco, estourados ou sem baixa')}\n    ${card('c-ok', c.kHoje ? num(c.kHoje.pedidos) : '-', 'Pedidos do dia', 'volume da operacao completa')}\n    ${card(c.mOk / c.mEnt >= 0.996 ? 'c-ok' : 'c-warn', pctS(c.mOk, c.mEnt, 2), 'SLA do mes', num(c.mEnt) + ' baixas apuradas')}\n  </div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">${graficoSla(c)}${graficoVolume(c)}</div>\n  <div class=\"grid g3\" style=\"margin-top:12px\">${graficoCanal(c)}${graficoRegiao(c)}${graficoOcorrencias(c)}</div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">${painelCriticos(c)}${painelRiscoCliente(c)}</div>`;\n}\n\nfunction dashOperacao(d2, c, agora) {\n  const est = {}; c.linhas.forEach(x => est[x.e] = (est[x.e] || 0) + 1);\n  const distr = ABERTOS.filter(k => k !== 'agendado' && est[k]).map((k, i) => ({ l: EST[k].rot, v: est[k], cor: PROBLEMA.indexOf(k) >= 0 ? 'var(--c4)' : 'var(--c1)' }));\n  return `<div class=\"grid g4\">\n    ${card('c-info', num(c.abertos.length), 'Em andamento', 'pedidos ainda nao entregues')}\n    ${card(c.prob.length ? 'c-crit' : 'c-ok', num(c.prob.length), 'Precisam de atencao', 'em risco, estourados ou sem baixa')}\n    ${card('c-info', num(c.naColeta.length + c.noPonto.length), 'Antes da entrega', c.naColeta.length + ' na coleta &middot; ' + c.noPonto.length + ' no ponto')}\n    ${card(c.mOk / c.mEnt >= 0.996 ? 'c-ok' : 'c-warn', pctS(c.mOk, c.mEnt, 2), 'SLA do mes', num(c.mEnt) + ' baixas apuradas')}\n  </div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">${graficoFunil(c)}${pnl('Onde estao os pedidos agora', 'base em acompanhamento', barsH(distr))}</div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">${graficoSla(c)}${graficoRegiao(c)}</div>\n  <div style=\"margin-top:12px\">${painelCriticos(c)}</div>`;\n}\n\nfunction dashColeta(d2, c, agora) {\n  const t = c.t;\n  const atrasadas = c.naColeta.filter(r => dt(r.coleta_prevista_em) && dt(r.coleta_prevista_em).getTime() < t).length;\n  const rem = L(d2, 'remessa');\n  const d30 = t - 30 * 86400000;\n  const coletadas = rem.filter(r => { const col = dt(r.coletado_em); return col && col.getTime() <= t && col.getTime() >= d30; });\n  const okCol = coletadas.filter(r => { const col = dt(r.coletado_em), pv = dt(r.coleta_prevista_em); return pv && col.getTime() <= pv.getTime() + 30 * 60000; }).length;\n  const porPonto = contaPor(c.noPonto, r => r.ponto_coleta);\n  const porRegColeta = {};\n  c.naColeta.forEach(r => { const cl = L(d2, 'cliente').find(x => x.cnpj_cpf === r.cliente_cnpj); const k = (cl && cl.regiao_coleta) || 'sem regiao'; porRegColeta[k] = (porRegColeta[k] || 0) + 1; });\n  return `<div class=\"grid g4\">\n    ${card('c-info', num(c.naColeta.length), 'Aguardando coleta', 'no cliente, prontos para o coletador')}\n    ${card(atrasadas ? 'c-warn' : 'c-ok', num(atrasadas), 'Coleta atrasada', 'passou da previsao combinada')}\n    ${card('c-info', num(c.noPonto.length), 'No ponto', 'prontos para o entregador levar')}\n    ${card(okCol / coletadas.length >= 0.95 ? 'c-ok' : 'c-warn', pctS(okCol, coletadas.length, 1), 'Coleta no prazo', 'ultimos 30 dias &middot; amostra')}\n  </div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">\n    ${pnl('Fila de coleta por regiao', 'onde estao os pedidos parados', barsH(topN(porRegColeta, 6)))}\n    ${pnl('No ponto, por local', 'aguardando entregador', barsH(topN(porPonto, 6)))}\n  </div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">\n    ${pnl('Coletadores com mais atraso', 'ultimos 30 dias &middot; % de coletas no prazo', barsH(rankTerceiros(d2, c, 'coletador', true)))}\n    ${graficoFunil(c)}\n  </div>\n  <div style=\"margin-top:12px\"><div class=\"note\"><b>A fila de coleta e onde o prazo se ganha.</b> Um pedido parado no cliente as 17h com corte as 21h ja esta comprometido, e a tela de Pedidos so vai acusar quando ele estiver em rota — tarde demais. <a style=\"color:var(--info);cursor:pointer\" data-ir=\"fluxo\">Abrir o Fluxo</a>.</div></div>`;\n}\n\nfunction dashContas(d2, c, agora) {\n  const lojas = L(d2, 'loja');\n  const ultMes = c.lista[c.lista.length - 1];\n  const serieMes = c.lista.slice(-12).map(m => {\n    const v = L(d2, 'clientemes').filter(x => x.mes === m).reduce((s, x) => s + (x.pedidos || 0), 0);\n    return { l: mesLabel(m), v: v, cor: 'var(--c1)' };\n  });\n  const porTag = {};\n  c.diag.forEach(x => { const r = x.d.rot; porTag[r] = (porTag[r] || 0) + 1; });\n  const topClientes = c.diag.slice().sort((a, b) => b.atual - a.atual).slice(0, 7).map(x => ({ l: x.nome, sub: x.d.rot, v: x.atual, cor: x.d.tag === 'evasao' || x.d.tag === 'queda' ? 'var(--c4)' : x.d.tag === 'cresce' ? 'var(--c2)' : 'var(--c1)' }));\n  const porCanal = somaPor(L(d2, 'clientemes').filter(x => x.mes === ultMes), x => x.canal, x => x.pedidos);\n  const porGerente = {};\n  L(d2, 'cliente').forEach(cl => { const g = cl.usuario_comercial || 'sem dono'; const agg = c.mm[cl.cnpj_cpf]; porGerente[g] = (porGerente[g] || 0) + ((agg && agg.meses[ultMes]) || 0); });\n  const risco = c.diag.filter(x => x.d.tag === 'evasao' || x.d.tag === 'queda').length;\n  const cresce = c.diag.filter(x => x.d.tag === 'cresce').length;\n  return `<div class=\"grid g4\">\n    ${card('c-info', num(L(d2, 'cliente').length), 'Clientes ativos', num(lojas.length) + ' lojas vinculadas')}\n    ${card(risco ? 'c-crit' : 'c-ok', num(risco), 'Clientes em risco', 'evasao ou queda anomala')}\n    ${card('c-ok', num(cresce), 'Clientes crescendo', 'acima da media dos 3 meses')}\n    ${card('c-warn', num(c.ocAbertas.length), 'Ocorrencias abertas', 'avarias, extravios, mediacoes')}\n  </div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">\n    ${pnl('Volume da carteira', 'ultimos 12 meses &middot; soma de todas as lojas', barsV(serieMes, { h: 140 }), mesLabel(c.lista.slice(-12)[0]) + ' &rarr; ' + mesLabel(ultMes))}\n    ${pnl('Situacao da carteira', c.diag.length + ' clientes', donut(Object.keys(porTag).map(k => ({ l: k, v: porTag[k], cor: k === 'Evasao provavel' || k === 'Queda anomala' ? 'var(--c4)' : k === 'Crescendo' ? 'var(--c2)' : k === 'Queda sazonal' ? 'var(--c3)' : 'var(--c1)' }))))}\n  </div>\n  <div class=\"grid g3\" style=\"margin-top:12px\">\n    ${pnl('Maiores clientes', 'pedidos no mes corrente', barsH(topClientes))}\n    ${pnl('Volume por canal', 'onde a carteira vende', donut(topN(porCanal, 6)))}\n    ${pnl('Carteira por gerente', 'pedidos no mes corrente', barsH(topN(porGerente, 6)))}\n  </div>\n  <div style=\"margin-top:12px\">${painelRiscoCliente(c)}</div>`;\n}\n\nfunction dashFinanceiro(d2, c, agora) {\n  const fat = L(d2, 'fatura');\n  const emAberto = fat.filter(f => f.status !== 'paga');\n  const vencidas = emAberto.filter(f => dt(f.vencimento) && dt(f.vencimento).getTime() < c.t);\n  const pagas = fat.filter(f => f.status === 'paga');\n  const porQuinzena = somaPor(fat, f => f.quinzena, f => f.valor);\n  const topFat = somaPor(fat, f => f.cliente_nome, f => f.valor);\n  const porFaixa = somaPor(c.recentes.map(x => x.r), r => r.peso_faixa === 'leve' ? 'Leve (R$ 10,90)' : r.peso_faixa === 'pesado10' ? 'Acima de 10kg (R$ 23,80)' : 'Acima de 30kg (R$ 35,70)', r => r.valor_frete);\n  const statusDon = [\n    { l: 'Baixadas', v: pagas.length, cor: 'var(--c2)' },\n    { l: 'Em aberto', v: emAberto.length - vencidas.length, cor: 'var(--c3)' },\n    { l: 'Vencidas', v: vencidas.length, cor: 'var(--c4)' }\n  ].filter(x => x.v);\n  return `<div class=\"grid g4\">\n    ${card('c-warn', num(emAberto.length), 'Faturas em aberto', brlC(emAberto.reduce((s, f) => s + (f.valor || 0), 0)))}\n    ${card(vencidas.length ? 'c-crit' : 'c-ok', num(vencidas.length), 'Vencidas', brlC(vencidas.reduce((s, f) => s + (f.valor || 0), 0)))}\n    ${card('c-ok', num(pagas.length), 'Baixadas', brlC(pagas.reduce((s, f) => s + (f.valor || 0), 0)))}\n    ${card('c-info', num(L(d2, 'cliente').length), 'Clientes faturados', num(L(d2, 'loja').length) + ' lojas')}\n  </div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">\n    ${pnl('Faturamento por quinzena', 'valor total emitido', barsH(Object.keys(porQuinzena).sort().map(k => ({ l: k, v: porQuinzena[k], rot: brlC(porQuinzena[k]), cor: 'var(--c1)' }))))}\n    ${pnl('Situacao das faturas', fat.length + ' no total', donut(statusDon))}\n  </div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">\n    ${pnl('Maiores faturamentos', 'por cliente &middot; soma das lojas', barsH(topN(topFat, 7, brlC)))}\n    ${pnl('Receita por faixa de peso', 'ultimos 30 dias &middot; amostra', donut(Object.keys(porFaixa).map(k => ({ l: k, v: Math.round(porFaixa[k]) }))))}\n  </div>\n  <div style=\"margin-top:12px\">${painelFaturas(d2, agora)}</div>`;\n}\n\nfunction dashTerceiros(d2, c, agora) {\n  const t3 = L(d2, 'terceiro');\n  const ents = t3.filter(x => x.funcao === 'entregador');\n  const cols = t3.filter(x => x.funcao === 'coletador');\n  const bloq = t3.filter(x => x.situacao === 'bloqueado').length;\n  const totEnt = c.entregues30.length;\n  const okEnt = c.entregues30.filter(x => x.e === 'entregue_no_prazo').length;\n  const porEquipe = {};\n  c.entregues30.forEach(x => { const k = x.r.equipe || (t3.find(y => y.usuario === x.r.entregador_usuario) || {}).equipe || '-'; porEquipe[k] = (porEquipe[k] || 0) + 1; });\n  const ocPorTerceiro = contaPor(c.ocs, o => o.terceiro_nome);\n  return `<div class=\"grid g4\">\n    ${card('c-info', num(ents.length + cols.length), 'Terceiros cadastrados', ents.length + ' entregadores &middot; ' + cols.length + ' coletadores')}\n    ${card(bloq ? 'c-warn' : 'c-ok', num(bloq), 'Bloqueados', 'impedidos de receber pedidos')}\n    ${card(okEnt / totEnt >= 0.99 ? 'c-ok' : 'c-warn', pctS(okEnt, totEnt, 1), 'No prazo (amostra)', num(totEnt) + ' entregas em 30 dias')}\n    ${card(c.ocAbertas.length ? 'c-crit' : 'c-ok', num(c.ocAbertas.length), 'Ocorrencias abertas', 'avarias, extravios, reclamacoes')}\n  </div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">\n    ${pnl('Entregadores com pior desempenho', 'ultimos 30 dias &middot; % no prazo', barsH(rankTerceiros(d2, c, 'entregador', true)))}\n    ${pnl('Coletadores com pior desempenho', 'ultimos 30 dias &middot; % de coletas no prazo', barsH(rankTerceiros(d2, c, 'coletador', true)))}\n  </div>\n  <div class=\"grid g3\" style=\"margin-top:12px\">\n    ${graficoOcorrencias(c)}\n    ${pnl('Ocorrencias por terceiro', 'quem mais gera problema', barsH(topN(ocPorTerceiro, 6), { cor: 'var(--c4)' }))}\n    ${pnl('Volume por equipe', 'entregas em 30 dias', barsH(topN(porEquipe, 6)))}\n  </div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">${painelOcAbertas(c)}${painelCriticos(c)}</div>`;\n}\n\n/* ---------- FLUXO: filas de coleta e expedicao ---------- */\nfunction folgaReal(r, agora) {\n  // tempo ate o prazo menos o que ainda falta acontecer (trajeto + processamento + entrega)\n  const pra = dt(r.prazo_em); if (!pra) return null;\n  const restante = pra.getTime() - agora.getTime();\n  const col = dt(r.coletado_em), gal = dt(r.galpao_em), rot = dt(r.rota_em);\n  let precisa = 0;\n  if (col && col.getTime() > agora.getTime()) precisa += 45 * 60000;          // trajeto ate o cliente\n  if (gal && gal.getTime() > agora.getTime()) precisa += 60 * 60000;          // processamento no ponto\n  if (rot && rot.getTime() > agora.getTime()) precisa += 40 * 60000;          // espera pelo entregador\n  precisa += 90 * 60000;                                                      // janela media de entrega\n  return restante - precisa;\n}\nfunction vFluxo(d2, agora) {\n  const t = agora.getTime();\n  const rem = L(d2, 'remessa');\n  const clientes = L(d2, 'cliente');\n  const pontos = L(d2, 'pontocoleta');\n  const fxPonto = d2.state.fxPonto || 'todos';\n\n  const naColeta = rem.filter(r => r.origem === 'coleta' && dt(r.criado_em) && dt(r.criado_em).getTime() <= t && (!dt(r.coletado_em) || dt(r.coletado_em).getTime() > t));\n  const noPonto = rem.filter(r => { const g = dt(r.galpao_em), ro = dt(r.rota_em); return g && g.getTime() <= t && (!ro || ro.getTime() > t); });\n\n  const comprometidos = naColeta.concat(noPonto).filter(r => { const f = folgaReal(r, agora); return f != null && f < 0; }).length;\n  const atrasoColeta = naColeta.filter(r => dt(r.coleta_prevista_em) && dt(r.coleta_prevista_em).getTime() < t).length;\n\n  // fila 1 agrupada por cliente\n  const g1 = {};\n  naColeta.forEach(r => {\n    const k = r.cliente_cnpj;\n    if (!g1[k]) { const c = clientes.find(x => x.cnpj_cpf === k) || {}; g1[k] = { cnpj: k, nome: r.cliente_nome, cli: c, itens: [], canais: {} }; }\n    g1[k].itens.push(r); g1[k].canais[r.canal] = (g1[k].canais[r.canal] || 0) + 1;\n  });\n  const fila1 = Object.keys(g1).map(k => {\n    const g = g1[k];\n    const folgas = g.itens.map(r => folgaReal(r, agora)).filter(v => v != null);\n    g.folga = folgas.length ? Math.min.apply(null, folgas) : null;\n    g.espera = t - Math.min.apply(null, g.itens.map(r => dt(r.criado_em).getTime()));\n    g.prazo = Math.min.apply(null, g.itens.map(r => dt(r.prazo_em).getTime()));\n    g.atrasado = g.itens.some(r => dt(r.coleta_prevista_em) && dt(r.coleta_prevista_em).getTime() < t);\n    g.coletador = g.itens[0].coletador_nome; g.ponto = g.itens[0].ponto_coleta;\n    return g;\n  }).sort((a, b) => (a.folga == null ? 1 : a.folga) - (b.folga == null ? 1 : b.folga));\n\n  // fila 2 agrupada por ponto -> regiao\n  const g2 = {};\n  noPonto.forEach(r => {\n    if (fxPonto !== 'todos' && r.ponto_coleta !== fxPonto) return;\n    if (!g2[r.ponto_coleta]) g2[r.ponto_coleta] = { nome: r.ponto_coleta, itens: [], regioes: {} };\n    g2[r.ponto_coleta].itens.push(r);\n    if (!g2[r.ponto_coleta].regioes[r.regiao]) g2[r.ponto_coleta].regioes[r.regiao] = [];\n    g2[r.ponto_coleta].regioes[r.regiao].push(r);\n  });\n  const fila2 = Object.keys(g2).map(k => g2[k]).sort((a, b) => b.itens.length - a.itens.length);\n\n  const cardsTop = `<div class=\"grid g4\">\n    ${card('c-info', num(naColeta.length), 'Aguardando coleta', 'no cliente, prontos para o coletador')}\n    ${card(atrasoColeta ? 'c-warn' : 'c-ok', num(atrasoColeta), 'Coleta atrasada', 'passou da previsao combinada')}\n    ${card('c-info', num(noPonto.length), 'No ponto', 'prontos para o entregador levar')}\n    ${card(comprometidos ? 'c-crit' : 'c-ok', num(comprometidos), 'Prazo ja comprometido', 'nao da mais tempo no ritmo normal')}\n  </div>`;\n\n  const painel1 = `<div class=\"panel\"><h3>Aguardando coleta <em>${fila1.length} clientes &middot; ${naColeta.length} pedidos</em></h3>\n  <div class=\"scroll\"><table><thead><tr>\n    <th>Cliente</th><th>Endereco de coleta</th><th class=\"num\">Pedidos</th><th>Canais</th><th class=\"num\">Espera</th><th class=\"num\">Folga real</th><th>Coletador</th><th>Destino</th><th></th>\n  </tr></thead><tbody>\n  ${fila1.map(g => `<tr data-key=\"${g.cnpj}\">\n    <td><span class=\"strong sel\" data-abre-cliente=\"${g.cnpj}\" style=\"cursor:pointer\">${esc(g.nome)}</span>${g.atrasado ? ' <span class=\"chip ch-warn\">atrasada</span>' : ''}</td>\n    <td class=\"tiny\">${esc(g.cli.endereco_coleta || '-')}<div class=\"tiny\">${esc(g.cli.bairro_coleta || '')} &middot; ${esc(g.cli.regiao_coleta || '')}</div></td>\n    <td class=\"num strong\">${g.itens.length}</td>\n    <td><div class=\"lojachips\">${Object.keys(g.canais).map(c => `<span class=\"chip ch-mute\">${esc(c)} ${g.canais[c]}</span>`).join('')}</div></td>\n    <td class=\"num tiny mono\">${dur(g.espera)}</td>\n    <td class=\"num strong mono\" style=\"color:${g.folga == null ? 'var(--ink3)' : g.folga < 0 ? 'var(--crit)' : g.folga < 3 * 3600000 ? 'var(--warn)' : 'var(--ok)'}\">${g.folga == null ? '-' : (g.folga < 0 ? '-' : '') + dur(g.folga)}</td>\n    <td class=\"tiny\">${esc(g.coletador || '-')}</td>\n    <td class=\"tiny\">${esc(g.ponto)}</td>\n    <td><button class=\"btn\" data-troca-coletador=\"${g.cnpj}\">Reatribuir</button></td>\n  </tr>`).join('') || '<tr><td class=\"vazio\" colspan=\"9\">Nenhum pedido aguardando coleta neste momento.</td></tr>'}\n  </tbody></table></div></div>`;\n\n  const painel2 = `<div class=\"panel\"><h3>No ponto, aguardando entregador <em>${noPonto.length} pedidos</em>\n    <select class=\"inp\" data-fxponto style=\"min-width:150px\"><option value=\"todos\">Todos os pontos</option>${pontos.map(p => opt(p.nome, fxPonto)).join('')}</select></h3>\n  ${fila2.map(p => `<div style=\"border-bottom:1px solid var(--line)\">\n    <div style=\"padding:10px 15px;display:flex;align-items:center;gap:10px;flex-wrap:wrap;background:var(--panel2)\">\n      <span class=\"strong\">${esc(p.nome)}</span><span class=\"tiny\">${p.itens.length} pedido${p.itens.length > 1 ? 's' : ''}</span>\n      <div class=\"lojachips\">${Object.keys(p.regioes).sort().map(rg => `<span class=\"chip ch-info\">${esc(rg)} ${p.regioes[rg].length}</span>`).join('')}</div>\n    </div>\n    <table><tbody>\n    ${Object.keys(p.regioes).sort().map(rg => p.regioes[rg].slice().sort((a, b) => dt(a.prazo_em) - dt(b.prazo_em)).map(r => {\n      const f = folgaReal(r, agora);\n      return `<tr class=\"sel\" data-abre-pedido=\"${r.cod_remessa}\" data-key=\"${r._id}\">\n        <td style=\"width:90px\"><span class=\"chip ch-mute\">${esc(r.regiao)}</span></td>\n        <td class=\"mono tiny\">${r.cod_remessa}</td>\n        <td><span class=\"strong\">${esc(r.cliente_nome)}</span><div class=\"tiny\">${esc(r.loja_nome)} &middot; ${esc(r.canal)}</div></td>\n        <td class=\"tiny\">${esc(r.bairro)}</td>\n        <td class=\"tiny\">${esc(r.entregador_nome)}</td>\n        <td class=\"num tiny mono\">no ponto ha ${dur(agora - dt(r.galpao_em))}</td>\n        <td class=\"num strong mono\" style=\"color:${f == null ? 'var(--ink3)' : f < 0 ? 'var(--crit)' : f < 2 * 3600000 ? 'var(--warn)' : 'var(--ok)'}\">${f == null ? '-' : (f < 0 ? '-' : '') + dur(f)}</td>\n        <td class=\"num tiny mono\">corte ${hhmm(dt(r.prazo_em))}</td>\n      </tr>`;\n    }).join('')).join('')}\n    </tbody></table></div>`).join('') || '<div class=\"vazio\">Nenhum pedido no ponto neste momento.</div>'}\n  </div>`;\n\n  const totalFull = rem.filter(r => r.origem === 'full').length;\n  return `<h2 class=\"h2\">Fluxo pre-entrega</h2>\n  <p class=\"sub\">O cano completo antes da entrega: o pedido esta no cliente esperando o coletador, ou ja no ponto esperando o entregador. E aqui que o prazo se ganha — a tela de Pedidos mostra o incendio, esta mostra a fumaca.</p>\n  ${cardsTop}\n  <div class=\"note\" style=\"margin:12px 0\"><b>Folga real</b> = tempo ate o corte menos o que ainda falta acontecer (trajeto da coleta, processamento no ponto, espera pelo entregador e a janela de entrega). Quando fica negativa, o pedido ja esta perdido — e ainda nem saiu da casa do cliente. Nenhum sistema hoje mostra esse numero.</div>\n  <div style=\"margin-bottom:12px\">${painel1}</div>\n  ${painel2}\n  <div class=\"origem\">Amostra de ~45 pedidos/dia &middot; na escala real da TM (23 mil/dia) estas filas teriam centenas de linhas &middot; ${num(totalFull)} pedidos do fulfillment nao passam por coleta e entram direto na segunda fila</div>`;\n}\n\n/* ---------- PEDIDOS ---------- */\nfunction vPedidos(d2, agora) {\n  const fE = d2.state.pedEstado || 'abertos';\n  const fC = d2.state.pedCliente || 'todos';\n  const fL = d2.state.pedLoja || 'todas';\n  const fK = d2.state.pedCanal || 'todos';\n  const busca = (d2.state.pedBusca || '').trim().toLowerCase();\n  const verFuturos = !!d2.state.pedFuturos;\n  const limite = agora.getTime() + 3 * 86400000;\n\n  let linhas = enriquece(d2);\n  const clientes = Array.from(new Set(linhas.map(x => x.r.cliente_nome))).sort();\n  const lojasDoCliente = fC === 'todos' ? [] : Array.from(new Set(L(d2, 'loja').filter(l => l.cliente_nome === fC).map(l => l.nome_loja))).sort();\n  const canais = Array.from(new Set(linhas.map(x => x.r.canal))).sort();\n\n  let ocultosFuturo = 0;\n  linhas = linhas.filter(x => {\n    if (!verFuturos && x.pra && x.pra.getTime() > limite) { ocultosFuturo++; return false; }\n    if (fE === 'abertos' && (ABERTOS.indexOf(x.e) < 0 || x.e === 'agendado')) return false;\n    if (fE === 'atencao' && PROBLEMA.indexOf(x.e) < 0) return false;\n    if (fE === 'entregues' && x.e.indexOf('entregue') !== 0) return false;\n    if (fE === 'foraprazo' && x.e !== 'entregue_fora') return false;\n    if (fC !== 'todos' && x.r.cliente_nome !== fC) return false;\n    if (fL !== 'todas' && x.r.loja_nome !== fL) return false;\n    if (fK !== 'todos' && x.r.canal !== fK) return false;\n    if (busca) {\n      const alvo = (x.r.cod_remessa + ' ' + x.r.num_pedido + ' ' + x.r.nota_fiscal + ' ' + x.r.destinatario + ' ' + x.r.cliente_nome + ' ' + x.r.loja_nome).toLowerCase();\n      if (alvo.indexOf(busca) < 0) return false;\n    }\n    return true;\n  });\n  const ord = { estourado: 0, sem_baixa: 1, vai_estourar: 2, em_risco: 3, em_rota: 4, no_galpao: 5, aguardando_coleta: 6, agendado: 7, entregue_fora: 8, entregue_no_prazo: 9 };\n  linhas.sort((a, b) => (ord[a.e] - ord[b.e]) || ((a.pra ? a.pra.getTime() : 0) - (b.pra ? b.pra.getTime() : 0)));\n  const mostra = linhas.slice(0, 300);\n  const cont = {}; linhas.forEach(x => { cont[x.e] = (cont[x.e] || 0) + 1; });\n  const resumo = PROBLEMA.filter(k => cont[k]).map(k => `<span style=\"color:var(--${k === 'em_risco' ? 'warn' : 'crit'})\">${cont[k]} ${EST[k].rot.toLowerCase()}</span>`).join(' &middot; ');\n\n  return `<h2 class=\"h2\">Pedidos</h2>\n  <p class=\"sub\">Ordenado por urgencia de prazo. Cliente e loja sao colunas e filtros — um cliente pode vender em varios canais, e cada loja e uma linha de negocio dele.</p>\n  <div class=\"toolbar\">\n    <div class=\"seg\">${[['abertos', 'em andamento'], ['atencao', 'atencao'], ['entregues', 'entregues'], ['foraprazo', 'fora do prazo'], ['todos', 'todos']].map(a => `<button data-pedestado=\"${a[0]}\" class=\"${fE === a[0] ? 'on' : ''}\">${a[1]}</button>`).join('')}</div>\n    <select class=\"inp\" data-pedcliente><option value=\"todos\">Todos os clientes</option>${clientes.map(c => opt(c, fC)).join('')}</select>\n    ${fC !== 'todos' ? `<select class=\"inp\" data-pedloja style=\"min-width:150px\"><option value=\"todas\">Todas as lojas (${lojasDoCliente.length})</option>${lojasDoCliente.map(l => opt(l, fL)).join('')}</select>` : ''}\n    <select class=\"inp\" data-pedcanal style=\"min-width:120px\"><option value=\"todos\">Todos os canais</option>${canais.map(c => opt(c, fK)).join('')}</select>\n    <input class=\"inp\" type=\"search\" placeholder=\"remessa, pedido, NF, destinatario...\" value=\"${esc(d2.state.pedBusca || '')}\" data-pedbusca>\n    <button class=\"btn ${verFuturos ? 'btn-ok' : ''}\" data-pedfuturos>${verFuturos ? 'Ocultar futuros' : 'Mostrar futuros' + (ocultosFuturo ? ' (' + ocultosFuturo + ')' : '')}</button>\n    <div class=\"spacer\"></div>\n    <span class=\"tiny\">${num(linhas.length)} pedidos${resumo ? ' &middot; ' + resumo : ''}${linhas.length > 300 ? ' &middot; exibindo 300' : ''}</span>\n  </div>\n  <div class=\"panel\"><div class=\"scroll\"><table><thead><tr>\n    <th>Situacao</th><th>Remessa</th><th>Cliente</th><th>Loja / canal</th><th>Destinatario</th><th>Coletador</th><th>Entregador</th><th>Prazo</th>\n  </tr></thead><tbody>\n  ${mostra.map(x => `<tr class=\"sel\" data-abre-pedido=\"${x.r.cod_remessa}\" data-key=\"${x.r._id}\">\n    <td><span class=\"chip ${EST[x.e].cls}\">${EST[x.e].rot}</span>${(x.e === 'em_rota' || x.e === 'em_risco' || x.e === 'vai_estourar') && x.pra ? '<div class=\"tiny mono\">' + dur(x.pra - agora) + '</div>' : ''}</td>\n    <td class=\"mono tiny\">${x.r.cod_remessa}<div class=\"tiny\">${esc(x.r.num_pedido)}</div></td>\n    <td><span class=\"strong\">${esc(x.r.cliente_nome)}</span></td>\n    <td><span class=\"chip ch-mute\">${esc(x.r.canal)}</span><div class=\"tiny\">${esc(x.r.loja_nome)}</div></td>\n    <td>${esc(x.r.destinatario)}<div class=\"tiny\">${esc(x.r.bairro)} &middot; ${esc(x.r.regiao)}</div></td>\n    <td class=\"tiny\">${x.r.coletador_nome ? esc(x.r.coletador_nome) : '<span style=\"color:var(--ink3)\">full</span>'}</td>\n    <td class=\"tiny\">${esc(x.r.entregador_nome)}</td>\n    <td class=\"num tiny mono\">${dtLabel(x.pra, agora)}</td>\n  </tr>`).join('') || '<tr><td class=\"vazio\" colspan=\"8\">Nenhum pedido com esses filtros.</td></tr>'}\n  </tbody></table></div></div>\n  <div class=\"origem\">Estado calculado contra o relogio real &middot; pedidos com prazo alem de 3 dias ficam ocultos por padrao</div>`;\n}\n\n/* ---------- CLIENTES ---------- */\nfunction vClientes(d2, agora) {\n  const ordem = d2.state.cliOrdem || 'atencao';\n  const mm = porMesCliente(d2), lista = mesesOrdenados(d2);\n  const lojas = L(d2, 'loja');\n  const linhas = enriquece(d2);\n  const clientes = L(d2, 'cliente').map(c => {\n    const agg = mm[c.cnpj_cpf] || { meses: {}, lojas: {} };\n    const d = diagnosticoCliente(agg.meses, lista);\n    const mesAtual = agg.meses[lista[lista.length - 1]] || 0;\n    const ls = lojas.filter(l => l.cliente_cnpj === c.cnpj_cpf);\n    const ped = linhas.filter(x => x.r.cliente_cnpj === c.cnpj_cpf);\n    const prob = ped.filter(x => PROBLEMA.indexOf(x.e) >= 0).length;\n    const serie = lista.slice(-12).map(m => agg.meses[m] || 0);\n    return { c: c, d: d, mesAtual: mesAtual, lojas: ls, prob: prob, serie: serie, aggLojas: agg.lojas };\n  });\n  const peso = { evasao: 0, queda: 1, cresce: 2, sazonal: 3, ok: 4 };\n  if (ordem === 'atencao') clientes.sort((a, b) => (peso[a.d.tag] - peso[b.d.tag]) || (b.mesAtual - a.mesAtual));\n  else if (ordem === 'volume') clientes.sort((a, b) => b.mesAtual - a.mesAtual);\n  else clientes.sort((a, b) => (a.c.nome_fantasia || '').localeCompare(b.c.nome_fantasia || ''));\n\n  return `<h2 class=\"h2\">Clientes</h2>\n  <p class=\"sub\">O cliente e a empresa; as lojas sao onde ele vende. Volume e faturamento somam todas as lojas, e abrem por canal quando voce clica.</p>\n  <div class=\"toolbar\">\n    <div class=\"seg\">${[['atencao', 'por atencao'], ['volume', 'por volume'], ['nome', 'por nome']].map(a => `<button data-cliordem=\"${a[0]}\" class=\"${ordem === a[0] ? 'on' : ''}\">${a[1]}</button>`).join('')}</div>\n    <div class=\"spacer\"></div><span class=\"tiny\">${clientes.length} clientes &middot; ${lojas.length} lojas</span>\n  </div>\n  <div class=\"panel\"><div class=\"scroll\"><table><thead><tr>\n    <th>Cliente</th><th>Lojas</th><th>12 meses</th><th class=\"num\">Mes atual</th><th>Situacao</th><th class=\"num\">Em atencao</th><th>Gerente</th>\n  </tr></thead><tbody>\n  ${clientes.map(x => {\n    const max = Math.max.apply(null, x.serie.concat([1]));\n    return `<tr class=\"sel\" data-abre-cliente=\"${x.c.cnpj_cpf}\" data-key=\"${x.c._id}\">\n      <td><span class=\"strong\">${esc(x.c.nome_fantasia)}</span><div class=\"tiny mono\">${esc(x.c.cnpj_cpf)}</div></td>\n      <td><div class=\"lojachips\">${x.lojas.map(l => `<span class=\"chip ch-mute\" title=\"${esc(l.nome_loja)}\">${esc(l.canal)}</span>`).join('') || '<span class=\"tiny\">sem loja</span>'}</div></td>\n      <td style=\"width:120px\"><div class=\"spark\">${x.serie.map((v, i) => `<i class=\"${i === x.serie.length - 1 ? (v < max * 0.45 ? 'down' : 'last') : ''}\" style=\"height:${Math.max(4, (v / max) * 100)}%\"></i>`).join('')}</div></td>\n      <td class=\"num strong\">${num(x.mesAtual)}</td>\n      <td><span class=\"chip ${x.d.cls}\">${x.d.rot}</span></td>\n      <td class=\"num\">${x.prob ? '<span style=\"color:var(--crit)\">' + x.prob + '</span>' : '-'}</td>\n      <td class=\"tiny\">${esc(x.c.usuario_comercial || '-')}</td>\n    </tr>`;\n  }).join('')}\n  </tbody></table></div></div>\n  <div class=\"origem\">Serie mensal por loja &middot; diagnostico compara os 3 meses anteriores e o mesmo mes do ano passado</div>`;\n}\n\n/* ---------- TERCEIROS ---------- */\nfunction vTerceiros(d2, agora) {\n  const func = d2.state.terFuncao || 'entregador';\n  const dias = d2.state.terDias || 30;\n  const t3 = L(d2, 'terceiro').filter(t => t.funcao === func);\n  const rows = t3.map(t => ({ t: t, m: metricasTerceiro(d2, t.usuario, func, dias) }));\n  rows.sort((a, b) => {\n    const pa = a.m.tot ? a.m.ok / a.m.tot : 1, pb = b.m.tot ? b.m.ok / b.m.tot : 1;\n    return (b.m.ocAbertas - a.m.ocAbertas) || (pa - pb);\n  });\n  const totEnt = rows.reduce((s, r) => s + r.m.tot, 0), totOk = rows.reduce((s, r) => s + r.m.ok, 0);\n  const bloq = t3.filter(t => t.situacao === 'bloqueado').length;\n\n  return `<h2 class=\"h2\">Terceiros</h2>\n  <p class=\"sub\">Coletadores e entregadores sao prestadores de servico. Aqui eles sao medidos por resultado — nao so por suspeita: volume, prazo, e ocorrencias que sobraram para a TM pagar.</p>\n  <div class=\"toolbar\">\n    <div class=\"seg\">${[['entregador', 'Entregadores'], ['coletador', 'Coletadores']].map(a => `<button data-terfuncao=\"${a[0]}\" class=\"${func === a[0] ? 'on' : ''}\">${a[1]}</button>`).join('')}</div>\n    <div class=\"seg\">${[[7, '7 dias'], [30, '30 dias'], [90, '90 dias']].map(a => `<button data-terdias=\"${a[0]}\" class=\"${dias === a[0] ? 'on' : ''}\">${a[1]}</button>`).join('')}</div>\n    <div class=\"spacer\"></div>\n    <button class=\"btn btn-ok\" data-novo-terceiro=\"${func}\">+ Novo ${func}</button>\n  </div>\n  <div class=\"grid g4\" style=\"margin-bottom:12px\">\n    ${card('c-info', num(t3.length), func === 'entregador' ? 'Entregadores' : 'Coletadores', bloq + ' bloqueado(s)')}\n    ${card('c-ok', num(totEnt), func === 'entregador' ? 'Entregas no periodo' : 'Coletas no periodo', 'ultimos ' + dias + ' dias')}\n    ${card(totOk / totEnt >= 0.99 ? 'c-ok' : 'c-warn', pctS(totOk, totEnt, 1), 'No prazo (amostra)', func === 'entregador' ? 'entregue ate o corte' : 'coletado ate 30min do previsto')}\n    ${card('c-crit', num(rows.reduce((s, r) => s + r.m.ocAbertas, 0)), 'Ocorrencias abertas', 'atribuidas a este grupo')}\n  </div>\n  <div class=\"panel\"><div class=\"scroll\"><table><thead><tr>\n    <th>${func === 'entregador' ? 'Entregador' : 'Coletador'}</th><th>Equipe</th><th class=\"num\">${func === 'entregador' ? 'Entregas' : 'Coletas'}</th><th class=\"num\">% no prazo</th><th class=\"num\">Fora</th><th class=\"num\">Ocorrencias</th><th>Situacao</th><th></th>\n  </tr></thead><tbody>\n  ${rows.map(x => {\n    const p = x.m.tot ? (x.m.ok / x.m.tot) * 100 : null;\n    return `<tr class=\"sel\" data-abre-terceiro=\"${esc(x.t.usuario)}\" data-key=\"${x.t.usuario}\">\n      <td><span class=\"strong\">${esc(x.t.nome)}</span><div class=\"tiny mono\">${esc(x.t.usuario)}</div></td>\n      <td class=\"tiny\">${esc(x.t.equipe)}<div class=\"tiny\">${esc(x.t.veiculo)}</div></td>\n      <td class=\"num\">${num(x.m.tot)}</td>\n      <td class=\"num strong\" style=\"color:${p == null ? 'var(--ink3)' : p < 97 ? 'var(--crit)' : p < 99.3 ? 'var(--warn)' : 'var(--ok)'}\">${p == null ? '-' : p.toFixed(1).replace('.', ',') + '%'}</td>\n      <td class=\"num\">${x.m.ruim || '-'}</td>\n      <td class=\"num\">${x.m.oc ? (x.m.ocAbertas ? '<span style=\"color:var(--crit)\">' + x.m.oc + '</span>' : x.m.oc) : '-'}</td>\n      <td>${x.t.situacao === 'bloqueado' ? '<span class=\"chip ch-crit\">bloqueado</span>' : '<span class=\"chip ch-ok\">ativo</span>'}</td>\n      <td style=\"white-space:nowrap\"><button class=\"btn ${x.t.situacao === 'bloqueado' ? 'btn-ok' : 'btn-crit'}\" data-bloqueia=\"${esc(x.t.usuario)}\">${x.t.situacao === 'bloqueado' ? 'Desbloquear' : 'Bloquear'}</button></td>\n    </tr>`;\n  }).join('')}\n  </tbody></table></div></div>\n  <div class=\"origem\">Metricas sobre a base detalhada em acompanhamento &middot; servem para comparar terceiros entre si, nao para apurar o SLA contratual &middot; ocorrencias vem da auditoria de pedido</div>`;\n}\n\n/* ---------- FINANCEIRO ---------- */\nfunction vFinanceiro(d2, agora) {\n  return `<h2 class=\"h2\">Financeiro</h2>\n  <p class=\"sub\">Faturamento quinzenal por cliente, somando todas as lojas dele. A baixa de pagamento e registrada aqui com autor e data.</p>\n  ${painelFaturas(d2, agora)}\n  <div class=\"origem\">Valor calculado da tabela de precos: R$ 10,90 leve &middot; R$ 23,80 acima de 10kg &middot; R$ 35,70 acima de 30kg &middot; etiqueta adicional por volume</div>`;\n}\nfunction painelFaturas(d2, agora) {\n  const f = d2.state.finStatus || 'todas';\n  let rows = L(d2, 'fatura').slice();\n  rows.forEach(x => { x._venc = dt(x.vencimento); x._vencida = x.status !== 'paga' && x._venc && x._venc.getTime() < agora.getTime(); });\n  if (f === 'abertas') rows = rows.filter(x => x.status !== 'paga');\n  if (f === 'vencidas') rows = rows.filter(x => x._vencida);\n  if (f === 'pagas') rows = rows.filter(x => x.status === 'paga');\n  rows.sort((a, b) => (a.status === 'paga' ? 1 : 0) - (b.status === 'paga' ? 1 : 0) || (a.vencimento < b.vencimento ? -1 : 1));\n  const tot = rows.reduce((s, x) => s + (x.valor || 0), 0);\n  const lojas = L(d2, 'loja');\n  return `<div class=\"toolbar\">\n    <div class=\"seg\">${[['todas', 'todas'], ['abertas', 'em aberto'], ['vencidas', 'vencidas'], ['pagas', 'baixadas']].map(a => `<button data-finstatus=\"${a[0]}\" class=\"${f === a[0] ? 'on' : ''}\">${a[1]}</button>`).join('')}</div>\n    <div class=\"spacer\"></div><span class=\"tiny\">${rows.length} faturas &middot; ${brl(tot)}</span>\n  </div>\n  <div class=\"panel\"><div class=\"scroll\"><table><thead><tr>\n    <th>Cliente</th><th>CNPJ / CPF</th><th>Lojas</th><th>Quinzena</th><th class=\"num\">Pedidos</th><th class=\"num\">Valor</th><th>Vencimento</th><th>Status</th><th></th>\n  </tr></thead><tbody>\n  ${rows.map(x => {\n    const ls = lojas.filter(l => l.cliente_cnpj === x.cliente_cnpj);\n    return `<tr data-key=\"${x._id}\">\n      <td><span class=\"strong\">${esc(x.cliente_nome)}</span></td>\n      <td class=\"mono tiny\">${esc(x.cliente_cnpj)}</td>\n      <td><div class=\"lojachips\">${ls.map(l => `<span class=\"chip ch-mute\" title=\"${esc(l.nome_loja)}\">${esc(l.canal)}</span>`).join('')}</div></td>\n      <td class=\"tiny mono\">${esc(x.quinzena)}</td>\n      <td class=\"num\">${num(x.pedidos_qtd)}</td>\n      <td class=\"num strong\">${brl(x.valor)}</td>\n      <td class=\"tiny mono\">${esc(x.vencimento)}</td>\n      <td>${x.status === 'paga' ? '<span class=\"chip ch-ok\">paga</span><div class=\"tiny\">' + esc(x.pago_em) + '</div>' : (x._vencida ? '<span class=\"chip ch-crit\">vencida</span>' : '<span class=\"chip ch-warn\">aberta</span>')}</td>\n      <td>${x.status === 'paga' ? '<button class=\"btn\" data-estorna=\"' + x._id + '\">Estornar</button>' : '<button class=\"btn btn-ok\" data-baixa=\"' + x._id + '\">Dar baixa</button>'}</td>\n    </tr>`;\n  }).join('') || '<tr><td class=\"vazio\" colspan=\"9\">Nenhuma fatura.</td></tr>'}\n  </tbody></table></div></div>`;\n}\n\n/* ---------- VENDEDOR: minha carteira ---------- */\nfunction vendedores(d2) {\n  return Array.from(new Set(L(d2, 'cliente').map(c => c.usuario_comercial).filter(Boolean))).sort();\n}\nfunction vendedorAtual(d2) {\n  const p = PERFIS[d2.state.perfil || 'admin'] || {};\n  if (p.fixo) return p.fixo;\n  const lst = vendedores(d2);\n  return d2.state.vendedor && lst.indexOf(d2.state.vendedor) >= 0 ? d2.state.vendedor : (lst[0] || '');\n}\nfunction compDe(d, delta) {\n  const x = new Date(d.getFullYear(), d.getMonth() + (delta || 0), 1);\n  return x.getFullYear() + '-' + String(x.getMonth() + 1).padStart(2, '0');\n}\nfunction sinaisCliente(d2, cli, agora, mm, lista) {\n  const out = [];\n  const agg = mm[cli.cnpj_cpf] || { meses: {}, lojas: {} };\n  const dg = diagnosticoCliente(agg.meses, lista);\n  if (dg.tag === 'evasao') out.push({ p: 0, cls: 'ch-crit', rot: 'Evasao', txt: dg.txt });\n  else if (dg.tag === 'queda') out.push({ p: 1, cls: 'ch-crit', rot: 'Queda', txt: dg.txt });\n  else if (dg.tag === 'sazonal') out.push({ p: 6, cls: 'ch-info', rot: 'Sazonal', txt: dg.txt });\n  else if (dg.tag === 'cresce') out.push({ p: 7, cls: 'ch-ok', rot: 'Crescendo', txt: dg.txt });\n  // loja parada com outras ativas\n  const ult = lista[lista.length - 1], pen = lista[lista.length - 2];\n  const nomes = Object.keys(agg.lojas);\n  if (nomes.length > 1) {\n    const paradas = nomes.filter(n => (agg.lojas[n].meses[ult] || 0) === 0 && (agg.lojas[n].meses[pen] || 0) === 0);\n    const ativas = nomes.filter(n => (agg.lojas[n].meses[ult] || 0) > 0);\n    if (paradas.length && ativas.length) out.push({ p: 2, cls: 'ch-warn', rot: 'Loja parada', txt: paradas.join(', ') + ' sem envio, mas ' + ativas.length + ' loja(s) seguem ativas — o cliente nao saiu, redirecionou o canal.' });\n  }\n  const fv = L(d2, 'fatura').filter(f => f.cliente_cnpj === cli.cnpj_cpf && f.status !== 'paga' && dt(f.vencimento) && dt(f.vencimento).getTime() < agora.getTime());\n  if (fv.length) out.push({ p: 3, cls: 'ch-crit', rot: 'Fatura vencida', txt: fv.length + ' fatura(s) vencida(s), total ' + brl(fv.reduce((s, f) => s + (f.valor || 0), 0)) });\n  const oc = L(d2, 'ocorrencia').filter(o => o.cliente_nome === cli.nome_fantasia && o.situacao === 'aberta');\n  if (oc.length) out.push({ p: 4, cls: 'ch-warn', rot: 'Ocorrencia', txt: oc.length + ' aberta(s): ' + Array.from(new Set(oc.map(o => o.tipo))).join(', ') });\n  const meus = L(d2, 'remessa').filter(r => r.cliente_cnpj === cli.cnpj_cpf && dt(r.criado_em) && dt(r.criado_em).getTime() <= agora.getTime());\n  const ultPed = meus.length ? Math.max.apply(null, meus.map(r => dt(r.criado_em).getTime())) : null;\n  const diasSem = ultPed ? Math.floor((agora.getTime() - ultPed) / 86400000) : null;\n  if (diasSem != null && diasSem >= 7) out.push({ p: 5, cls: 'ch-warn', rot: 'Sem pedido', txt: 'Ultimo pedido ha ' + diasSem + ' dias' });\n  out.sort((a, b) => a.p - b.p);\n  return { sinais: out, diag: dg, ultPed: ultPed, diasSem: diasSem, volMes: agg.meses[ult] || 0 };\n}\nfunction vVendedor(d2, agora) {\n  const eu = vendedorAtual(d2);\n  const fixo = !!(PERFIS[d2.state.perfil || 'admin'] || {}).fixo;\n  if (!eu) return '<div class=\"note warn\">Nenhum vendedor cadastrado na carteira.</div>';\n  const mm = porMesCliente(d2), lista = mesesOrdenados(d2);\n  const meusClientes = L(d2, 'cliente').filter(c => c.usuario_comercial === eu);\n  const lojas = L(d2, 'loja');\n  const compAtual = compDe(agora, 0), compAnt = compDe(agora, -1);\n  const comis = L(d2, 'comissao').filter(x => x.beneficiario === eu && x.papel === 'comercial');\n  const cAtual = comis.filter(x => x.competencia === compAtual).reduce((s, x) => s + (x.valor || 0), 0);\n  const cAnt = comis.filter(x => x.competencia === compAnt);\n  const cAntVal = cAnt.reduce((s, x) => s + (x.valor || 0), 0);\n  const cAntPago = cAnt.every(x => x.pago_em) && cAnt.length > 0;\n\n  const fichas = meusClientes.map(c => Object.assign({ c: c, lojas: lojas.filter(l => l.cliente_cnpj === c.cnpj_cpf) }, sinaisCliente(d2, c, agora, mm, lista)));\n  const totLojas = fichas.reduce((s, f) => s + f.lojas.length, 0);\n  const volMes = fichas.reduce((s, f) => s + f.volMes, 0);\n  const precisam = fichas.filter(f => f.sinais.some(s => s.p <= 5)).sort((a, b) => (a.sinais[0] ? a.sinais[0].p : 9) - (b.sinais[0] ? b.sinais[0].p : 9));\n  // pos-venda: 2 primeiros meses desde data_inicio\n  const posVenda = fichas.filter(f => {\n    const di = dt(f.c.data_inicio); if (!di) return false;\n    const meses = (agora.getFullYear() - di.getFullYear()) * 12 + (agora.getMonth() - di.getMonth());\n    return meses <= 1 && di.getTime() <= agora.getTime();\n  }).map(f => {\n    const di = dt(f.c.data_inicio);\n    const fim = new Date(di.getFullYear(), di.getMonth() + 2, di.getDate());\n    return Object.assign({}, f, { fim: fim, dias: Math.ceil((fim.getTime() - agora.getTime()) / 86400000) });\n  });\n\n  const cab = fixo\n    ? `<div class=\"note\" style=\"margin-bottom:12px\"><b>${esc(eu)}</b> &middot; vendedor (usuario comercial). Esta visao mostra <b>apenas a carteira dele</b> — e o que ele veria ao entrar no sistema com o proprio login.</div>`\n    : `<div class=\"toolbar\"><span class=\"tiny\">Ver como o vendedor:</span><select class=\"inp\" data-vend>${vendedores(d2).map(v => opt(v, eu)).join('')}</select><div class=\"spacer\"></div><span class=\"tiny\">visao generica do papel — troque a pessoa para comparar carteiras</span></div>`;\n\n  return `<h2 class=\"h2\">Minha carteira</h2>\n  <p class=\"sub\">O que a TM chama de <b>vendedor</b> (usuario comercial no TRACKen): quem fecha o contrato e acompanha o cliente. Aqui ele ve so os clientes dele, os sinais que exigem acao e a propria comissao.</p>\n  ${cab}\n  <div class=\"grid g4\">\n    ${card('c-info', num(meusClientes.length), 'Meus clientes', num(totLojas) + ' lojas vinculadas')}\n    ${card(precisam.length ? 'c-crit' : 'c-ok', num(precisam.length), 'Precisam de mim', 'com sinal que exige acao')}\n    ${card('c-info', num(volMes), 'Pedidos no mes', 'somando todas as lojas')}\n    ${card('c-ok', brl(cAtual), 'Minha comissao', compAtual + ' · 4% do frete' + (cAntVal ? ' &middot; ' + compAnt + ': ' + brlC(cAntVal) + (cAntPago ? ' pago' : ' a receber') : ''))}\n  </div>\n\n  <div class=\"panel\" style=\"margin-top:12px\"><h3>Precisam de mim hoje <em>${precisam.length} de ${meusClientes.length} clientes</em></h3>\n  <div class=\"scroll\"><table><tbody>\n  ${precisam.map(f => `<tr data-key=\"${f.c.cnpj_cpf}\">\n    <td style=\"width:130px\"><div class=\"lojachips\">${f.sinais.filter(s => s.p <= 5).map(s => `<span class=\"chip ${s.cls}\">${s.rot}</span>`).join('')}</div></td>\n    <td><span class=\"strong sel\" data-abre-cliente=\"${f.c.cnpj_cpf}\" style=\"cursor:pointer\">${esc(f.c.nome_fantasia)}</span>\n      <div class=\"tiny\">${esc(f.sinais.filter(s => s.p <= 5).map(s => s.txt).join(' · '))}</div></td>\n    <td class=\"num tiny\" style=\"white-space:nowrap\"><button class=\"btn\" data-ir=\"pedidos\" data-cliente=\"${esc(f.c.nome_fantasia)}\">Ver pedidos</button></td>\n  </tr>`).join('') || '<tr><td class=\"vazio\">Nenhum cliente seu precisa de acao agora.</td></tr>'}\n  </tbody></table></div></div>\n\n  ${posVenda.length ? `<div class=\"panel\" style=\"margin-top:12px\"><h3>Em pos-venda <em>2 primeiros meses — janela em que a comissao e apurada</em></h3>\n  <table><tbody>${posVenda.map(f => `<tr class=\"sel\" data-abre-cliente=\"${f.c.cnpj_cpf}\" data-key=\"pv-${f.c.cnpj_cpf}\">\n    <td><span class=\"strong\">${esc(f.c.nome_fantasia)}</span><div class=\"tiny\">cliente desde ${esc(f.c.data_inicio)} &middot; ${f.lojas.length} loja(s)</div></td>\n    <td class=\"num\">${num(f.volMes)}<div class=\"tiny\">pedidos/mes</div></td>\n    <td class=\"num\" style=\"width:150px\">${f.dias > 0 ? '<span class=\"chip ch-warn\">' + f.dias + ' dias de janela</span>' : '<span class=\"chip ch-mute\">janela encerrada</span>'}</td>\n  </tr>`).join('')}</tbody></table>\n  <div style=\"padding:10px 15px\" class=\"tiny\">O vendedor acompanha de perto nos dois primeiros meses porque e nessa janela que a comissao dele e apurada.</div></div>` : ''}\n\n  <div class=\"panel\" style=\"margin-top:12px\"><h3>Minha carteira completa</h3>\n  <div class=\"scroll\"><table><thead><tr><th>Cliente</th><th>Lojas</th><th class=\"num\">Mes atual</th><th>Situacao</th><th class=\"num\">Ultimo pedido</th><th class=\"num\">Comissao ${esc(compAtual)}</th></tr></thead><tbody>\n  ${fichas.sort((a, b) => b.volMes - a.volMes).map(f => {\n    const cm = comis.filter(x => x.competencia === compAtual && x.cliente_cnpj === f.c.cnpj_cpf).reduce((s, x) => s + (x.valor || 0), 0);\n    return `<tr class=\"sel\" data-abre-cliente=\"${f.c.cnpj_cpf}\" data-key=\"mc-${f.c.cnpj_cpf}\">\n      <td><span class=\"strong\">${esc(f.c.nome_fantasia)}</span><div class=\"tiny mono\">${esc(f.c.cnpj_cpf)}</div></td>\n      <td><div class=\"lojachips\">${f.lojas.map(l => `<span class=\"chip ch-mute\" title=\"${esc(l.nome_loja)}\">${esc(l.canal)}</span>`).join('') || '<span class=\"tiny\">sem loja</span>'}</div></td>\n      <td class=\"num strong\">${num(f.volMes)}</td>\n      <td><span class=\"chip ${f.diag.cls}\">${f.diag.rot}</span></td>\n      <td class=\"num tiny\">${f.ultPed ? dtLabel(new Date(f.ultPed), agora) : '-'}</td>\n      <td class=\"num mono\">${cm ? brl(cm) : '-'}</td>\n    </tr>`;\n  }).join('')}\n  </tbody></table></div></div>\n  <div class=\"origem\">Carteira de ${esc(eu)} &middot; ${meusClientes.length} clientes na amostra da POC — na operacao real a TM fatura mais de 2.400 clientes por dia, e uma carteira seria bem maior</div>`;\n}\n\n/* ---------- COMISSOES ---------- */\nfunction vComissoes(d2, agora) {\n  const todas = L(d2, 'comissao');\n  const comps = Array.from(new Set(todas.map(x => x.competencia))).sort().reverse();\n  const comp = d2.state.comComp || comps[0] || '';\n  const agrupar = d2.state.comAgrupar || 'beneficiario';\n  const linhas = todas.filter(x => x.competencia === comp);\n\n  const totFat = linhas.length ? Array.from(new Set(linhas.map(x => x.cliente_cnpj))).reduce((s, k) => { const r = linhas.find(y => y.cliente_cnpj === k); return s + (r ? r.faturamento : 0); }, 0) : 0;\n  const totCom = linhas.reduce((s, x) => s + (x.valor || 0), 0);\n  const pagas = linhas.filter(x => x.pago_em);\n  const totPago = pagas.reduce((s, x) => s + (x.valor || 0), 0);\n  const aPagar = totCom - totPago;\n\n  let corpo = '';\n  if (agrupar === 'beneficiario') {\n    const g = {};\n    linhas.forEach(x => {\n      if (!g[x.beneficiario]) g[x.beneficiario] = { nome: x.beneficiario, papel: x.papel, pct: x.percentual, itens: [], valor: 0, pago: 0, clientes: 0 };\n      const b = g[x.beneficiario];\n      b.itens.push(x); b.valor += x.valor || 0; b.clientes++;\n      if (x.pago_em) b.pago += x.valor || 0;\n    });\n    const rows = Object.keys(g).map(k => g[k]).sort((a, b) => b.valor - a.valor);\n    corpo = `<div class=\"panel\"><h3>Por beneficiario <em>competencia ${esc(comp)}</em></h3><div class=\"scroll\">\n    <table><thead><tr><th>Beneficiario</th><th>Papel</th><th class=\"num\">%</th><th class=\"num\">Clientes</th><th class=\"num\">Base de frete</th><th class=\"num\">Comissao</th><th>Situacao</th><th></th></tr></thead><tbody>\n    ${rows.map(b => {\n      const base = b.itens.reduce((s, x) => s + (x.faturamento || 0), 0);\n      const tudoPago = b.pago >= b.valor - 0.01;\n      return `<tr data-key=\"${esc(b.nome)}\">\n        <td><span class=\"strong\">${esc(b.nome)}</span></td>\n        <td><span class=\"chip ${b.papel === 'comercial' ? 'ch-info' : 'ch-mute'}\">${esc(PAPEL[b.papel].rot)}</span><div class=\"tiny\">${esc(PAPEL[b.papel].desc)}</div></td>\n        <td class=\"num mono\">${b.pct}%</td>\n        <td class=\"num\">${b.clientes}</td>\n        <td class=\"num mono\">${brl(base)}</td>\n        <td class=\"num strong mono\">${brl(b.valor)}</td>\n        <td>${tudoPago ? '<span class=\"chip ch-ok\">pago</span><div class=\"tiny\">' + esc((b.itens.find(x => x.pago_em) || {}).pago_em || '') + '</div>' : '<span class=\"chip ch-warn\">a pagar</span>'}</td>\n        <td>${tudoPago ? '<button class=\"btn\" data-estorna-com=\"' + esc(comp) + '\" data-ben=\"' + esc(b.nome) + '\">Estornar</button>' : '<button class=\"btn btn-ok\" data-paga-com=\"' + esc(comp) + '\" data-ben=\"' + esc(b.nome) + '\">Pagar</button>'}</td>\n      </tr>`;\n    }).join('') || '<tr><td class=\"vazio\" colspan=\"8\">Sem comissao nesta competencia.</td></tr>'}\n    </tbody></table></div></div>`;\n  } else {\n    const g = {};\n    linhas.forEach(x => {\n      if (!g[x.cliente_cnpj]) g[x.cliente_cnpj] = { nome: x.cliente_nome, cnpj: x.cliente_cnpj, fat: x.faturamento, pedidos: x.pedidos, itens: [] };\n      g[x.cliente_cnpj].itens.push(x);\n    });\n    const lojas = L(d2, 'loja');\n    const rows = Object.keys(g).map(k => g[k]).sort((a, b) => b.fat - a.fat);\n    corpo = `<div class=\"panel\"><h3>Por cliente <em>competencia ${esc(comp)} &middot; base = frete faturado, somando todas as lojas</em></h3><div class=\"scroll\">\n    <table><thead><tr><th>Cliente</th><th>Lojas</th><th class=\"num\">Pedidos</th><th class=\"num\">Frete faturado</th><th>Comercial</th><th class=\"num\">4%</th><th>SDR</th><th class=\"num\">3%</th><th class=\"num\">Total</th></tr></thead><tbody>\n    ${rows.map(c => {\n      const com = c.itens.find(x => x.papel === 'comercial');\n      const sdr = c.itens.find(x => x.papel === 'sdr');\n      const ls = lojas.filter(l => l.cliente_cnpj === c.cnpj);\n      const tot = c.itens.reduce((s, x) => s + (x.valor || 0), 0);\n      return `<tr class=\"sel\" data-abre-cliente=\"${c.cnpj}\" data-key=\"${c.cnpj}\">\n        <td><span class=\"strong\">${esc(c.nome)}</span><div class=\"tiny mono\">${esc(c.cnpj)}</div></td>\n        <td><div class=\"lojachips\">${ls.map(l => `<span class=\"chip ch-mute\" title=\"${esc(l.nome_loja)}\">${esc(l.canal)}</span>`).join('')}</div></td>\n        <td class=\"num\">${num(c.pedidos)}</td>\n        <td class=\"num mono\">${brl(c.fat)}</td>\n        <td class=\"tiny\">${com ? esc(com.beneficiario) : '<span style=\"color:var(--warn)\">sem dono</span>'}</td>\n        <td class=\"num mono\">${com ? brl(com.valor) : '-'}</td>\n        <td class=\"tiny\">${sdr ? esc(sdr.beneficiario) : '<span style=\"color:var(--ink3)\">-</span>'}</td>\n        <td class=\"num mono\">${sdr ? brl(sdr.valor) : '-'}</td>\n        <td class=\"num strong mono\">${brl(tot)}</td>\n      </tr>`;\n    }).join('') || '<tr><td class=\"vazio\" colspan=\"9\">Sem comissao nesta competencia.</td></tr>'}\n    </tbody></table></div></div>`;\n  }\n\n  const porPapel = {};\n  linhas.forEach(x => { const k = PAPEL[x.papel].rot + ' (' + x.percentual + '%)'; porPapel[k] = (porPapel[k] || 0) + (x.valor || 0); });\n  const semDono = Array.from(new Set(linhas.map(x => x.cliente_cnpj)));\n  const clientesTodos = L(d2, 'cliente').filter(c => !c.usuario_comercial);\n\n  return `<h2 class=\"h2\">Comissoes</h2>\n  <p class=\"sub\">A TM paga os proprios funcionarios comerciais um percentual do <b>frete</b> que os clientes trazidos por eles faturam — nao do valor do produto. Dois papeis: quem fecha o contrato e quem prospecta.</p>\n  <div class=\"toolbar\">\n    <select class=\"inp\" data-comcomp>${comps.map(k => opt(k, comp)).join('')}</select>\n    <div class=\"seg\">${[['beneficiario', 'por beneficiario'], ['cliente', 'por cliente']].map(a => `<button data-comagrupar=\"${a[0]}\" class=\"${agrupar === a[0] ? 'on' : ''}\">${a[1]}</button>`).join('')}</div>\n    <div class=\"spacer\"></div><span class=\"tiny\">${linhas.length} linhas &middot; ${Array.from(new Set(linhas.map(x => x.beneficiario))).length} beneficiarios</span>\n  </div>\n  <div class=\"grid g4\">\n    ${card('c-info', brlC(totFat), 'Base de frete', 'faturado na competencia')}\n    ${card('c-info', brlC(totCom), 'Comissao apurada', totFat > 0 ? (totCom / totFat * 100).toFixed(1).replace('.', ',') + '% do frete' : '')}\n    ${card(aPagar > 0 ? 'c-warn' : 'c-ok', brlC(aPagar), 'A pagar', aPagar > 0 ? 'aguardando pagamento' : 'competencia fechada')}\n    ${card('c-ok', brlC(totPago), 'Ja pago', pagas.length + ' de ' + linhas.length + ' linhas')}\n  </div>\n  <div class=\"grid g2\" style=\"margin-top:12px\">\n    ${pnl('Comissao por papel', 'competencia ' + esc(comp), donut(Object.keys(porPapel).map(k => ({ l: k, v: Math.round(porPapel[k]) }))))}\n    ${pnl('Maiores beneficiarios', 'competencia ' + esc(comp), barsH(topN(somaPor(linhas, x => x.beneficiario, x => x.valor), 7, brlC)))}\n  </div>\n  <div style=\"margin-top:12px\">${corpo}</div>\n  ${clientesTodos.length ? '<div class=\"note warn\" style=\"margin-top:12px\"><b>' + clientesTodos.length + ' cliente(s) sem responsavel comercial na carteira</b> — faturam, mas nao geram comissao. Resolver no cadastro antes de fechar a competencia.</div>' : ''}\n  <div class=\"origem\">Base = soma do frete das remessas do mes, por cliente (todas as lojas) &middot; percentuais fixos nesta POC: comercial 4%, SDR 3% &middot; no projeto real seriam versionados por vigencia, para que um mes fechado mantenha a taxa vigente na epoca</div>`;\n}\n\n/* ---------- CADASTROS ---------- */\nfunction vCadastros(d2, agora) {\n  const tab = d2.state.cadTab || 'clientes';\n  const busca = (d2.state.cadBusca || '').trim().toLowerCase();\n  const lojas = L(d2, 'loja');\n  let corpo = '';\n  if (tab === 'clientes') {\n    let rows = L(d2, 'cliente').slice().sort((a, b) => (a.nome_fantasia || '').localeCompare(b.nome_fantasia || ''));\n    if (busca) rows = rows.filter(c => ((c.nome_fantasia || '') + ' ' + (c.cnpj_cpf || '')).toLowerCase().indexOf(busca) >= 0);\n    corpo = `<div class=\"panel\"><div class=\"scroll\"><table><thead><tr><th>Cliente</th><th>CNPJ / CPF</th><th>Lojas por canal</th><th>Gerente</th><th>Inicio</th><th>Situacao</th></tr></thead><tbody>\n    ${rows.map(c => {\n      const ls = lojas.filter(l => l.cliente_cnpj === c.cnpj_cpf);\n      return `<tr class=\"sel\" data-abre-cliente=\"${c.cnpj_cpf}\" data-key=\"${c._id}\">\n        <td><span class=\"strong\">${esc(c.nome_fantasia)}</span><div class=\"tiny\">${esc(c.razao_social)}</div></td>\n        <td class=\"mono tiny\">${esc(c.cnpj_cpf)}</td>\n        <td><div class=\"lojachips\">${ls.map(l => `<span class=\"chip ch-info\" title=\"${esc(l.nome_loja)}\">${esc(l.canal)}</span>`).join('') || '<span class=\"tiny\" style=\"color:var(--warn)\">sem loja</span>'}</div></td>\n        <td class=\"tiny\">${esc(c.usuario_comercial || '-')}</td>\n        <td class=\"tiny mono\">${esc(c.data_inicio || '-')}</td>\n        <td>${c.situacao === 'ativo' ? '<span class=\"chip ch-ok\">ativo</span>' : '<span class=\"chip ch-mute\">inativo</span>'}</td>\n      </tr>`;\n    }).join('')}\n    </tbody></table></div></div>`;\n  } else if (tab === 'lojas') {\n    let rows = lojas.slice().sort((a, b) => (a.cliente_nome || '').localeCompare(b.cliente_nome || ''));\n    if (busca) rows = rows.filter(l => ((l.cliente_nome || '') + ' ' + (l.nome_loja || '') + ' ' + (l.canal || '')).toLowerCase().indexOf(busca) >= 0);\n    corpo = `<div class=\"panel\"><div class=\"scroll\"><table><thead><tr><th>Loja</th><th>Cliente</th><th>Canal</th><th>Cod TRACKen</th><th>Servico</th><th>Situacao</th></tr></thead><tbody>\n    ${rows.map(l => `<tr class=\"sel\" data-abre-cliente=\"${l.cliente_cnpj}\" data-key=\"${l._id}\">\n      <td><span class=\"strong\">${esc(l.nome_loja)}</span></td>\n      <td class=\"tiny\">${esc(l.cliente_nome)}<div class=\"tiny mono\">${esc(l.cliente_cnpj)}</div></td>\n      <td><span class=\"chip ch-info\">${esc(l.canal)}</span></td>\n      <td class=\"mono tiny\">${esc(l.cod_tracken)}</td>\n      <td class=\"tiny\">${l.cod_servico === 1 ? 'Mercado Envio Flex' : 'Ecommerce / avulso'}</td>\n      <td>${l.situacao === 'ativo' ? '<span class=\"chip ch-ok\">ativo</span>' : '<span class=\"chip ch-mute\">inativo</span>'}</td>\n    </tr>`).join('')}\n    </tbody></table></div></div>`;\n  } else if (tab === 'terceiros') {\n    let rows = L(d2, 'terceiro').slice().sort((a, b) => (a.funcao || '').localeCompare(b.funcao || '') || (a.nome || '').localeCompare(b.nome || ''));\n    if (busca) rows = rows.filter(t => ((t.nome || '') + ' ' + (t.usuario || '') + ' ' + (t.equipe || '')).toLowerCase().indexOf(busca) >= 0);\n    corpo = `<div class=\"panel\"><div class=\"scroll\"><table><thead><tr><th>Nome</th><th>Funcao</th><th>Telefone</th><th>Equipe</th><th>Base</th><th>Situacao</th><th></th></tr></thead><tbody>\n    ${rows.map(t => `<tr data-key=\"${t._id}\">\n      <td><span class=\"strong\">${esc(t.nome)}</span><div class=\"tiny mono\">${esc(t.usuario)}</div></td>\n      <td><span class=\"chip ${t.funcao === 'entregador' ? 'ch-info' : 'ch-mute'}\">${esc(t.funcao)}</span></td>\n      <td class=\"mono tiny\">${esc(t.telefone)}</td>\n      <td class=\"tiny\">${esc(t.equipe)}<div class=\"tiny\">${esc(t.coordenador)}</div></td>\n      <td class=\"tiny\">${esc(t.ponto_coleta || '-')}</td>\n      <td>${t.situacao === 'bloqueado' ? '<span class=\"chip ch-crit\">bloqueado</span>' : '<span class=\"chip ch-ok\">ativo</span>'}</td>\n      <td><button class=\"btn\" data-edita-terceiro=\"${esc(t.usuario)}\">Editar</button></td>\n    </tr>`).join('')}\n    </tbody></table></div></div>`;\n  } else {\n    const pts = L(d2, 'pontocoleta');\n    corpo = `<div class=\"panel\"><table><thead><tr><th>Ponto</th><th>Endereco</th><th>Tipo</th><th>Responsavel</th><th class=\"num\">Remessas (30d)</th></tr></thead><tbody>\n    ${pts.map(p => {\n      const n = L(d2, 'remessa').filter(r => r.ponto_coleta === p.nome && dt(r.criado_em) && (agora - dt(r.criado_em)) < 30 * 86400000 && dt(r.criado_em) <= agora).length;\n      return `<tr data-key=\"${p._id}\"><td class=\"strong\">${esc(p.nome)}</td><td class=\"tiny\">${esc(p.endereco)}, ${esc(p.bairro)} - ${esc(p.cidade)}</td>\n      <td><span class=\"chip ch-mute\">${esc(p.tipo)}</span></td><td class=\"tiny\">${esc(p.responsavel)}</td><td class=\"num\">${num(n)}</td></tr>`;\n    }).join('')}\n    </tbody></table></div>`;\n  }\n  return `<h2 class=\"h2\">Cadastros</h2>\n  <p class=\"sub\">Clientes com suas lojas por canal, terceiros e pontos de coleta. Um cliente pode ter varias lojas: propria, Mercado Livre, Shopee, Amazon.</p>\n  <div class=\"toolbar\">\n    <div class=\"seg\">${[['clientes', 'Clientes'], ['lojas', 'Lojas'], ['terceiros', 'Terceiros'], ['pontos', 'Pontos de coleta']].map(a => `<button data-cadtab=\"${a[0]}\" class=\"${tab === a[0] ? 'on' : ''}\">${a[1]}</button>`).join('')}</div>\n    ${tab !== 'pontos' ? `<input class=\"inp\" type=\"search\" placeholder=\"buscar...\" value=\"${esc(d2.state.cadBusca || '')}\" data-cadbusca>` : ''}\n    <div class=\"spacer\"></div>\n    ${tab === 'terceiros' ? '<button class=\"btn btn-ok\" data-novo-terceiro=\"entregador\">+ Novo terceiro</button>' : ''}\n  </div>\n  ${corpo}\n  <div class=\"origem\">No projeto real, importados do TRACKen (Administracao &gt; Pessoas / Comercial) e mantidos aqui</div>`;\n}\n\n/* ---------- DRAWERS ---------- */\nfunction drawer(d2, agora) {\n  const dw = d2.state.drawer;\n  if (!dw) return '';\n  let corpo = '';\n  try {\n    if (dw.tipo === 'pedido') corpo = dPedido(d2, dw.id, agora);\n    else if (dw.tipo === 'cliente') corpo = dCliente(d2, dw.id, agora);\n    else if (dw.tipo === 'terceiro') corpo = dTerceiro(d2, dw.id, agora);\n    else if (dw.tipo === 'terceiro-form') corpo = dTerceiroForm(d2, dw.id, dw.funcao);\n  } catch (e) { corpo = '<div class=\"note crit\">Erro: ' + esc(e && e.message) + '</div>'; }\n  return `<div class=\"drawer\"><div class=\"backdrop\" data-fecha></div><div class=\"sheet\"><button class=\"close\" data-fecha>&times;</button>${corpo}</div></div>`;\n}\n\nfunction dPedido(d2, cod, agora) {\n  const r = L(d2, 'remessa').find(x => String(x.cod_remessa) === String(cod));\n  if (!r) return '<p>Pedido nao encontrado.</p>';\n  const e = estadoDe(r, agora);\n  const ocs = L(d2, 'ocorrencia').filter(o => String(o.cod_remessa) === String(cod));\n  const passos = [\n    { t: 'Pedido criado', d: dt(r.criado_em), obs: r.canal },\n    r.origem === 'coleta' ? { t: 'Coleta prevista', d: dt(r.coleta_prevista_em), obs: r.coletador_nome } : null,\n    r.origem === 'coleta' ? { t: 'Coletado', d: dt(r.coletado_em), obs: r.coletador_nome ? 'por ' + r.coletador_nome : '' } : null,\n    { t: r.origem === 'full' ? 'Separado no full' : 'Recebido no ponto', d: dt(r.galpao_em), obs: r.ponto_coleta },\n    { t: 'Em rota de entrega', d: dt(r.rota_em), obs: r.entregador_nome ? 'com ' + r.entregador_nome : '' },\n    { t: 'Prazo de entrega', d: dt(r.prazo_em), obs: 'corte do canal ' + r.canal, prazo: true },\n    { t: r.entrega_em ? 'Entregue' : 'Sem baixa de entrega', d: dt(r.entrega_em), obs: r.entrega_em ? (r.recebedor ? 'recebido por ' + r.recebedor + (r.documento ? ' (' + r.documento + ')' : '') : 'sem dados do recebedor') : '' }\n  ].filter(Boolean);\n  const semProva = r.entrega_em && !r.recebedor;\n  const atrasoColeta = dt(r.coletado_em) && dt(r.coleta_prevista_em) && (dt(r.coletado_em) - dt(r.coleta_prevista_em)) > 30 * 60000;\n\n  return `<span class=\"chip ${EST[e].cls}\">${EST[e].rot}</span> <span class=\"chip ch-mute\">${esc(r.canal)}</span>\n  <h4 style=\"margin-top:10px\">Remessa ${r.cod_remessa}</h4>\n  <p class=\"sub\" style=\"margin-bottom:0\">${esc(r.cliente_nome)} &middot; loja ${esc(r.loja_nome)}</p>\n  <dl class=\"kv\">\n    <dt>Pedido / NF</dt><dd class=\"mono\">${esc(r.num_pedido)} &middot; ${esc(r.nota_fiscal)}</dd>\n    <dt>Destinatario</dt><dd>${esc(r.destinatario)}<div class=\"tiny\">${esc(r.bairro)}, ${esc(r.cidade)} &middot; ${esc(r.cep)} &middot; ${esc(r.regiao)}</div></dd>\n    <dt>Valor NF / frete</dt><dd>${brl(r.valor_nf)} &middot; frete ${brl(r.valor_frete)} <span class=\"tiny\">(${esc(r.peso_faixa)}${r.etiquetas > 1 ? ', ' + r.etiquetas + ' etiquetas' : ''})</span></dd>\n    <dt>Origem</dt><dd>${r.origem === 'full' ? 'Fulfillment TM' : 'Coleta no cliente'} &middot; ${esc(r.ponto_coleta)}</dd>\n    <dt>Coletador</dt><dd>${r.coletador_nome ? esc(r.coletador_nome) : '<span class=\"tiny\">nao se aplica (full)</span>'}</dd>\n    <dt>Entregador</dt><dd>${esc(r.entregador_nome)}</dd>\n  </dl>\n  ${semProva ? '<div class=\"note warn\"><b>Sem comprovacao de recebimento.</b> A baixa nao registrou nome nem documento do recebedor. Se o comprador abrir reclamacao, nao ha o que apresentar — e a TM arca com o reembolso.</div>' : ''}\n  ${atrasoColeta ? '<div class=\"note warn\" style=\"margin-top:8px\"><b>Coleta atrasada.</b> Coletado ' + dur(dt(r.coletado_em) - dt(r.coleta_prevista_em)) + ' depois do previsto.</div>' : ''}\n  <h3 style=\"font-size:11px;letter-spacing:.11em;text-transform:uppercase;color:var(--ink2);margin:20px 0 0;font-family:'IBM Plex Mono',monospace\">Cadeia do pedido</h3>\n  <ul class=\"tl\">\n  ${passos.map(p => {\n    const futuro = !p.d || p.d.getTime() > agora.getTime();\n    const bad = p.prazo && dt(r.entrega_em) && dt(r.entrega_em) > p.d;\n    const semBaixa = !p.d && !p.prazo;\n    return `<li class=\"${semBaixa ? 'bad' : futuro ? 'futuro' : bad ? 'bad' : 'done'}\" data-key=\"${p.t}\">\n      <div class=\"t\">${esc(p.t)} <span class=\"mono tiny\">${p.d ? dtLabel(p.d, agora) : '—'}</span></div>\n      ${p.obs ? '<div class=\"d\">' + esc(p.obs) + '</div>' : ''}\n    </li>`;\n  }).join('')}\n  </ul>\n  ${ocs.length ? `<h3 style=\"font-size:11px;letter-spacing:.11em;text-transform:uppercase;color:var(--ink2);margin:20px 0 8px;font-family:'IBM Plex Mono',monospace\">Ocorrencias</h3>\n  ${ocs.map(o => `<div class=\"note ${o.situacao === 'aberta' ? 'crit' : ''}\" style=\"margin-bottom:8px\">\n    <b>${esc(o.tipo)}</b> &middot; <span class=\"tiny\">${dtLabel(dt(o.aberto_em), agora)} &middot; ${esc(o.terceiro_nome)} (${esc(o.terceiro_funcao)})</span><br>${esc(o.descricao)}\n    ${o.situacao === 'aberta' ? '<div style=\"margin-top:8px;display:flex;gap:6px\"><button class=\"btn btn-crit\" data-resolve-oc=\"' + o._id + '\" data-sit=\"procedente\">Procedente</button><button class=\"btn\" data-resolve-oc=\"' + o._id + '\" data-sit=\"improcedente\">Improcedente</button></div>' : '<div class=\"tiny\" style=\"margin-top:6px\">' + esc(o.situacao) + ' em ' + esc((o.resolvido_em || '').slice(0, 10)) + '</div>'}\n  </div>`).join('')}` : ''}\n  <div class=\"origem\">Auditoria completa: coleta &rarr; ponto &rarr; rota &rarr; entrega, com responsavel em cada etapa</div>`;\n}\n\nfunction dCliente(d2, cnpj, agora) {\n  const c = L(d2, 'cliente').find(x => x.cnpj_cpf === cnpj);\n  if (!c) return '<p>Cliente nao encontrado.</p>';\n  const mm = porMesCliente(d2), lista = mesesOrdenados(d2);\n  const agg = mm[cnpj] || { meses: {}, lojas: {} };\n  const diag = diagnosticoCliente(agg.meses, lista);\n  const lojas = L(d2, 'loja').filter(l => l.cliente_cnpj === cnpj);\n  const linhas = enriquece(d2).filter(x => x.r.cliente_cnpj === cnpj);\n  const abertos = linhas.filter(x => ABERTOS.indexOf(x.e) >= 0 && x.e !== 'agendado');\n  const prob = linhas.filter(x => PROBLEMA.indexOf(x.e) >= 0);\n  const fats = L(d2, 'fatura').filter(f => f.cliente_cnpj === cnpj);\n  const ult12 = lista.slice(-12);\n  const serie = ult12.map(m => agg.meses[m] || 0);\n  const max = Math.max.apply(null, serie.concat([1]));\n  const ocs = L(d2, 'ocorrencia').filter(o => o.cliente_nome === c.nome_fantasia);\n\n  return `<h4>${esc(c.nome_fantasia)}</h4>\n  <p class=\"sub\" style=\"margin-bottom:6px\">${esc(c.razao_social)} &middot; <span class=\"mono\">${esc(c.cnpj_cpf)}</span></p>\n  <span class=\"chip ${diag.cls}\">${diag.rot}</span>\n  <div class=\"note ${diag.tag === 'evasao' || diag.tag === 'queda' ? 'crit' : diag.tag === 'cresce' ? '' : 'warn'}\" style=\"margin-top:10px\">${esc(diag.txt)}</div>\n  <dl class=\"kv\">\n    <dt>Gerente de contas</dt><dd>${esc(c.usuario_comercial || '-')}${c.sdr ? '<div class=\"tiny\">SDR: ' + esc(c.sdr) + '</div>' : ''}</dd>\n    <dt>Responsavel</dt><dd>${esc(c.responsavel || '-')}</dd>\n    <dt>Cliente desde</dt><dd class=\"mono\">${esc(c.data_inicio || '-')}</dd>\n    <dt>Em andamento</dt><dd>${abertos.length} pedidos${prob.length ? ' &middot; <span style=\"color:var(--crit)\">' + prob.length + ' em atencao</span>' : ''}</dd>\n  </dl>\n\n  <div class=\"panel\" style=\"margin-top:14px\"><h3>Lojas do cliente <em>${lojas.length} canais</em></h3>\n  <table><tbody>\n  ${lojas.map(l => {\n    const lm = (agg.lojas[l.nome_loja] || { meses: {} }).meses;\n    const atual = lm[ult12[ult12.length - 1]] || 0;\n    const ant = lm[ult12[ult12.length - 2]] || 0;\n    const morta = atual === 0 && ant === 0;\n    return `<tr data-key=\"${l._id}\">\n      <td style=\"width:120px\"><span class=\"chip ch-info\">${esc(l.canal)}</span></td>\n      <td>${esc(l.nome_loja)}<div class=\"tiny mono\">cod ${esc(l.cod_tracken)}</div></td>\n      <td class=\"num\">${num(atual)}<div class=\"tiny\">pedidos/mes</div></td>\n      <td class=\"num\" style=\"width:110px\">${morta ? '<span class=\"chip ch-crit\">sem envio</span>' : (atual < ant * 0.6 ? '<span class=\"chip ch-warn\">caindo</span>' : '<span class=\"chip ch-ok\">ativa</span>')}</td>\n    </tr>`;\n  }).join('') || '<tr><td class=\"vazio\">Sem lojas cadastradas.</td></tr>'}\n  </tbody></table>\n  ${lojas.length > 1 ? '<div style=\"padding:10px 14px\" class=\"tiny\">Um cliente, varias lojas. Se uma para de enviar e as outras seguem, o cliente nao saiu — ele redirecionou o volume daquele canal.</div>' : ''}\n  </div>\n\n  <div class=\"panel\" style=\"margin-top:12px\"><h3>Volume nos ultimos 12 meses</h3>\n  <div class=\"bars\" style=\"height:110px\">${serie.map((v, i) => `<div class=\"w\" title=\"${mesLabel(ult12[i])}: ${v}\"><div class=\"b ${i === serie.length - 1 && v < max * 0.45 ? 'miss' : ''}\" style=\"height:${Math.max(3, (v / max) * 100)}%\"></div></div>`).join('')}</div>\n  <div style=\"padding:0 14px 12px\" class=\"tiny\">${mesLabel(ult12[0])} a ${mesLabel(ult12[ult12.length - 1])} &middot; soma de todas as lojas</div></div>\n\n  ${fats.length ? `<div class=\"panel\" style=\"margin-top:12px\"><h3>Faturas</h3><table><tbody>\n  ${fats.map(f => `<tr data-key=\"${f._id}\"><td class=\"tiny mono\">${esc(f.quinzena)}</td><td class=\"num\">${brl(f.valor)}</td>\n  <td class=\"num\" style=\"width:110px\">${f.status === 'paga' ? '<span class=\"chip ch-ok\">paga</span>' : '<span class=\"chip ch-warn\">aberta</span>'}</td></tr>`).join('')}\n  </tbody></table></div>` : ''}\n\n  ${ocs.length ? `<div class=\"panel\" style=\"margin-top:12px\"><h3>Ocorrencias <em>${ocs.filter(o => o.situacao === 'aberta').length} abertas</em></h3><table><tbody>\n  ${ocs.slice(0, 6).map(o => `<tr class=\"sel\" data-abre-pedido=\"${o.cod_remessa}\" data-key=\"${o._id}\"><td style=\"width:100px\"><span class=\"chip ${o.situacao === 'aberta' ? 'ch-crit' : 'ch-mute'}\">${esc(o.tipo)}</span></td>\n  <td class=\"tiny\">${esc(o.descricao)}</td><td class=\"num tiny\">${dtLabel(dt(o.aberto_em), agora)}</td></tr>`).join('')}\n  </tbody></table></div>` : ''}\n  <div class=\"origem\">Serie e diagnostico somam todas as lojas &middot; clique numa ocorrencia para abrir o pedido</div>`;\n}\n\nfunction dTerceiro(d2, usuario, agora) {\n  const t = L(d2, 'terceiro').find(x => x.usuario === usuario);\n  if (!t) return '<p>Nao encontrado.</p>';\n  const ocs = L(d2, 'ocorrencia').filter(o => o.terceiro_usuario === usuario);\n  const m30 = metricasTerceiro(d2, usuario, t.funcao, 30);\n  const m7 = metricasTerceiro(d2, usuario, t.funcao, 7);\n  const linhas = enriquece(d2).filter(x => (t.funcao === 'coletador' ? x.r.coletador_usuario : x.r.entregador_usuario) === usuario && ABERTOS.indexOf(x.e) >= 0 && x.e !== 'agendado');\n  return `<h4>${esc(t.nome)}</h4>\n  <p class=\"sub\" style=\"margin-bottom:6px\"><span class=\"chip ${t.funcao === 'entregador' ? 'ch-info' : 'ch-mute'}\">${esc(t.funcao)}</span> ${esc(t.equipe)} &middot; ${esc(t.coordenador)}</p>\n  <dl class=\"kv\">\n    <dt>Usuario</dt><dd class=\"mono\">${esc(t.usuario)}</dd>\n    <dt>Telefone</dt><dd class=\"mono\">${esc(t.telefone)}</dd>\n    <dt>Veiculo</dt><dd>${esc(t.veiculo)}</dd>\n    ${t.ponto_coleta ? '<dt>Base</dt><dd>' + esc(t.ponto_coleta) + '</dd>' : ''}\n    <dt>Situacao</dt><dd>${t.situacao === 'bloqueado' ? '<span class=\"chip ch-crit\">bloqueado</span>' : '<span class=\"chip ch-ok\">ativo</span>'}</dd>\n    <dt>Em andamento</dt><dd>${linhas.length} ${t.funcao === 'coletador' ? 'coletas' : 'entregas'}</dd>\n  </dl>\n  ${t.situacao === 'bloqueado' ? '<div class=\"note crit\"><b>Bloqueado.</b> ' + esc(t.motivo_bloqueio) + '<div class=\"tiny\" style=\"margin-top:4px\">por ' + esc(t.bloqueado_por) + ' em ' + esc((t.bloqueado_em || '').slice(0, 10)) + '</div></div>' : ''}\n  <div class=\"grid g2\" style=\"margin-top:14px\">\n    ${card('c-info', num(m7.tot), '7 dias', pctS(m7.ok, m7.tot, 1) + ' no prazo')}\n    ${card(m30.tot && m30.ok / m30.tot < 0.97 ? 'c-crit' : 'c-ok', num(m30.tot), '30 dias', pctS(m30.ok, m30.tot, 1) + ' no prazo')}\n  </div>\n  ${ocs.length ? `<div class=\"panel\" style=\"margin-top:12px\"><h3>Ocorrencias atribuidas <em>${ocs.filter(o => o.situacao === 'aberta').length} abertas</em></h3><table><tbody>\n  ${ocs.map(o => `<tr class=\"sel\" data-abre-pedido=\"${o.cod_remessa}\" data-key=\"${o._id}\">\n    <td style=\"width:100px\"><span class=\"chip ${o.situacao === 'aberta' ? 'ch-crit' : 'ch-mute'}\">${esc(o.tipo)}</span></td>\n    <td class=\"tiny\">${esc(o.cliente_nome)}<div class=\"tiny\">${esc(o.descricao)}</div></td>\n    <td class=\"num tiny\">${dtLabel(dt(o.aberto_em), agora)}</td></tr>`).join('')}\n  </tbody></table></div>` : '<div class=\"note\" style=\"margin-top:12px\">Nenhuma ocorrencia atribuida a este terceiro.</div>'}\n  <div style=\"display:flex;gap:8px;margin-top:18px\">\n    <button class=\"btn\" data-edita-terceiro=\"${esc(t.usuario)}\">Editar cadastro</button>\n    <button class=\"btn ${t.situacao === 'bloqueado' ? 'btn-ok' : 'btn-crit'}\" data-bloqueia=\"${esc(t.usuario)}\">${t.situacao === 'bloqueado' ? 'Desbloquear' : 'Bloquear'}</button>\n  </div>\n  <div class=\"origem\">A decisao fica registrada aqui com autor e hora &middot; a execucao do bloqueio acontece no TRACKen</div>`;\n}\n\nfunction dTerceiroForm(d2, usuario, funcaoNova) {\n  const t = usuario ? (L(d2, 'terceiro').find(x => x.usuario === usuario) || {}) : {};\n  const func = t.funcao || funcaoNova || 'entregador';\n  const equipes = Array.from(new Set(L(d2, 'terceiro').map(x => x.equipe).filter(Boolean))).sort();\n  const pontos = L(d2, 'pontocoleta');\n  return `<h4>${usuario ? 'Editar' : 'Novo'} terceiro</h4>\n  <p class=\"sub\">${usuario ? esc(t.nome) : 'Prestador de servico: entregador ou coletador.'}</p>\n  <div class=\"fgrid\">\n    <div class=\"fitem\"><label>Funcao *</label><select class=\"inp\" id=\"ft-funcao\">${opt('entregador', func)}${opt('coletador', func)}</select></div>\n    <div class=\"fitem\"><label>Situacao</label><select class=\"inp\" id=\"ft-sit\">${opt('ativo', t.situacao || 'ativo')}${opt('bloqueado', t.situacao)}</select></div>\n    <div class=\"fitem\"><label>Nome *</label><input class=\"inp\" id=\"ft-nome\" value=\"${esc(t.nome || '')}\"></div>\n    <div class=\"fitem\"><label>Usuario *</label><input class=\"inp\" id=\"ft-usuario\" ${usuario ? 'disabled' : ''} placeholder=\"nome.sobrenome\" value=\"${esc(t.usuario || '')}\"></div>\n    <div class=\"fitem\"><label>Telefone</label><input class=\"inp\" id=\"ft-tel\" value=\"${esc(t.telefone || '')}\"></div>\n    <div class=\"fitem\"><label>Veiculo</label><select class=\"inp\" id=\"ft-veiculo\">${['Moto', 'Fiorino', 'Van'].map(v => opt(v, t.veiculo || 'Moto')).join('')}</select></div>\n    <div class=\"fitem\"><label>Equipe</label><input class=\"inp\" id=\"ft-equipe\" list=\"ft-eqs\" value=\"${esc(t.equipe || '')}\"><datalist id=\"ft-eqs\">${equipes.map(q => '<option value=\"' + esc(q) + '\">').join('')}</datalist></div>\n    <div class=\"fitem\"><label>Coordenador</label><input class=\"inp\" id=\"ft-coord\" value=\"${esc(t.coordenador || '')}\"></div>\n    <div class=\"fitem w2\"><label>Base / ponto de coleta</label><select class=\"inp\" id=\"ft-ponto\"><option value=\"\">-</option>${pontos.map(p => opt(p.nome, t.ponto_coleta)).join('')}</select></div>\n  </div>\n  <button class=\"btn btn-ok\" data-salva-terceiro>${usuario ? 'Salvar alteracoes' : 'Criar'}</button>`;\n}\n"}}}}}}}},{"_id":"6ab6cc79ff43b91b61b9b353","component":"data2-core-types@Component","system":"6a8c48a1e9d7f931a6fd649e","params":{"extends":"data2-core-primitives@Block","component":"kTmProposta","package":"tm-logistica-poc","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Deck de proposta preliminar da TM Logística (coletas + clientes).\n// O módulo completo (CSS + slides) vive no drive media e é carregado em runtime,\n// como o kKickoffB2b da Granado. Para editar: gerar de novo o kTmProposta.js\n// (pasta tm-logistica/), subir no mesmo drive e trocar o SRC.\nconst SRC='https://tm-logistica-poc.data2.media/file/wMXFyC48AZYdr0dqNDg7H'\nlet MOD=null, LOADING=null, BOOTED=false\n\nfunction load(){\n  if(!LOADING){\n    LOADING=fetch(SRC,{cache:'no-cache'})\n      .then(r=>r.text())\n      .then(code=>import(URL.createObjectURL(new Blob([code],{type:'text/javascript'}))))\n      .then(m=>{ MOD=m.default; return MOD })\n  }\n  return LOADING\n}\n\nexport default {\n  css:`:host{display:block}\n  .ld{height:100vh;height:100svh;background:#F7F8FA;display:flex;align-items:center;justify-content:center;\n    font-family:-apple-system,BlinkMacSystemFont,sans-serif;font-size:11px;letter-spacing:.24em;text-transform:uppercase;color:#5C6675}`,\n  render(d2){\n    if(!d2.state.ready||!MOD) return '<div class=\"ld\">carregando</div>'\n    return '<style>'+MOD.css+'</style>'+MOD.render(d2)\n  },\n  mounted(d2){\n    load().then(()=>{\n      d2.state.ready=1\n      // preview do builder (data2.qa) já exige login de builder: pula o gate\n      try{ if(/\\.data2\\.qa$/.test(location.hostname)) d2.state.unlocked=true }catch(e){}\n      setTimeout(()=>{ if(!BOOTED){ BOOTED=true; MOD.mounted(d2) } },0)\n    }).catch(()=>{})\n  },\n  updated(d2){\n    if(BOOTED&&MOD&&MOD.updated) MOD.updated(d2)\n  }\n}\n"}}}}}}}},{"_id":"5ed9bed7b9e0891ce913e884","component":"data2-core-types@Component","params":{"package":"data2-core","component":"DataSource","renderable":{"dimensions":{"disabled":false,"component":"data2-core-types@Dimensions","params":{"width":1366,"exactWidth":false,"exactHeight":false,"height":768}}}}},{"_id":"5f472ae463c680de4ff296e9","component":"data2-core-types@Component","params":{"package":"data2-core","component":"Data2TableDataSource","extends":"data2-core@DataSource","renderable":{"dimensions":{"disabled":false,"component":"data2-core-types@Dimensions","params":{"width":1366,"exactWidth":false,"exactHeight":false,"height":768}}}}}]}},{"reference":"ExternalComponentInstancesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"_id":"5f060d9b1ca96def42f3c40a","displayName":"Builder AuthStrategy","component":"data2-core@AuthenticationStrategy","system":"5e3b796d6228227ca637d0f4","params":{"credentials":[{"component":"data2-core-types@DataSetColumnReference","params":{"column":"email"}},{"component":"data2-core-types@DataSetColumnReference","params":{"column":"password"}},{"component":"data2-core-types@DataSetColumnReference","params":{"column":"status"}}],"verifier":{"component":"data2-core-types@DataSetReference","params":{"reference":"UsersDataSet"}},"sessionShared":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"password":{"disabled":false,"component":"data2-core-types@DataSetColumnReference","params":{"column":"password"}},"email":{"disabled":false,"component":"data2-core-types@DataSetColumnReference","params":{"column":"email"}},"resetPassword":{"resetEmail":{"artboard":{"params":{"preventEvaluation":true,"reference":"nR6Q9d7qdaPtZhJ28Q8Dy"},"component":"data2-core-types@ArtboardReference"}},"resetSuccessEmail":{"artboard":{"params":{"preventEvaluation":true,"reference":"yPCJBTKo8q1Mw0B_3Kpwl"},"component":"data2-core-types@ArtboardReference"}}},"session":[{"component":"data2-core-types@DataSetColumnReference","params":{"column":"name"}},{"component":"data2-core-types@DataSetColumnReference","params":{"column":"email"}},{"component":"data2-core-types@DataSetColumnReference","params":{"column":"password"}},{"component":"data2-core-types@DataSetColumnReference","params":{"column":"status"}}],"sessionMetadata":{"params":{"actions":[{"params":{"compare":{"params":{"subject":{"params":{"components":[{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$user._id"}}}},{"params":{"comparisonSubject":{"component":"data2-core-primitives@String","params":{"content":"active"}},"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$user.status"}}}}},"component":"data2-core-comparison-operators@Equal","displayName":"is active user"}]},"component":"data2-core-logical-operators@And","displayName":"is active and has _id"}},"component":"data2-core-logical-operators@Not"},"then":{"params":{"message":{"component":"data2-core-primitives@String","params":{"content":"Invalid Credentials"}},"code":{"component":"data2-core-primitives@String","params":{"content":"401"}}},"component":"data2-core-types@Error"}},"component":"data2-core-flow@If","displayName":"check $user"},{"params":{"action":{"params":{"pattern":{"component":"data2-core-primitives@String","params":{"content":"@data2.app"}},"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$user.email"}}}}},"component":"data2-core-functions@Includes","displayName":"isData2User"},"resultName":{"component":"data2-core-primitives@String","params":{"content":"is_data2_user"}}},"component":"data2-core-flow@Step"},{"params":{"action":{"params":{"pattern":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$metadata.d2_app"}}}},"subject":[{"component":"data2-core-primitives@String","params":{"content":"management"}}]},"component":"data2-core-functions@Includes","displayName":"isData2App Exception"},"resultName":{"component":"data2-core-primitives@String","params":{"content":"is_data2_app_exception"}}},"component":"data2-core-flow@Step"},{"params":{"resultName":{"component":"data2-core-primitives@String","params":{"content":"has_access"}},"action":{"params":{"compare":{"params":{"components":[{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"is_data2_user"}}}},{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"is_data2_app_exception"}}}}]},"component":"data2-core-logical-operators@Or"},"else":{"params":{"actions":[{"params":{"actions":[{"params":{"compare":{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$metadata.system"}}}}},"component":"data2-core-logical-operators@Not"},"then":{"params":{"message":{"component":"data2-core-primitives@String","params":{"content":"Invalid Credentials"}},"code":{"component":"data2-core-primitives@String","params":{"content":"401"}}},"component":"data2-core-types@Error"}},"component":"data2-core-flow@If","displayName":"check $metadata.system"},{"params":{"module":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"WuUa-VKHhW9uYU0E3-mJ8"}},"prop":"filter","args":[{"_id":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$metadata.system"}}}}}]},"component":"data2-core-types@Interaction"},{"params":{"compare":{"params":{"subject":{"component":"data2-core-types@Getter","params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"WuUa-VKHhW9uYU0E3-mJ8"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records.length"}}}}},"component":"data2-core-logical-operators@Not","displayName":"systems not found"},"then":{"params":{"message":{"component":"data2-core-primitives@String","params":{"content":"Invalid Credentials"}},"code":{"component":"data2-core-primitives@String","params":{"content":"401"}}},"component":"data2-core-types@Error"}},"component":"data2-core-flow@If","displayName":"check system found"},{"params":{"actions":[{"params":{"module":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Ok6Tsu5XkS7r8PyW_7TyW"}},"prop":"filter","args":[{"user":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$user._id"}}}},"organization":{"component":"data2-core-types@Getter","params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"WuUa-VKHhW9uYU0E3-mJ8"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"cursor.current.organization._id"}}}}}]},"component":"data2-core-types@Interaction"},{"params":{"module":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"NqKAY34n2ffFL64zamp7t"}},"prop":"filter","args":[{"user":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$user._id"}}}},"system":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$metadata.system"}}}}}]},"component":"data2-core-types@Interaction"}]},"component":"data2-core-flow@Parallel"}]},"component":"data2-core-flow@Series","displayName":"common setup"},{"params":{"then":{"params":{"content":true},"component":"data2-core-primitives@Boolean"},"else":{"params":{"content":false},"component":"data2-core-primitives@Boolean"},"compare":{"params":{"components":{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"WuUa-VKHhW9uYU0E3-mJ8"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"mapper":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"system"}}],"body":{"params":{"expression":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system.visibility"}}}},"defaultCase":{"params":{"content":false},"component":"data2-core-primitives@Boolean"},"cases":[{"component":"data2-core-flow@Case","params":{"expression":{"component":"data2-core-primitives@String","params":{"content":"public"}},"value":{"params":{"components":[{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Ok6Tsu5XkS7r8PyW_7TyW"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"member"}}],"body":{"params":{"components":[{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.organization._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system.organization._id"}}}}},"component":"data2-core-comparison-operators@Equal","displayName":"is org member"},{"params":{"pattern":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.role"}}}},"subject":[{"component":"data2-core-primitives@String","params":{"content":"owner"}},{"component":"data2-core-primitives@String","params":{"content":"billing-owner"}},{"component":"data2-core-primitives@String","params":{"content":"admin"}},{"component":"data2-core-primitives@String","params":{"content":"member"}}]},"component":"data2-core-functions@Includes","displayName":"has role with access"}]},"component":"data2-core-logical-operators@And","displayName":"has org member role with access"}}}},"component":"data2-core-functions@ArrayFind","displayName":"is org member"},{"params":{"components":[{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Ok6Tsu5XkS7r8PyW_7TyW"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"member"}}],"body":{"params":{"components":[{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.organization._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system.organization._id"}}}}},"component":"data2-core-comparison-operators@Equal","displayName":"is org member"},{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.role"}}}},"comparisonSubject":{"component":"data2-core-primitives@String","params":{"content":"collaborator"}}},"component":"data2-core-comparison-operators@Equal","displayName":"is collaborator"}]},"component":"data2-core-logical-operators@And","displayName":"is org member and collaborator"}}}},"component":"data2-core-functions@ArrayFind","displayName":"is collaborator"},{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"NqKAY34n2ffFL64zamp7t"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"access"}}],"body":{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"access.system._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system._id"}}}}},"component":"data2-core-comparison-operators@Equal"}}}},"component":"data2-core-functions@ArrayFind","displayName":"has system access"}]},"component":"data2-core-logical-operators@And","displayName":"is collaborator and has system access"}]},"component":"data2-core-logical-operators@Or"}}},{"component":"data2-core-flow@Case","params":{"expression":{"component":"data2-core-primitives@String","params":{"content":"private"}},"value":{"params":{"components":[{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Ok6Tsu5XkS7r8PyW_7TyW"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"member"}}],"body":{"params":{"components":[{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.organization._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system.organization._id"}}}}},"component":"data2-core-comparison-operators@Equal","displayName":"is org member"},{"params":{"pattern":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.role"}}}},"subject":[{"component":"data2-core-primitives@String","params":{"content":"owner"}},{"component":"data2-core-primitives@String","params":{"content":"admin"}}]},"component":"data2-core-functions@Includes","displayName":"is owner/admin"}]},"component":"data2-core-logical-operators@And","displayName":"has org member role with access"}}}},"component":"data2-core-functions@ArrayFind","displayName":"is owner/admin"},{"params":{"components":[{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Ok6Tsu5XkS7r8PyW_7TyW"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"member"}}],"body":{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.organization._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system.organization._id"}}}}},"component":"data2-core-comparison-operators@Equal"}}}},"component":"data2-core-functions@ArrayFind","displayName":"is org member"},{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"NqKAY34n2ffFL64zamp7t"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"access"}}],"body":{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"access.system._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system._id"}}}}},"component":"data2-core-comparison-operators@Equal"}}}},"component":"data2-core-functions@ArrayFind","displayName":"has system access"}]},"component":"data2-core-logical-operators@And","displayName":"is member and has system access"}]},"component":"data2-core-logical-operators@Or","displayName":"is owner/admin or has system access"}}}]},"component":"data2-core-flow@Switch"}}}},"component":"data2-core-functions@ArrayMap"}},"component":"data2-core-logical-operators@And","displayName":"has org member for all systems in request"}},"component":"data2-core-flow@If"}]},"component":"data2-core-flow@Series"},"then":{"params":{"content":true},"component":"data2-core-primitives@Boolean"}},"component":"data2-core-flow@If"}},"component":"data2-core-flow@Step"},{"params":{"then":{"system":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$metadata.system"}}}}},"else":{"params":{"message":{"component":"data2-core-primitives@String","params":{"content":"Invalid Credentials"}},"code":{"component":"data2-core-primitives@String","params":{"content":"401"}}},"component":"data2-core-types@Error"},"compare":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"has_access"}}}}},"component":"data2-core-flow@If"}]},"component":"data2-core-flow@Series"},"sessionExpiresIn":{"component":"data2-core-primitives@Number","params":{"content":604800}},"sessionRenewal":{"component":"data2-core-primitives@Boolean","params":{"content":true}},"identityProviders":[{"provider":{"component":"data2-core-primitives@String","params":{"content":"GOOGLE"}},"clientId":{"component":"data2-core-primitives@String","params":{"content":"55470861603-22pvfc1t49lp8cjnbfk71s5ct9hp1q1v.apps.googleusercontent.com"}}}]},"reference":"Data2BuilderAuthentication","updatedAt":"2026-08-06T19:31:23.557Z"},{"_id":"5f060ee51ca96def42f3fbd1","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"UsersTableDataSource"}},"pagination":{"size":{"component":"data2-core-primitives@Number","params":{"content":1}}}},"reference":"UsersDataSet","updatedAt":"2026-03-04T21:16:40.291Z"},{"_id":"68f938cf5fb002e33752a43d","displayName":"InternalApplicationsAuthenticationStrategy","component":"data2-core@AuthenticationStrategy","system":"5e3b796d6228227ca637d0f4","params":{"resetPassword":{"resetEmail":{"artboard":{"params":{"preventEvaluation":true},"component":"data2-core-types@ArtboardReference"}},"resetSuccessEmail":{"artboard":{"params":{"preventEvaluation":true},"component":"data2-core-types@ArtboardReference"}}},"verifier":{"disabled":false,"component":"data2-core-types@DataSetReference","params":{"reference":"InternalApplicationsVerifierDataSet"}},"password":{"disabled":false,"component":"data2-core-types@DataSetColumnReference","params":{"column":"secret"}},"credentials":[{"component":"data2-core-types@FieldReference","params":{"key":"application"}},{"component":"data2-core-types@FieldReference","params":{"key":"secret"}},{"component":"data2-core-types@FieldReference","params":{"key":"status"}}],"session":[{"component":"data2-core-types@FieldReference","params":{"key":"application"}},{"component":"data2-core-types@FieldReference","params":{"key":"secret"}},{"component":"data2-core-types@FieldReference","params":{"key":"status"}}]},"reference":"InternalApplicationsAuthenticationStrategy","updatedAt":"2025-10-22T20:08:54.442Z","createdAt":"2025-10-22T20:04:31.198Z"},{"component":"data2-core@DataSet","reference":"SessionsDataSet","params":{"requiresConfirmation":false,"pk":"key","datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"data2sessionsdatasource"}}}},{"reference":"UsersTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"component":"data2-core@ServerSessionsDataSource","reference":"data2sessionsdatasource","params":{}},{"_id":"5f1600b70528b92601890f75","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"ServiceComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"policies":{"params":{"allowGet":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2@hkXy-UhMjhyfptdE6_fpW"}},"reference":"ServiceComponentInstancesDataSet","updatedAt":"2025-11-06T21:07:20.208Z","createdAt":"2020-07-20T20:38:15.436Z"},{"_id":"5f1602190528b92601890f7d","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"pagination":{"size":40000},"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"ComponentInstancesTableDataSource"}},"sort":{"_id":1},"pk":"_id","autoEdit":true,"master":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"policies":{"params":{"allowGet":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2@hkXy-UhMjhyfptdE6_fpW"}},"reference":"ComponentInstancesDataSet","updatedAt":"2025-11-06T21:07:07.089Z","createdAt":"2020-07-20T20:44:09.350Z"},{"_id":"5f16017f0528b92601890f7a","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"FileComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"filter":{"domain":{"component":"data2-core-types@Reference","params":{"reference":"clientApplicationDomain"}}},"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}}},"reference":"FileComponentInstancesDataSet","updatedAt":"2023-08-03T16:08:18.193Z","createdAt":"2020-07-20T20:41:35.797Z"},{"_id":"5f1601990528b92601890f7b","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"ApplicationsTableDataSource"}},"pk":"_id","autoEdit":{"component":"data2-core-primitives@Boolean","params":{"content":true}},"master":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"params":{"column":"_id"},"component":"data2-core-types@DataSetColumnReference"}},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}}},"reference":"ApplicationsDataSet","updatedAt":"2022-12-13T21:51:13.995Z","createdAt":"2020-07-20T20:42:01.657Z"},{"_id":"5f16172a0528b92601890f85","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"pagination":{"size":{"component":"data2-core-primitives@Number","params":{"content":10000}}},"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"DataComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"policies":{"params":{"allowGet":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2@hkXy-UhMjhyfptdE6_fpW"}},"reference":"DataComponentInstancesDataSet","updatedAt":"2025-11-06T21:07:12.831Z","createdAt":"2020-07-20T22:14:02.097Z"},{"_id":"60ddc1bbda3861ca65407c5a","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"FileComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"filter":{"domain":{"component":"data2-core-types@Reference","params":{"reference":"clientApplicationDomain"}}},"pagination":{"size":1},"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"}},"reference":"OneFileComponentInstancesDataSet","updatedAt":"2022-02-09T19:44:38.036Z","createdAt":"2020-07-20T20:41:35.797Z"},{"_id":"63ee3d38b8c9838c62fb05fb","displayName":"DriveFileComponentInstancesDataSet","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"FileComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"filter":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core@Drive"}}},"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}}},"reference":"DriveFileComponentInstancesDataSet","updatedAt":"2025-12-04T21:58:32.367Z","createdAt":"2023-02-16T14:27:07.797Z"},{"reference":"ServiceComponentInstancesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"6a8f50b53fe0271acb12be00","component":"data2-rush@HTTPListener","reference":"api-dados","system":"6a8c48a1e9d7f931a6fd649e","params":{},"deleteMetadata":{}},{"_id":"6a972c550f64e6daf3d6a7cb","component":"data2-rush@HTTPListener","reference":"act-comissao","system":"6a8c48a1e9d7f931a6fd649e","params":{},"deleteMetadata":{}},{"_id":"6a922bc1eed7600008c5b24c","component":"data2-rush@HTTPListener","reference":"act-remessa","system":"6a8c48a1e9d7f931a6fd649e","params":{},"deleteMetadata":{}},{"_id":"6a921e92ce14b82021438512","component":"data2-rush@HTTPListener","reference":"act-fatura","system":"6a8c48a1e9d7f931a6fd649e","params":{},"deleteMetadata":{}},{"_id":"6a921e8f08e43b08a99f5be9","component":"data2-rush@HTTPListener","reference":"act-terceiro","system":"6a8c48a1e9d7f931a6fd649e","params":{},"deleteMetadata":{}},{"_id":"6a921e9442a2cc71dcc099bb","component":"data2-rush@HTTPListener","reference":"act-ocorrencia","system":"6a8c48a1e9d7f931a6fd649e","params":{},"deleteMetadata":{}}]}},{"reference":"ComponentInstancesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"6a8f510e2e83a7b3d435fbc3","component":"data2-core-primitives@Artboard","system":"6a8c48a1e9d7f931a6fd649e","displayName":"App","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"App"}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":900}},"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0}}},"reference":"sXo6rMiqdL0iRToD8BjKj","deleteMetadata":{}},{"_id":"87e496620208834fdfe2dd19","parent":"6a8f510e2e83a7b3d435fbc3","component":"tm-logistica-poc@prazoeprova","system":"6a8c48a1e9d7f931a6fd649e","displayName":"Prazo e Prova (app)","params":{"super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0,"freeTransform":true,"left":true,"top":true}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":900}}}},"reference":"M8WjbUGVCmEAePdUReTM-","deleteMetadata":{}}]}},{"_id":"5fc4faeec8da12be8bf3d08a","component":"data2-core@Data2TableDataSource","system":"5e3b796d6228227ca637d0f4","params":{"paginate":{"default":1000},"super":{},"table":"fileComponentInstances","schema":[{"component":"data2-core-types@Field","params":{"key":"component","title":"Component","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"system","title":"System","component":"data2-core-primitives@ObjectId"}},{"component":"data2-core-types@Field","params":{"key":"displayName","title":"Display Name","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"params","title":"Params","component":"data2-core-primitives@Object"}},{"component":"data2-core-types@Field","params":{"key":"reference","title":"Reference","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":{"component":"data2-core-primitives@String","params":{"content":"fileId"}},"title":"File ID","component":"data2-core-primitives@ObjectId"},"break":true}],"hooks":{"before":{"all":[{"hook":"softDelete"}],"find":[{"hook":"useCache","options":{"additionalGroupKeys":["$and.0.system","$and.1.system"],"skipCache":true}}],"create":[{"hook":"timestamp","options":{"fields":["createdAt","updatedAt"]}}],"update":[{"hook":"timestamp","options":{"fields":["updatedAt"]}}],"patch":[{"hook":"timestamp","options":{"fields":["updatedAt"]}}]},"after":{"all":[{"hook":"fileUrl","options":{"downloadField":"params.fileUrl","uploadField":"params.uploadFileUrl","enhanceSchema":false}}],"find":[{"hook":"useCache","options":{"additionalGroupKeys":["$and.0.system","$and.1.system"],"skipCache":true}}],"create":[{"hook":"invalidateCache","options":{"additionalGroupKeys":["system"],"secondaryUniqueKeys":["reference"]}},{"hook":"invalidateEnvCache"}],"update":[{"hook":"invalidateCache","options":{"additionalGroupKeys":["system"],"secondaryUniqueKeys":["reference"]}},{"hook":"invalidateEnvCache"}],"patch":[{"hook":"invalidateCache","options":{"additionalGroupKeys":["system"],"secondaryUniqueKeys":["reference"]}},{"hook":"invalidateEnvCache"}],"remove":[{"hook":"invalidateCache","options":{"additionalGroupKeys":["system"],"secondaryUniqueKeys":["reference"]}},{"hook":"invalidateEnvCache"}]}},"multi":["create"],"useEstimatedDocumentCount":true},"reference":"FileComponentInstancesTableDataSource","updatedAt":"2022-12-19T20:42:51.837Z","createdAt":"2020-11-30T13:59:52.294Z"},{"reference":"ApplicationsTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"6a8f52668c33b1efb42c0d7c","displayName":"Prazo e Prova","reference":"AjDh__IDU3QDbnmv7E21X","params":{"domain":{"component":"data2-core-primitives@String","params":{"content":"app"}},"entryPoint":{"component":"data2-core-types@ComponentInstanceReference","params":{"component":"data2-core-primitives@Artboard","reference":"sXo6rMiqdL0iRToD8BjKj"}}},"system":"6a8c48a1e9d7f931a6fd649e","component":"data2-core-primitives@Application"}]}},{"reference":"DataComponentInstancesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"6a921e6cceaa5f4634dd3bed","component":"data2-core@Data2TableDataSource","system":"6a8c48a1e9d7f931a6fd649e","params":{"table":"remessa","schema":[{"component":"data2-core-types@Field","params":{"key":"cod_remessa","title":"Remessa","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"num_pedido","title":"N Pedido","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"nota_fiscal","title":"Nota Fiscal","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cliente_cnpj","title":"CNPJ Cliente","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cliente_nome","title":"Cliente","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"loja_nome","title":"Loja","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"canal","title":"Canal","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"destinatario","title":"Destinatario","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"bairro","title":"Bairro","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cidade","title":"Cidade","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"regiao","title":"Regiao","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cep","title":"CEP","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"valor_nf","title":"Valor NF","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"peso_faixa","title":"Faixa de peso","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"valor_frete","title":"Valor frete","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"etiquetas","title":"Etiquetas","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"origem","title":"Origem","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"ponto_coleta","title":"Ponto de coleta","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"coletador_usuario","title":"Coletador usuario","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"coletador_nome","title":"Coletador","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"entregador_usuario","title":"Entregador usuario","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"entregador_nome","title":"Entregador","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"criado_em","title":"Criado em","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"coleta_prevista_em","title":"Coleta prevista","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"coletado_em","title":"Coletado em","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"galpao_em","title":"No galpao em","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"rota_em","title":"Em rota em","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"prazo_em","title":"Prazo de entrega","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"entrega_em","title":"Entrega roteirizada","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"recebedor","title":"Recebedor","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"documento","title":"Documento recebedor","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"tem_ocorrencia","title":"Tem ocorrencia","component":"data2-core-primitives@Boolean"}}]},"reference":"remessa","deleteMetadata":{}},{"_id":"6a921e7d73446ad7d92502c1","component":"data2-core@Data2TableDataSource","system":"6a8c48a1e9d7f931a6fd649e","params":{"table":"clientemes","schema":[{"component":"data2-core-types@Field","params":{"key":"cliente_cnpj","title":"CNPJ","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cliente_nome","title":"Cliente","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"loja_nome","title":"Loja","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"canal","title":"Canal","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"mes","title":"Mes","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"pedidos","title":"Pedidos","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"faturamento","title":"Faturamento","component":"data2-core-primitives@Number"}}]},"reference":"clientemes","deleteMetadata":{}},{"_id":"6a921e762c78bf972cef4648","component":"data2-core@Data2TableDataSource","system":"6a8c48a1e9d7f931a6fd649e","params":{"table":"ocorrencia","schema":[{"component":"data2-core-types@Field","params":{"key":"cod_remessa","title":"Remessa","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"tipo","title":"Tipo","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"descricao","title":"Descricao","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"aberto_em","title":"Aberta em","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"situacao","title":"Situacao","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"resolvido_em","title":"Resolvida em","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"resolvido_por","title":"Resolvida por","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"terceiro_usuario","title":"Terceiro usuario","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"terceiro_nome","title":"Terceiro","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"terceiro_funcao","title":"Funcao","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cliente_nome","title":"Cliente","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"loja_nome","title":"Loja","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"canal","title":"Canal","component":"data2-core-primitives@String"}}]},"reference":"ocorrencia","deleteMetadata":{}},{"_id":"6a91d45eeed7600008c4f863","component":"data2-core@Data2TableDataSource","system":"6a8c48a1e9d7f931a6fd649e","params":{"table":"cliente","schema":[{"component":"data2-core-types@Field","params":{"key":"nome_fantasia","title":"Nome Fantasia","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"razao_social","title":"Razao Social","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cnpj_cpf","title":"CNPJ / CPF","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"telefone","title":"Telefone","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"email","title":"Email","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"responsavel","title":"Responsavel","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"usuario_comercial","title":"Usuario Comercial","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"sdr","title":"SDR","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"data_inicio","title":"Data de Inicio","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"situacao","title":"Situacao","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"observacao","title":"Observacao","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"endereco_coleta","title":"Endereco de coleta","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"bairro_coleta","title":"Bairro de coleta","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cidade_coleta","title":"Cidade de coleta","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"regiao_coleta","title":"Regiao de coleta","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"ponto_coleta_padrao","title":"Ponto de coleta padrao","component":"data2-core-primitives@String"}}]},"reference":"cliente","deleteMetadata":{}},{"_id":"6a921e70e388bf7aa9a3d387","component":"data2-core@Data2TableDataSource","system":"6a8c48a1e9d7f931a6fd649e","params":{"table":"terceiro","schema":[{"component":"data2-core-types@Field","params":{"key":"funcao","title":"Funcao","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"usuario","title":"Usuario","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"nome","title":"Nome","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"telefone","title":"Telefone","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"equipe","title":"Equipe","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"coordenador","title":"Coordenador","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"veiculo","title":"Veiculo","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"ponto_coleta","title":"Ponto de coleta base","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"situacao","title":"Situacao","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"motivo_bloqueio","title":"Motivo bloqueio","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"bloqueado_em","title":"Bloqueado em","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"bloqueado_por","title":"Bloqueado por","component":"data2-core-primitives@String"}}]},"reference":"terceiro","deleteMetadata":{}},{"_id":"6a921e79ce14b820214384e7","component":"data2-core@Data2TableDataSource","system":"6a8c48a1e9d7f931a6fd649e","params":{"table":"fatura","schema":[{"component":"data2-core-types@Field","params":{"key":"cliente_cnpj","title":"CNPJ","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cliente_nome","title":"Cliente","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"quinzena","title":"Quinzena","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"vencimento","title":"Vencimento","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"pedidos_qtd","title":"Pedidos","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"valor","title":"Valor","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"status","title":"Status","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"pago_em","title":"Pago em","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"baixa_por","title":"Baixa por","component":"data2-core-primitives@String"}}]},"reference":"fatura","deleteMetadata":{}},{"_id":"6a921e8053f4640402764ade","component":"data2-core@Data2TableDataSource","system":"6a8c48a1e9d7f931a6fd649e","params":{"table":"kpidiario","schema":[{"component":"data2-core-types@Field","params":{"key":"dia","title":"Dia","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"pedidos","title":"Pedidos","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"entregues","title":"Entregues","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"no_prazo","title":"No prazo","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"fora_prazo","title":"Fora do prazo","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"ocorrencias","title":"Ocorrencias","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"clientes_faturados","title":"Clientes faturados","component":"data2-core-primitives@Number"}}]},"reference":"kpidiario","deleteMetadata":{}},{"_id":"6a91d460eed7600008c4f86e","component":"data2-core@Data2TableDataSource","system":"6a8c48a1e9d7f931a6fd649e","params":{"table":"loja","schema":[{"component":"data2-core-types@Field","params":{"key":"cliente_cnpj","title":"CNPJ do Cliente","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cliente_nome","title":"Cliente","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"canal","title":"Canal","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"nome_loja","title":"Nome no canal / TRACKen","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cod_tracken","title":"Cod parceiro TRACKen","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cod_servico","title":"Cod Servico","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"situacao","title":"Situacao","component":"data2-core-primitives@String"}}]},"reference":"loja","deleteMetadata":{}},{"_id":"6a921e73ceaa5f4634dd3bf7","component":"data2-core@Data2TableDataSource","system":"6a8c48a1e9d7f931a6fd649e","params":{"table":"pontocoleta","schema":[{"component":"data2-core-types@Field","params":{"key":"nome","title":"Nome","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"endereco","title":"Endereco","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"bairro","title":"Bairro","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cidade","title":"Cidade","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"responsavel","title":"Responsavel","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"tipo","title":"Tipo","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"ativo","title":"Ativo","component":"data2-core-primitives@Boolean"}}]},"reference":"pontocoleta","deleteMetadata":{}}]}},{"reference":"BundlesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}}],"processesParams":{}}}}